diff --git a/cockatrice/cockatrice.pro b/cockatrice/cockatrice.pro index 4a0203f26..5902e4184 100644 --- a/cockatrice/cockatrice.pro +++ b/cockatrice/cockatrice.pro @@ -5,7 +5,7 @@ INCLUDEPATH += . src ../common MOC_DIR = build OBJECTS_DIR = build RESOURCES = cockatrice.qrc -QT += network svg +QT += network script svg multimedia HEADERS += src/abstractcounter.h \ src/counter_general.h \ @@ -28,6 +28,8 @@ HEADERS += src/abstractcounter.h \ src/handcounter.h \ src/carddatabase.h \ src/gameview.h \ + src/gameselector.h \ + src/gametypemap.h \ src/decklistmodel.h \ src/dlg_load_deck_from_clipboard.h \ src/dlg_load_remote_deck.h \ @@ -71,6 +73,8 @@ HEADERS += src/abstractcounter.h \ src/localserverinterface.h \ src/localclient.h \ src/translation.h \ + src/priceupdater.h \ + src/soundengine.h \ ../common/color.h \ ../common/serializable_item.h \ ../common/decklist.h \ @@ -112,6 +116,7 @@ SOURCES += src/abstractcounter.cpp \ src/handcounter.cpp \ src/carddatabase.cpp \ src/gameview.cpp \ + src/gameselector.cpp \ src/decklistmodel.cpp \ src/dlg_load_deck_from_clipboard.cpp \ src/dlg_load_remote_deck.cpp \ @@ -134,6 +139,7 @@ SOURCES += src/abstractcounter.cpp \ src/gamescene.cpp \ src/arrowitem.cpp \ src/arrowtarget.cpp \ + src/tab.cpp \ src/tab_server.cpp \ src/tab_room.cpp \ src/tab_message.cpp \ @@ -153,6 +159,8 @@ SOURCES += src/abstractcounter.cpp \ src/localserver.cpp \ src/localserverinterface.cpp \ src/localclient.cpp \ + src/priceupdater.cpp \ + src/soundengine.cpp \ ../common/serializable_item.cpp \ ../common/decklist.cpp \ ../common/protocol.cpp \ @@ -177,7 +185,11 @@ TRANSLATIONS += \ translations/cockatrice_pt-br.ts \ translations/cockatrice_fr.ts \ translations/cockatrice_ja.ts \ - translations/cockatrice_ru.ts + translations/cockatrice_ru.ts \ + translations/cockatrice_cs.ts \ + translations/cockatrice_pl.ts \ + translations/cockatrice_sk.ts + win32 { RC_FILE = cockatrice.rc } diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc index a71ed41e6..3a75a53d8 100644 --- a/cockatrice/cockatrice.qrc +++ b/cockatrice/cockatrice.qrc @@ -7,6 +7,7 @@ resources/icon_config_appearance.svg resources/icon_config_interface.svg resources/icon_config_messages.svg + resources/icon_config_deckeditor.svg resources/phases/icon_phase_untap.svg resources/phases/icon_phase_upkeep.svg resources/phases/icon_phase_draw.svg @@ -23,6 +24,7 @@ resources/pencil.svg resources/icon_search.svg resources/icon_clearsearch.svg + resources/icon_update.png resources/hr.jpg resources/appicon.svg resources/add_to_sideboard.svg @@ -37,6 +39,10 @@ resources/icon_player.svg resources/icon_spectator.svg + resources/genders/male.svg + resources/genders/female.svg + resources/genders/unknown.svg + translations/cockatrice_de.qm translations/cockatrice_en.qm translations/cockatrice_es.qm @@ -45,12 +51,18 @@ translations/cockatrice_fr.qm translations/cockatrice_ja.qm translations/cockatrice_ru.qm + translations/cockatrice_cs.qm + translations/cockatrice_pl.qm + translations/cockatrice_sk.qm + resources/countries/ar.svg resources/countries/at.svg resources/countries/au.svg resources/countries/be.svg resources/countries/br.svg + resources/countries/by.svg resources/countries/ca.svg + resources/countries/cz.svg resources/countries/ch.svg resources/countries/cn.svg resources/countries/de.svg @@ -65,16 +77,22 @@ resources/countries/it.svg resources/countries/jp.svg resources/countries/mx.svg + resources/countries/my.svg resources/countries/nl.svg resources/countries/no.svg resources/countries/ph.svg resources/countries/pl.svg resources/countries/pt.svg + resources/countries/ro.svg resources/countries/ru.svg resources/countries/se.svg + resources/countries/sg.svg + resources/countries/sk.svg resources/countries/tr.svg + resources/countries/ua.svg resources/countries/uk.svg resources/countries/us.svg + resources/countries/za.svg resources/counters/w.svg resources/counters/w_highlight.svg @@ -91,7 +109,7 @@ resources/userlevels/normal.svg resources/userlevels/registered.svg - resources/userlevels/judge.svg + resources/userlevels/moderator.svg resources/userlevels/admin.svg resources/news/exclamation_mark.svg diff --git a/cockatrice/resources/countries/ar.svg b/cockatrice/resources/countries/ar.svg new file mode 100644 index 000000000..543196fc3 --- /dev/null +++ b/cockatrice/resources/countries/ar.svg @@ -0,0 +1,109 @@ + + + + + \ No newline at end of file diff --git a/cockatrice/resources/countries/by.svg b/cockatrice/resources/countries/by.svg new file mode 100644 index 000000000..bb1dfa789 --- /dev/null +++ b/cockatrice/resources/countries/by.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/cockatrice/resources/countries/cz.svg b/cockatrice/resources/countries/cz.svg new file mode 100644 index 000000000..51bf4fb7e --- /dev/null +++ b/cockatrice/resources/countries/cz.svg @@ -0,0 +1,11 @@ + + + + +Flag of the Czech Republic + + + + diff --git a/cockatrice/resources/countries/my.svg b/cockatrice/resources/countries/my.svg new file mode 100644 index 000000000..988b507b7 --- /dev/null +++ b/cockatrice/resources/countries/my.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/countries/ro.svg b/cockatrice/resources/countries/ro.svg new file mode 100644 index 000000000..c9b6da860 --- /dev/null +++ b/cockatrice/resources/countries/ro.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/cockatrice/resources/countries/sg.svg b/cockatrice/resources/countries/sg.svg new file mode 100644 index 000000000..572cb3b1b --- /dev/null +++ b/cockatrice/resources/countries/sg.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/cockatrice/resources/countries/sk.svg b/cockatrice/resources/countries/sk.svg new file mode 100644 index 000000000..3b4e666a3 --- /dev/null +++ b/cockatrice/resources/countries/sk.svg @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/cockatrice/resources/countries/ua.svg b/cockatrice/resources/countries/ua.svg new file mode 100644 index 000000000..8f4b0a436 --- /dev/null +++ b/cockatrice/resources/countries/ua.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/cockatrice/resources/countries/za.svg b/cockatrice/resources/countries/za.svg new file mode 100644 index 000000000..ccfe132f5 --- /dev/null +++ b/cockatrice/resources/countries/za.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/cockatrice/resources/genders/female.svg b/cockatrice/resources/genders/female.svg new file mode 100644 index 000000000..b0fbb1306 --- /dev/null +++ b/cockatrice/resources/genders/female.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/cockatrice/resources/genders/male.svg b/cockatrice/resources/genders/male.svg new file mode 100644 index 000000000..8c58a40fc --- /dev/null +++ b/cockatrice/resources/genders/male.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/cockatrice/resources/genders/unknown.svg b/cockatrice/resources/genders/unknown.svg new file mode 100644 index 000000000..99f681f9c --- /dev/null +++ b/cockatrice/resources/genders/unknown.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/cockatrice/resources/icon_config_deckeditor.svg b/cockatrice/resources/icon_config_deckeditor.svg new file mode 100644 index 000000000..9e167516c --- /dev/null +++ b/cockatrice/resources/icon_config_deckeditor.svg @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cockatrice/resources/icon_update.png b/cockatrice/resources/icon_update.png new file mode 100644 index 000000000..825c0aee7 Binary files /dev/null and b/cockatrice/resources/icon_update.png differ diff --git a/cockatrice/resources/phases/icon_phase_cleanup.svg b/cockatrice/resources/phases/icon_phase_cleanup.svg index a675d66f5..9786daca9 100644 --- a/cockatrice/resources/phases/icon_phase_cleanup.svg +++ b/cockatrice/resources/phases/icon_phase_cleanup.svg @@ -1,749 +1,186 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_combat_attackers.svg b/cockatrice/resources/phases/icon_phase_combat_attackers.svg index 540107ac2..d74832536 100644 --- a/cockatrice/resources/phases/icon_phase_combat_attackers.svg +++ b/cockatrice/resources/phases/icon_phase_combat_attackers.svg @@ -1,162 +1,103 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_combat_blockers.svg b/cockatrice/resources/phases/icon_phase_combat_blockers.svg index 6344ef6b3..6602eaef0 100644 --- a/cockatrice/resources/phases/icon_phase_combat_blockers.svg +++ b/cockatrice/resources/phases/icon_phase_combat_blockers.svg @@ -1,181 +1,1930 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_combat_damage.svg b/cockatrice/resources/phases/icon_phase_combat_damage.svg index 8536764e8..aa356e2a9 100644 --- a/cockatrice/resources/phases/icon_phase_combat_damage.svg +++ b/cockatrice/resources/phases/icon_phase_combat_damage.svg @@ -1,169 +1,108 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_combat_end.svg b/cockatrice/resources/phases/icon_phase_combat_end.svg index 9e7b8950b..bbbbf9bff 100644 --- a/cockatrice/resources/phases/icon_phase_combat_end.svg +++ b/cockatrice/resources/phases/icon_phase_combat_end.svg @@ -1,253 +1,319 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_combat_start.svg b/cockatrice/resources/phases/icon_phase_combat_start.svg index 996571d71..b80b571dc 100644 --- a/cockatrice/resources/phases/icon_phase_combat_start.svg +++ b/cockatrice/resources/phases/icon_phase_combat_start.svg @@ -1,253 +1,348 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_draw.svg b/cockatrice/resources/phases/icon_phase_draw.svg index 51918274c..4d1062199 100644 --- a/cockatrice/resources/phases/icon_phase_draw.svg +++ b/cockatrice/resources/phases/icon_phase_draw.svg @@ -1,192 +1,190 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_main1.svg b/cockatrice/resources/phases/icon_phase_main1.svg index 264cef395..48fce651b 100644 --- a/cockatrice/resources/phases/icon_phase_main1.svg +++ b/cockatrice/resources/phases/icon_phase_main1.svg @@ -1,135 +1,79 @@ - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_main2.svg b/cockatrice/resources/phases/icon_phase_main2.svg index 50f77fa70..61be736ef 100644 --- a/cockatrice/resources/phases/icon_phase_main2.svg +++ b/cockatrice/resources/phases/icon_phase_main2.svg @@ -1,135 +1,235 @@ - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_nextturn.svg b/cockatrice/resources/phases/icon_phase_nextturn.svg index 3cfd19ab0..302a57d67 100644 --- a/cockatrice/resources/phases/icon_phase_nextturn.svg +++ b/cockatrice/resources/phases/icon_phase_nextturn.svg @@ -1,89 +1,102 @@ - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_untap.svg b/cockatrice/resources/phases/icon_phase_untap.svg index 2f4d81732..3d316ab04 100644 --- a/cockatrice/resources/phases/icon_phase_untap.svg +++ b/cockatrice/resources/phases/icon_phase_untap.svg @@ -1,198 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases/icon_phase_upkeep.svg b/cockatrice/resources/phases/icon_phase_upkeep.svg index 5a06aae9c..2317a9379 100644 --- a/cockatrice/resources/phases/icon_phase_upkeep.svg +++ b/cockatrice/resources/phases/icon_phase_upkeep.svg @@ -1,159 +1,162 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_cleanup.svg b/cockatrice/resources/phases_old/icon_phase_cleanup.svg new file mode 100644 index 000000000..a675d66f5 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_cleanup.svg @@ -0,0 +1,749 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_combat_attackers.svg b/cockatrice/resources/phases_old/icon_phase_combat_attackers.svg new file mode 100644 index 000000000..540107ac2 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_combat_attackers.svg @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_combat_blockers.svg b/cockatrice/resources/phases_old/icon_phase_combat_blockers.svg new file mode 100644 index 000000000..6344ef6b3 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_combat_blockers.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_combat_damage.svg b/cockatrice/resources/phases_old/icon_phase_combat_damage.svg new file mode 100644 index 000000000..8536764e8 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_combat_damage.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_combat_end.svg b/cockatrice/resources/phases_old/icon_phase_combat_end.svg new file mode 100644 index 000000000..9e7b8950b --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_combat_end.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_combat_start.svg b/cockatrice/resources/phases_old/icon_phase_combat_start.svg new file mode 100644 index 000000000..996571d71 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_combat_start.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_draw.svg b/cockatrice/resources/phases_old/icon_phase_draw.svg new file mode 100644 index 000000000..51918274c --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_draw.svg @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_main1.svg b/cockatrice/resources/phases_old/icon_phase_main1.svg new file mode 100644 index 000000000..264cef395 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_main1.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_main2.svg b/cockatrice/resources/phases_old/icon_phase_main2.svg new file mode 100644 index 000000000..50f77fa70 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_main2.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_nextturn.svg b/cockatrice/resources/phases_old/icon_phase_nextturn.svg new file mode 100644 index 000000000..3cfd19ab0 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_nextturn.svg @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_untap.svg b/cockatrice/resources/phases_old/icon_phase_untap.svg new file mode 100644 index 000000000..2f4d81732 --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_untap.svg @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/phases_old/icon_phase_upkeep.svg b/cockatrice/resources/phases_old/icon_phase_upkeep.svg new file mode 100644 index 000000000..5a06aae9c --- /dev/null +++ b/cockatrice/resources/phases_old/icon_phase_upkeep.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/cockatrice/resources/userlevels/judge.svg b/cockatrice/resources/userlevels/moderator.svg similarity index 100% rename from cockatrice/resources/userlevels/judge.svg rename to cockatrice/resources/userlevels/moderator.svg diff --git a/cockatrice/src/abstractcarditem.cpp b/cockatrice/src/abstractcarditem.cpp index 0deed4ea3..20e7c8e9e 100644 --- a/cockatrice/src/abstractcarditem.cpp +++ b/cockatrice/src/abstractcarditem.cpp @@ -26,6 +26,7 @@ AbstractCardItem::AbstractCardItem(const QString &_name, Player *_owner, QGraphi AbstractCardItem::~AbstractCardItem() { qDebug() << "AbstractCardItem destructor:" << name; + emit deleteCardInfoPopup(name); } QRectF AbstractCardItem::boundingRect() const @@ -157,6 +158,10 @@ void AbstractCardItem::paint(QPainter *painter, const QStyleOptionGraphicsItem * void AbstractCardItem::setName(const QString &_name) { + if (name == _name) + return; + + emit deleteCardInfoPopup(name); disconnect(info, 0, this, 0); name = _name; info = db->getCard(name); @@ -212,6 +217,9 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event) void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + if (event->button() == Qt::MidButton) + emit deleteCardInfoPopup(name); + // This function ensures the parent function doesn't mess around with our selection. event->accept(); } diff --git a/cockatrice/src/abstractcarditem.h b/cockatrice/src/abstractcarditem.h index c1345564f..e11bdf852 100644 --- a/cockatrice/src/abstractcarditem.h +++ b/cockatrice/src/abstractcarditem.h @@ -30,7 +30,7 @@ private slots: signals: void hovered(AbstractCardItem *card); void showCardInfoPopup(QPoint pos, QString cardName); - void deleteCardInfoPopup(); + void deleteCardInfoPopup(QString cardName); public: enum { Type = typeCard }; int type() const { return Type; } @@ -50,6 +50,7 @@ public: bool getTapped() const { return tapped; } void setTapped(bool _tapped, bool canAnimate = false); void processHoverEvent(); + void deleteCardInfoPopup() { emit deleteCardInfoPopup(name); } protected: QSizeF getTranslatedSize(QPainter *painter) const; void transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle); diff --git a/cockatrice/src/abstractclient.cpp b/cockatrice/src/abstractclient.cpp index 5fb9b433a..7edb7a2ea 100644 --- a/cockatrice/src/abstractclient.cpp +++ b/cockatrice/src/abstractclient.cpp @@ -32,15 +32,16 @@ void AbstractClient::processProtocolItem(ProtocolItem *item) GenericEvent *genericEvent = qobject_cast(item); if (genericEvent) { switch (genericEvent->getItemId()) { - case ItemId_Event_ConnectionClosed: emit connectionClosedEventReceived(qobject_cast(item)); break; - case ItemId_Event_AddToList: emit addToListEventReceived(qobject_cast(item)); break; - case ItemId_Event_RemoveFromList: emit removeFromListEventReceived(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_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; + case ItemId_Event_ConnectionClosed: emit connectionClosedEventReceived(static_cast(item)); break; + case ItemId_Event_ServerShutdown: emit serverShutdownEventReceived(static_cast(item)); break; + case ItemId_Event_AddToList: emit addToListEventReceived(static_cast(item)); break; + case ItemId_Event_RemoveFromList: emit removeFromListEventReceived(static_cast(item)); break; + case ItemId_Event_UserJoined: emit userJoinedEventReceived(static_cast(item)); break; + case ItemId_Event_UserLeft: emit userLeftEventReceived(static_cast(item)); break; + case ItemId_Event_ServerMessage: emit serverMessageEventReceived(static_cast(item)); break; + case ItemId_Event_ListRooms: emit listRoomsEventReceived(static_cast(item)); break; + case ItemId_Event_GameJoined: emit gameJoinedEventReceived(static_cast(item)); break; + case ItemId_Event_Message: emit messageEventReceived(static_cast(item)); break; } if (genericEvent->getReceiverMayDelete()) delete genericEvent; diff --git a/cockatrice/src/abstractclient.h b/cockatrice/src/abstractclient.h index f43131b56..d896a89dc 100644 --- a/cockatrice/src/abstractclient.h +++ b/cockatrice/src/abstractclient.h @@ -21,6 +21,7 @@ class Event_ListRooms; class Event_GameJoined; class Event_Message; class Event_ConnectionClosed; +class Event_ServerShutdown; enum ClientStatus { StatusDisconnected, @@ -43,6 +44,7 @@ signals: void gameEventContainerReceived(GameEventContainer *event); // Generic events void connectionClosedEventReceived(Event_ConnectionClosed *event); + void serverShutdownEventReceived(Event_ServerShutdown *event); void addToListEventReceived(Event_AddToList *event); void removeFromListEventReceived(Event_RemoveFromList *event); void userJoinedEventReceived(Event_UserJoined *event); diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index ff8e44742..1ba308b6d 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -298,8 +298,8 @@ QString CardInfo::getMainCardType() const QString CardInfo::getCorrectedName() const { QString result = name; - // Fire // Ice, Circle of Protection: Red - return result.remove(" // ").remove(":"); + // Fire // Ice, Circle of Protection: Red, "Ach! Hans, Run!", Who/What/When/Where/Why, Question Elemental? + return result.remove(" // ").remove(':').remove('"').remove('?').replace('/', ' '); } void CardInfo::addToSet(CardSet *set) diff --git a/cockatrice/src/carddatabasemodel.h b/cockatrice/src/carddatabasemodel.h index 453782579..d6404b422 100644 --- a/cockatrice/src/carddatabasemodel.h +++ b/cockatrice/src/carddatabasemodel.h @@ -31,11 +31,11 @@ private: QSet cardTypes, cardColors; public: CardDatabaseDisplayModel(QObject *parent = 0); - void setCardNameBeginning(const QString &_beginning) { cardNameBeginning = _beginning; invalidateFilter(); } - void setCardName(const QString &_cardName) { cardName = _cardName; invalidateFilter(); } - void setCardText(const QString &_cardText) { cardText = _cardText; invalidateFilter(); } - void setCardTypes(const QSet &_cardTypes) { cardTypes = _cardTypes; invalidateFilter(); } - void setCardColors(const QSet &_cardColors) { cardColors = _cardColors; invalidateFilter(); } + void setCardNameBeginning(const QString &_beginning) { cardNameBeginning = _beginning; invalidate(); } + void setCardName(const QString &_cardName) { cardName = _cardName; invalidate(); } + void setCardText(const QString &_cardText) { cardText = _cardText; invalidate(); } + void setCardTypes(const QSet &_cardTypes) { cardTypes = _cardTypes; invalidate(); } + void setCardColors(const QSet &_cardColors) { cardColors = _cardColors; invalidate(); } void clearSearch(); protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; diff --git a/cockatrice/src/cardinfowidget.cpp b/cockatrice/src/cardinfowidget.cpp index 3e7268bf3..1ce584b2f 100644 --- a/cockatrice/src/cardinfowidget.cpp +++ b/cockatrice/src/cardinfowidget.cpp @@ -11,13 +11,24 @@ #include "settingscache.h" CardInfoWidget::CardInfoWidget(ResizeMode _mode, QWidget *parent, Qt::WindowFlags flags) - : QFrame(parent, flags), pixmapWidth(160), aspectRatio((qreal) CARD_HEIGHT / (qreal) CARD_WIDTH), minimized(false), mode(_mode), minimizeButton(0), info(0) + : QFrame(parent, flags) + , pixmapWidth(160) + , aspectRatio((qreal) CARD_HEIGHT / (qreal) CARD_WIDTH) + , minimized(settingsCache->getCardInfoMinimized()) // Initialize the cardinfo view status from cache. + , mode(_mode) + , info(0) { if (mode == ModeGameTab) { - minimizeButton = new QPushButton(QIcon(style()->standardIcon(QStyle::SP_ArrowUp)), QString()); - connect(minimizeButton, SIGNAL(clicked()), this, SLOT(minimizeClicked())); + // Create indexed list of status views for card. + const QStringList cardInfoStatus = QStringList() << tr("Hide card info") << tr("Show card only") << tr("Show text only") << tr("Show full info"); + + // Create droplist for cardinfo view selection, and set right current index. + dropList = new QComboBox(); + dropList->addItems(cardInfoStatus); + dropList->setCurrentIndex(minimized); + connect(dropList, SIGNAL(currentIndexChanged(int)), this, SLOT(minimizeClicked(int))); } - + cardPicture = new QLabel; cardPicture->setAlignment(Qt::AlignCenter); @@ -39,7 +50,7 @@ CardInfoWidget::CardInfoWidget(ResizeMode _mode, QWidget *parent, Qt::WindowFlag QGridLayout *grid = new QGridLayout(this); int row = 0; if (mode == ModeGameTab) - grid->addWidget(minimizeButton, row++, 1, 1, 1, Qt::AlignRight); + grid->addWidget(dropList, row++, 1, 1, 1, Qt::AlignRight); grid->addWidget(cardPicture, row++, 0, 1, 2); grid->addWidget(nameLabel1, row, 0); grid->addWidget(nameLabel2, row++, 1); @@ -70,30 +81,38 @@ CardInfoWidget::CardInfoWidget(ResizeMode _mode, QWidget *parent, Qt::WindowFlag setFixedHeight(sizeHint().height()); } -void CardInfoWidget::minimizeClicked() +void CardInfoWidget::minimizeClicked(int newMinimized) { - setMinimized(!minimized); - settingsCache->setCardInfoMinimized(minimized); + // Set new status, and store it in the settings cache. + setMinimized(newMinimized); + settingsCache->setCardInfoMinimized(newMinimized); } -void CardInfoWidget::setMinimized(bool _minimized) +void CardInfoWidget::setMinimized(int _minimized) { minimized = _minimized; - - cardPicture->setVisible(!minimized); - nameLabel2->setVisible(!minimized); - nameLabel1->setVisible(!minimized); - manacostLabel1->setVisible(!minimized); - manacostLabel2->setVisible(!minimized); - cardtypeLabel1->setVisible(!minimized); - cardtypeLabel2->setVisible(!minimized); - powtoughLabel1->setVisible(!minimized); - powtoughLabel2->setVisible(!minimized); - textLabel->setVisible(!minimized); - - if (minimizeButton) - minimizeButton->setIcon(style()->standardIcon(minimized ? QStyle::SP_ArrowDown : QStyle::SP_ArrowUp)); - + + // Set the picture to be shown only at "card only" (1) and "full info" (3) + if (minimized == 1 || minimized == 3) { + cardPicture->setVisible(true); + } else { + cardPicture->setVisible(false); + } + + // Set the rest of the fields to be shown only at "full info" (3) and "oracle only" (2) + bool showAll = (minimized == 2 || minimized == 3) ? true : false; + + // Toggle oracle fields as according to selected view. + nameLabel2->setVisible(showAll); + nameLabel1->setVisible(showAll); + manacostLabel1->setVisible(showAll); + manacostLabel2->setVisible(showAll); + cardtypeLabel1->setVisible(showAll); + cardtypeLabel2->setVisible(showAll); + powtoughLabel1->setVisible(showAll); + powtoughLabel2->setVisible(showAll); + textLabel->setVisible(showAll); + setFixedHeight(sizeHint().height()); } @@ -153,8 +172,7 @@ void CardInfoWidget::resizeEvent(QResizeEvent * /*event*/) } } -void CardInfoWidget::mouseReleaseEvent(QMouseEvent *event) +QString CardInfoWidget::getCardName() const { - if ((event->button() == Qt::MidButton) && (mode == ModePopUp)) - emit mouseReleased(); -} + return nameLabel2->text(); +} \ No newline at end of file diff --git a/cockatrice/src/cardinfowidget.h b/cockatrice/src/cardinfowidget.h index d140009e4..21ee7ccd6 100644 --- a/cockatrice/src/cardinfowidget.h +++ b/cockatrice/src/cardinfowidget.h @@ -2,6 +2,8 @@ #define CARDINFOWIDGET_H #include +#include +#include class QLabel; class QTextEdit; @@ -13,40 +15,44 @@ class QMouseEvent; class CardInfoWidget : public QFrame { Q_OBJECT + public: enum ResizeMode { ModeDeckEditor, ModeGameTab, ModePopUp }; + private: int pixmapWidth; qreal aspectRatio; - bool minimized; + int minimized; // 0 - minimized, 1 - card, 2 - oracle only, 3 - full ResizeMode mode; - QPushButton *minimizeButton; + QComboBox *dropList; QLabel *cardPicture; QLabel *nameLabel1, *nameLabel2; QLabel *manacostLabel1, *manacostLabel2; QLabel *cardtypeLabel1, *cardtypeLabel2; QLabel *powtoughLabel1, *powtoughLabel2; QTextEdit *textLabel; - + CardInfo *info; - void setMinimized(bool _minimized); + void setMinimized(int _minimized); + public: CardInfoWidget(ResizeMode _mode, QWidget *parent = 0, Qt::WindowFlags f = 0); void retranslateUi(); + QString getCardName() const; + public slots: void setCard(CardInfo *card); void setCard(const QString &cardName); void setCard(AbstractCardItem *card); + private slots: void clear(); void updatePixmap(); - void minimizeClicked(); -signals: - void mouseReleased(); + void minimizeClicked(int newMinimized); + protected: void resizeEvent(QResizeEvent *event); - void mouseReleaseEvent(QMouseEvent *event); }; #endif diff --git a/cockatrice/src/carditem.cpp b/cockatrice/src/carditem.cpp index 21ae3bb68..afc15e8c0 100644 --- a/cockatrice/src/carditem.cpp +++ b/cockatrice/src/carditem.cpp @@ -34,6 +34,8 @@ CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, bool _reve connect(aAttach, SIGNAL(triggered()), this, SLOT(actAttach())); aUnattach = new QAction(this); connect(aUnattach, SIGNAL(triggered()), this, SLOT(actUnattach())); + aDrawArrow = new QAction(this); + connect(aDrawArrow, SIGNAL(triggered()), this, SLOT(actDrawArrow())); aIncP = new QAction(this); connect(aIncP, SIGNAL(triggered()), this, SLOT(actIncP())); aDecP = new QAction(this); @@ -172,6 +174,7 @@ void CardItem::updateCardMenu() cardMenu->addAction(aAttach); if (attachedTo) cardMenu->addAction(aUnattach); + cardMenu->addAction(aDrawArrow); cardMenu->addSeparator(); cardMenu->addMenu(ptMenu); cardMenu->addAction(aSetAnnotation); @@ -186,6 +189,9 @@ void CardItem::updateCardMenu() cardMenu->addAction(aSetCounter[i]); } cardMenu->addSeparator(); + } else if (zone->getName() == "stack") { + cardMenu->addAction(aDrawArrow); + cardMenu->addMenu(moveMenu); } else { cardMenu->addAction(aPlay); cardMenu->addMenu(moveMenu); @@ -209,6 +215,7 @@ void CardItem::retranslateUi() aAttach->setText(tr("&Attach to card...")); aAttach->setShortcut(tr("Ctrl+A")); aUnattach->setText(tr("Unattac&h")); + aDrawArrow->setText(tr("&Draw arrow...")); ptMenu->setTitle(tr("&Power / toughness")); aIncP->setText(tr("&Increase power")); aIncP->setShortcut(tr("Ctrl++")); @@ -360,7 +367,7 @@ void CardItem::resetState() annotation.clear(); attachedTo = 0; attachedCards.clear(); - setTapped(false); + setTapped(false, false); setDoesntUntap(false); update(); } @@ -380,6 +387,7 @@ void CardItem::processCardInfo(ServerInfo_Card *info) setColor(info->getColor()); setTapped(info->getTapped()); setDestroyOnZoneChange(info->getDestroyOnZoneChange()); + setDoesntUntap(info->getDoesntUntap()); } CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPointF &_scenePos, bool faceDown) @@ -398,13 +406,35 @@ void CardItem::deleteDragItem() dragItem = NULL; } +void CardItem::drawArrow(const QColor &arrowColor) +{ + if (static_cast(owner->parent())->getSpectator()) + return; + + Player *arrowOwner = static_cast(owner->parent())->getActiveLocalPlayer(); + ArrowDragItem *arrow = new ArrowDragItem(arrowOwner, this, arrowColor); + scene()->addItem(arrow); + arrow->grabMouse(); + + QListIterator itemIterator(scene()->selectedItems()); + while (itemIterator.hasNext()) { + CardItem *c = qgraphicsitem_cast(itemIterator.next()); + if (!c || (c == this)) + continue; + if (c->getZone() != zone) + continue; + + ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, c, arrowColor); + scene()->addItem(childArrow); + arrow->addChildArrow(childArrow); + } +} + void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { if (event->buttons().testFlag(Qt::RightButton)) { if ((event->screenPos() - event->buttonDownScreenPos(Qt::RightButton)).manhattanLength() < 2 * QApplication::startDragDistance()) return; - if (static_cast(owner->parent())->getSpectator()) - return; QColor arrowColor = Qt::red; if (event->modifiers().testFlag(Qt::ControlModifier)) @@ -414,23 +444,7 @@ void CardItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) else if (event->modifiers().testFlag(Qt::ShiftModifier)) arrowColor = Qt::green; - Player *arrowOwner = static_cast(owner->parent())->getActiveLocalPlayer(); - ArrowDragItem *arrow = new ArrowDragItem(arrowOwner, this, arrowColor); - scene()->addItem(arrow); - arrow->grabMouse(); - - QListIterator itemIterator(scene()->selectedItems()); - while (itemIterator.hasNext()) { - CardItem *c = qgraphicsitem_cast(itemIterator.next()); - if (!c || (c == this)) - continue; - if (c->getZone() != zone) - continue; - - ArrowDragItem *childArrow = new ArrowDragItem(arrowOwner, c, arrowColor); - scene()->addItem(childArrow); - arrow->addChildArrow(childArrow); - } + drawArrow(arrowColor); } else if (event->buttons().testFlag(Qt::LeftButton)) { if ((event->screenPos() - event->buttonDownScreenPos(Qt::LeftButton)).manhattanLength() < 2 * QApplication::startDragDistance()) return; @@ -546,6 +560,11 @@ void CardItem::actUnattach() owner->actUnattach(static_cast(sender())); } +void CardItem::actDrawArrow() +{ + drawArrow(Qt::red); +} + void CardItem::actIncP() { owner->actIncPT(1, 0); diff --git a/cockatrice/src/carditem.h b/cockatrice/src/carditem.h index 88b19d6f3..6c02a4bbe 100644 --- a/cockatrice/src/carditem.h +++ b/cockatrice/src/carditem.h @@ -9,6 +9,7 @@ class CardZone; class ServerInfo_Card; class Player; class QAction; +class QColor; const int MAX_COUNTERS_ON_CARD = 999; @@ -33,17 +34,19 @@ private: QList aAddCounter, aSetCounter, aRemoveCounter; QAction *aPlay, *aHide, - *aTap, *aUntap, *aDoesntUntap, *aAttach, *aUnattach, *aSetPT, *aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aSetAnnotation, *aFlip, *aClone, + *aTap, *aUntap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aIncP, *aDecP, *aIncT, *aDecT, *aIncPT, *aDecPT, *aSetAnnotation, *aFlip, *aClone, *aMoveToTopLibrary, *aMoveToBottomLibrary, *aMoveToGraveyard, *aMoveToExile; QMenu *cardMenu, *ptMenu, *moveMenu; void playCard(bool faceDown); + void drawArrow(const QColor &arrowColor); void prepareDelete(); private slots: void cardMenuAction(); void actCardCounterTrigger(); void actAttach(); void actUnattach(); + void actDrawArrow(); void actSetPT(); void actIncP(); void actDecP(); diff --git a/cockatrice/src/cardzone.cpp b/cockatrice/src/cardzone.cpp index 3c3606ee2..ceaf08523 100644 --- a/cockatrice/src/cardzone.cpp +++ b/cockatrice/src/cardzone.cpp @@ -46,35 +46,36 @@ void CardZone::clearContents() QString CardZone::getTranslatedName(bool hisOwn, GrammaticalCase gc) const { QString ownerName = player->getName(); + bool female = player->getUserInfo()->getGender() == ServerInfo_User::Female; if (name == "hand") switch (gc) { - case CaseNominative: return hisOwn ? tr("his hand", "nominative") : tr("%1's hand", "nominative").arg(ownerName); - case CaseGenitive: return hisOwn ? tr("of his hand", "genitive") : tr("of %1's hand", "genitive").arg(ownerName); - case CaseAccusative: return hisOwn ? tr("his hand", "accusative") : tr("%1's hand", "accusative").arg(ownerName); + case CaseNominative: return female ? (hisOwn ? tr("her hand", "nominative, female owner") : tr("%1's hand", "nominative, female owner").arg(ownerName)) : (hisOwn ? tr("his hand", "nominative, male owner") : tr("%1's hand", "nominative, male owner").arg(ownerName)); + case CaseGenitive: return female ? (hisOwn ? tr("of her hand", "genitive, female owner") : tr("of %1's hand", "genitive, female owner").arg(ownerName)) : (hisOwn ? tr("of his hand", "genitive, male owner") : tr("of %1's hand", "genitive, male owner").arg(ownerName)); + case CaseAccusative: return female ? (hisOwn ? tr("her hand", "accusative, female owner") : tr("%1's hand", "accusative, female owner").arg(ownerName)) : (hisOwn ? tr("his hand", "accusative, male owner") : tr("%1's hand", "accusative, male owner").arg(ownerName)); } else if (name == "deck") switch (gc) { - case CaseNominative: return hisOwn ? tr("his library", "nominative") : tr("%1's library", "nominative").arg(ownerName); - case CaseGenitive: return hisOwn ? tr("of his library", "genitive") : tr("of %1's library", "genitive").arg(ownerName); - case CaseAccusative: return hisOwn ? tr("his library", "accusative") : tr("%1's library", "accusative").arg(ownerName); + case CaseNominative: return female ? (hisOwn ? tr("her library", "nominative, female owner") : tr("%1's library", "nominative, female owner").arg(ownerName)) : (hisOwn ? tr("his library", "nominative, male owner") : tr("%1's library", "nominative, male owner").arg(ownerName)); + case CaseGenitive: return female ? (hisOwn ? tr("of her library", "genitive, female owner") : tr("of %1's library", "genitive, female owner").arg(ownerName)) : (hisOwn ? tr("of his library", "genitive, male owner") : tr("of %1's library", "genitive, male owner").arg(ownerName)); + case CaseAccusative: return female ? (hisOwn ? tr("her library", "accusative, female owner") : tr("%1's library", "accusative, female owner").arg(ownerName)) : (hisOwn ? tr("his library", "accusative, male owner") : tr("%1's library", "accusative, male owner").arg(ownerName)); } else if (name == "grave") switch (gc) { - case CaseNominative: return hisOwn ? tr("his graveyard", "nominative") : tr("%1's graveyard", "nominative").arg(ownerName); - case CaseGenitive: return hisOwn ? tr("of his graveyard", "genitive") : tr("of %1's graveyard", "genitive").arg(ownerName); - case CaseAccusative: return hisOwn ? tr("his graveyard", "accusative") : tr("%1's graveyard", "accusative").arg(ownerName); + case CaseNominative: return female ? (hisOwn ? tr("her graveyard", "nominative, female owner") : tr("%1's graveyard", "nominative, female owner").arg(ownerName)) : (hisOwn ? tr("his graveyard", "nominative, male owner") : tr("%1's graveyard", "nominative, male owner").arg(ownerName)); + case CaseGenitive: return female ? (hisOwn ? tr("of her graveyard", "genitive, female owner") : tr("of %1's graveyard", "genitive, female owner").arg(ownerName)) : (hisOwn ? tr("of his graveyard", "genitive, male owner") : tr("of %1's graveyard", "genitive, male owner").arg(ownerName)); + case CaseAccusative: return female ? (hisOwn ? tr("her graveyard", "accusative, female owner") : tr("%1's graveyard", "accusative, female owner").arg(ownerName)) : (hisOwn ? tr("his graveyard", "accusative, male owner") : tr("%1's graveyard", "accusative, male owner").arg(ownerName)); } else if (name == "rfg") switch (gc) { - case CaseNominative: return hisOwn ? tr("his exile", "nominative") : tr("%1's exile", "nominative").arg(ownerName); - case CaseGenitive: return hisOwn ? tr("of his exile", "genitive") : tr("of %1's exile", "genitive").arg(ownerName); - case CaseAccusative: return hisOwn ? tr("his exile", "accusative") : tr("%1's exile", "accusative").arg(ownerName); + case CaseNominative: return female ? (hisOwn ? tr("her exile", "nominative, female owner") : tr("%1's exile", "nominative, female owner").arg(ownerName)) : (hisOwn ? tr("his exile", "nominative, male owner") : tr("%1's exile", "nominative, male owner").arg(ownerName)); + case CaseGenitive: return female ? (hisOwn ? tr("of her exile", "genitive, female owner") : tr("of %1's exile", "genitive, female owner").arg(ownerName)) : (hisOwn ? tr("of his exile", "genitive, male owner") : tr("of %1's exile", "genitive, male owner").arg(ownerName)); + case CaseAccusative: return female ? (hisOwn ? tr("her exile", "accusative, female owner") : tr("%1's exile", "accusative, female owner").arg(ownerName)) : (hisOwn ? tr("his exile", "accusative, male owner") : tr("%1's exile", "accusative, male owner").arg(ownerName)); } else if (name == "sb") switch (gc) { - case CaseNominative: return hisOwn ? tr("his sideboard", "nominative") : tr("%1's sideboard", "nominative").arg(ownerName); - case CaseGenitive: return hisOwn ? tr("of his sideboard", "genitive") : tr("of %1's sideboard", "genitive").arg(ownerName); - case CaseAccusative: return hisOwn ? tr("his sideboard", "accusative") : tr("%1's sideboard", "accusative").arg(ownerName); + case CaseNominative: return female ? (hisOwn ? tr("her sideboard", "nominative, female owner") : tr("%1's sideboard", "nominative, female owner").arg(ownerName)) : (hisOwn ? tr("his sideboard", "nominative, male owner") : tr("%1's sideboard", "nominative, male owner").arg(ownerName)); + case CaseGenitive: return female ? (hisOwn ? tr("of her sideboard", "genitive, female owner") : tr("of %1's sideboard", "genitive, female owner").arg(ownerName)) : (hisOwn ? tr("of his sideboard", "genitive, male owner") : tr("of %1's sideboard", "genitive, male owner").arg(ownerName)); + case CaseAccusative: return female ? (hisOwn ? tr("her sideboard", "accusative, female owner") : tr("%1's sideboard", "accusative, female owner").arg(ownerName)) : (hisOwn ? tr("his sideboard", "accusative, male owner") : tr("%1's sideboard", "accusative, male owner").arg(ownerName)); } return QString(); } diff --git a/cockatrice/src/chatview.cpp b/cockatrice/src/chatview.cpp index 92696cf01..9aecfd1ee 100644 --- a/cockatrice/src/chatview.cpp +++ b/cockatrice/src/chatview.cpp @@ -1,45 +1,198 @@ #include #include -#include #include +#include +#include #include "chatview.h" -ChatView::ChatView(const QString &_ownName, QWidget *parent) - : QTextEdit(parent), ownName(_ownName) +ChatView::ChatView(const QString &_ownName, bool _showTimestamps, QWidget *parent) + : QTextBrowser(parent), evenNumber(true), ownName(_ownName), showTimestamps(_showTimestamps) { - setTextInteractionFlags(Qt::TextSelectableByMouse); + setReadOnly(true); + setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse); + setOpenLinks(false); + connect(this, SIGNAL(anchorClicked(const QUrl &)), this, SLOT(openLink(const QUrl &))); } -void ChatView::appendMessage(QString sender, const QString &message) +QTextCursor ChatView::prepareBlock(bool same) { + lastSender.clear(); + QTextCursor cursor(document()->lastBlock()); cursor.movePosition(QTextCursor::End); + if (!same) { + QTextBlockFormat blockFormat; + if ((evenNumber = !evenNumber)) + blockFormat.setBackground(palette().alternateBase()); + blockFormat.setBottomMargin(2); + cursor.insertBlock(blockFormat); + } else + cursor.insertHtml("
"); - QTextBlockFormat blockFormat; - blockFormat.setBottomMargin(3); - cursor.insertBlock(blockFormat); + return cursor; +} + +void ChatView::appendHtml(const QString &html) +{ + prepareBlock().insertHtml(html); + verticalScrollBar()->setValue(verticalScrollBar()->maximum()); +} + +void ChatView::appendMessage(QString sender, QString message, QColor playerColor, bool playerBold) +{ + bool sameSender = (sender == lastSender) && !lastSender.isEmpty(); + QTextCursor cursor = prepareBlock(sameSender); + lastSender = sender; - QTextCharFormat timeFormat; - timeFormat.setForeground(Qt::black); - cursor.setCharFormat(timeFormat); - cursor.insertText(QDateTime::currentDateTime().toString("[hh:mm] ")); + if (showTimestamps) { + QTextCharFormat timeFormat; + if (sameSender) + timeFormat.setForeground(Qt::transparent); + else + timeFormat.setForeground(Qt::black); + cursor.setCharFormat(timeFormat); + cursor.insertText(QDateTime::currentDateTime().toString("[hh:mm] ")); + } QTextCharFormat senderFormat; if (sender == ownName) { senderFormat.setFontWeight(QFont::Bold); senderFormat.setForeground(Qt::red); - } else - senderFormat.setForeground(Qt::blue); + } else { + if (playerColor == QColor()) + senderFormat.setForeground(QColor(0, 0, 254)); + else + senderFormat.setForeground(playerColor); + if (playerBold) + senderFormat.setFontWeight(QFont::Bold); + } + if (sameSender) + senderFormat.setForeground(Qt::transparent); cursor.setCharFormat(senderFormat); if (!sender.isEmpty()) - sender.append(" "); + sender.append(": "); cursor.insertText(sender); QTextCharFormat messageFormat; if (sender.isEmpty()) messageFormat.setForeground(Qt::darkGreen); cursor.setCharFormat(messageFormat); - cursor.insertText(message); + + int from = 0, index = 0; + while ((index = message.indexOf('[', from)) != -1) { + cursor.insertText(message.left(index)); + message = message.mid(index); + if (message.isEmpty()) + break; + + if (message.startsWith("[card]")) { + message = message.mid(6); + QTextCharFormat tempFormat = messageFormat; + tempFormat.setForeground(Qt::blue); + cursor.setCharFormat(tempFormat); + int closeTagIndex = message.indexOf("[/card]"); + cursor.insertText(message.left(closeTagIndex)); + cursor.setCharFormat(messageFormat); + if (closeTagIndex == -1) + message.clear(); + else + message = message.mid(closeTagIndex + 7); + } else if (message.startsWith("[url]")) { + message = message.mid(5); + int closeTagIndex = message.indexOf("[/url]"); + QString url = message.left(closeTagIndex); + if (!url.startsWith("http://")) + url.prepend("http://"); + QTextCharFormat tempFormat = messageFormat; + tempFormat.setForeground(QColor(0, 0, 254)); + tempFormat.setAnchor(true); + tempFormat.setAnchorHref(url); + cursor.setCharFormat(tempFormat); + cursor.insertText(url); + cursor.setCharFormat(messageFormat); + if (closeTagIndex == -1) + message.clear(); + else + message = message.mid(closeTagIndex + 6); + } else + from = 1; + } + if (!message.isEmpty()) + cursor.insertText(message); verticalScrollBar()->setValue(verticalScrollBar()->maximum()); } + +void ChatView::enterEvent(QEvent * /*event*/) +{ + setMouseTracking(true); +} + +void ChatView::leaveEvent(QEvent * /*event*/) +{ + setMouseTracking(false); +} + +QTextFragment ChatView::getFragmentUnderMouse(const QPoint &pos) const +{ + QTextCursor cursor(cursorForPosition(pos)); + QTextBlock block(cursor.block()); + QTextBlock::iterator it; + for (it = block.begin(); !(it.atEnd()); ++it) { + QTextFragment frag = it.fragment(); + if (frag.contains(cursor.position())) + return frag; + } + return QTextFragment(); +} + +QString ChatView::getCardNameUnderMouse(QTextFragment frag) const +{ + if (frag.charFormat().foreground().color() == Qt::blue) + return frag.text(); + return QString(); +} + +QString ChatView::getCardNameUnderMouse(const QPoint &pos) const +{ + return getCardNameUnderMouse(getFragmentUnderMouse(pos)); +} + +void ChatView::mouseMoveEvent(QMouseEvent *event) +{ + QTextFragment frag = getFragmentUnderMouse(event->pos()); + QString cardName = getCardNameUnderMouse(frag); + if (!cardName.isEmpty()) { + viewport()->setCursor(Qt::PointingHandCursor); + emit cardNameHovered(cardName); + } else if (frag.charFormat().isAnchor()) + viewport()->setCursor(Qt::PointingHandCursor); + else + viewport()->setCursor(Qt::IBeamCursor); + + QTextBrowser::mouseMoveEvent(event); +} + +void ChatView::mousePressEvent(QMouseEvent *event) +{ + if (event->button() == Qt::MidButton) { + QString cardName = getCardNameUnderMouse(event->pos()); + if (!cardName.isEmpty()) + emit showCardInfoPopup(event->globalPos(), cardName); + } + + QTextBrowser::mousePressEvent(event); +} + +void ChatView::mouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() == Qt::MidButton) + emit deleteCardInfoPopup(QString("_")); + + QTextBrowser::mouseReleaseEvent(event); +} + +void ChatView::openLink(const QUrl &link) +{ + QDesktopServices::openUrl(link); +} diff --git a/cockatrice/src/chatview.h b/cockatrice/src/chatview.h index bd7e763aa..33c583c68 100644 --- a/cockatrice/src/chatview.h +++ b/cockatrice/src/chatview.h @@ -1,18 +1,41 @@ #ifndef CHATVIEW_H #define CHATVIEW_H -#include +#include +#include +#include +#include class QTextTable; +class QMouseEvent; -class ChatView : public QTextEdit { +class ChatView : public QTextBrowser { Q_OBJECT; private: - QTextTable *table; + QString lastSender; + bool evenNumber; QString ownName; + bool showTimestamps; + QTextFragment getFragmentUnderMouse(const QPoint &pos) const; + QString getCardNameUnderMouse(QTextFragment frag) const; + QString getCardNameUnderMouse(const QPoint &pos) const; + QTextCursor prepareBlock(bool same = false); +private slots: + void openLink(const QUrl &link); public: - ChatView(const QString &_ownName, QWidget *parent = 0); - void appendMessage(QString sender, const QString &message); + ChatView(const QString &_ownName, bool _showTimestamps, QWidget *parent = 0); + void appendHtml(const QString &html); + void appendMessage(QString sender, QString message, QColor playerColor = QColor(), bool playerBold = false); +protected: + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); +signals: + void cardNameHovered(QString cardName); + void showCardInfoPopup(QPoint pos, QString cardName); + void deleteCardInfoPopup(QString cardName); }; #endif \ No newline at end of file diff --git a/cockatrice/src/decklistmodel.cpp b/cockatrice/src/decklistmodel.cpp index 1084f3457..82a443264 100644 --- a/cockatrice/src/decklistmodel.cpp +++ b/cockatrice/src/decklistmodel.cpp @@ -10,6 +10,7 @@ #include "main.h" #include "decklistmodel.h" #include "carddatabase.h" +#include "settingscache.h" DeckListModel::DeckListModel(QObject *parent) : QAbstractItemModel(parent) @@ -65,12 +66,20 @@ int DeckListModel::rowCount(const QModelIndex &parent) const return 0; } +int DeckListModel::columnCount(const QModelIndex &/*parent*/) const +{ + if (settingsCache->getPriceTagFeature()) + return 3; + else + return 2; +} + QVariant DeckListModel::data(const QModelIndex &index, int role) const { // debugIndexInfo("data", index); if (!index.isValid()) return QVariant(); - if (index.column() >= 2) + if (index.column() >= columnCount()) return QVariant(); AbstractDecklistNode *temp = static_cast(index.internalPointer()); @@ -86,8 +95,9 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: case Qt::EditRole: switch (index.column()) { - case 0: return node->recursiveCount(true); - case 1: return node->getVisibleName(); + case 0: return node->recursiveCount(true); + case 1: return node->getVisibleName(); + case 2: return QString().sprintf("$%.2f", node->recursivePrice(true)); default: return QVariant(); } case Qt::BackgroundRole: { @@ -101,8 +111,9 @@ QVariant DeckListModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: case Qt::EditRole: { switch (index.column()) { - case 0: return card->getNumber(); - case 1: return card->getName(); + case 0: return card->getNumber(); + case 1: return card->getName(); + case 2: return QString().sprintf("$%.2f", card->getTotalPrice()); default: return QVariant(); } } @@ -119,9 +130,12 @@ QVariant DeckListModel::headerData(int section, Qt::Orientation orientation, int { if ((role != Qt::DisplayRole) || (orientation != Qt::Horizontal)) return QVariant(); + if (section >= columnCount()) + return QVariant(); switch (section) { - case 0: return tr("Number"); - case 1: return tr("Card"); + case 0: return tr("Number"); + case 1: return tr("Card"); + case 2: return tr("Price"); default: return QVariant(); } } @@ -174,8 +188,9 @@ bool DeckListModel::setData(const QModelIndex &index, const QVariant &value, int return false; switch (index.column()) { - case 0: node->setNumber(value.toInt()); break; - case 1: node->setName(value.toString()); break; + case 0: node->setNumber(value.toInt()); break; + case 1: node->setName(value.toString()); break; + case 2: node->setPrice(value.toFloat()); break; default: return false; } emitRecursiveUpdates(index); @@ -300,7 +315,7 @@ void DeckListModel::setDeckList(DeckList *_deck) void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *node) { - static const int totalColumns = 3; + const int totalColumns = settingsCache->getPriceTagFeature() ? 3 : 2; if (node->height() == 1) { QTextBlockFormat blockFormat; @@ -308,13 +323,16 @@ void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *no charFormat.setFontPointSize(11); charFormat.setFontWeight(QFont::Bold); cursor->insertBlock(blockFormat, charFormat); - cursor->insertText(QString("%1: %2").arg(node->getVisibleName()).arg(node->recursiveCount(true))); + QString priceStr; + if (settingsCache->getPriceTagFeature()) + priceStr = QString().sprintf(": $%.2f", node->recursivePrice(true)); + cursor->insertText(QString("%1: %2").arg(node->getVisibleName()).arg(node->recursiveCount(true)).append(priceStr)); QTextTableFormat tableFormat; tableFormat.setCellPadding(0); tableFormat.setCellSpacing(0); tableFormat.setBorder(0); - QTextTable *table = cursor->insertTable(node->size() + 1, 2, tableFormat); + QTextTable *table = cursor->insertTable(node->size() + 1, totalColumns, tableFormat); for (int i = 0; i < node->size(); i++) { AbstractDecklistCardNode *card = dynamic_cast(node->at(i)); @@ -330,6 +348,13 @@ void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *no cell.setFormat(cellCharFormat); cellCursor = cell.firstCursorPosition(); cellCursor.insertText(card->getName()); + + if (settingsCache->getPriceTagFeature()) { + cell = table->cellAt(i, 2); + cell.setFormat(cellCharFormat); + cellCursor = cell.firstCursorPosition(); + cellCursor.insertText(QString().sprintf("$%.2f ", card->getTotalPrice())); + } } } else if (node->height() == 2) { QTextBlockFormat blockFormat; @@ -338,7 +363,10 @@ void DeckListModel::printDeckListNode(QTextCursor *cursor, InnerDecklistNode *no charFormat.setFontWeight(QFont::Bold); cursor->insertBlock(blockFormat, charFormat); - cursor->insertText(QString("%1: %2").arg(node->getVisibleName()).arg(node->recursiveCount(true))); + QString priceStr; + if (settingsCache->getPriceTagFeature()) + priceStr = QString().sprintf(": $%.2f", node->recursivePrice(true)); + cursor->insertText(QString("%1: %2").arg(node->getVisibleName()).arg(node->recursiveCount(true)).append(priceStr)); QTextTableFormat tableFormat; tableFormat.setCellPadding(10); @@ -391,3 +419,14 @@ void DeckListModel::printDeckList(QPrinter *printer) doc.print(printer); } + +void DeckListModel::pricesUpdated(InnerDecklistNode *node) +{ + if (!node) + node = root; + + if (node->isEmpty()) + return; + + emit dataChanged(createIndex(0, 2, node->at(0)), createIndex(node->size() - 1, 2, node->last())); +} diff --git a/cockatrice/src/decklistmodel.h b/cockatrice/src/decklistmodel.h index f66f509de..a8a22c78b 100644 --- a/cockatrice/src/decklistmodel.h +++ b/cockatrice/src/decklistmodel.h @@ -17,6 +17,8 @@ public: DecklistModelCardNode(DecklistCardNode *_dataNode, InnerDecklistNode *_parent) : AbstractDecklistCardNode(_parent), dataNode(_dataNode) { } int getNumber() const { return dataNode->getNumber(); } void setNumber(int _number) { dataNode->setNumber(_number); } + float getPrice() const { return dataNode->getPrice(); } + void setPrice(float _price) { dataNode->setPrice(_price); } QString getName() const { return dataNode->getName(); } void setName(const QString &_name) { dataNode->setName(_name); } DecklistCardNode *getDataNode() const { return dataNode; } @@ -32,7 +34,7 @@ public: DeckListModel(QObject *parent = 0); ~DeckListModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const { return 2; } + int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; @@ -45,6 +47,7 @@ public: void cleanList(); DeckList *getDeckList() const { return deckList; } void setDeckList(DeckList *_deck); + void pricesUpdated(InnerDecklistNode *node = 0); private: DeckList *deckList; InnerDecklistNode *root; diff --git a/cockatrice/src/dlg_creategame.cpp b/cockatrice/src/dlg_creategame.cpp index b96c93a16..0d5b69f43 100644 --- a/cockatrice/src/dlg_creategame.cpp +++ b/cockatrice/src/dlg_creategame.cpp @@ -17,6 +17,7 @@ DlgCreateGame::DlgCreateGame(AbstractClient *_client, int _roomId, const QMapsetBuddy(descriptionEdit); + descriptionEdit->setMaxLength(60); maxPlayersLabel = new QLabel(tr("P&layers:")); maxPlayersEdit = new QSpinBox(); diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index 88bdfd989..01d4445a5 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "carddatabase.h" #include "dlg_settings.h" #include "main.h" @@ -242,8 +243,17 @@ AppearanceSettingsPage::AppearanceSettingsPage() invertVerticalCoordinateCheckBox->setChecked(settingsCache->getInvertVerticalCoordinate()); connect(invertVerticalCoordinateCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setInvertVerticalCoordinate(int))); + minPlayersForMultiColumnLayoutLabel = new QLabel; + minPlayersForMultiColumnLayoutEdit = new QSpinBox; + minPlayersForMultiColumnLayoutEdit->setMinimum(2); + minPlayersForMultiColumnLayoutEdit->setValue(settingsCache->getMinPlayersForMultiColumnLayout()); + connect(minPlayersForMultiColumnLayoutEdit, SIGNAL(valueChanged(int)), settingsCache, SLOT(setMinPlayersForMultiColumnLayout(int))); + minPlayersForMultiColumnLayoutLabel->setBuddy(minPlayersForMultiColumnLayoutEdit); + QGridLayout *tableGrid = new QGridLayout; tableGrid->addWidget(invertVerticalCoordinateCheckBox, 0, 0, 1, 2); + tableGrid->addWidget(minPlayersForMultiColumnLayoutLabel, 1, 0, 1, 1); + tableGrid->addWidget(minPlayersForMultiColumnLayoutEdit, 1, 1, 1, 1); tableGroupBox = new QGroupBox; tableGroupBox->setLayout(tableGrid); @@ -289,6 +299,7 @@ void AppearanceSettingsPage::retranslateUi() tableGroupBox->setTitle(tr("Table grid layout")); invertVerticalCoordinateCheckBox->setText(tr("Invert vertical coordinate")); + minPlayersForMultiColumnLayoutLabel->setText(tr("Minimum player count for multi-column layout:")); zoneViewGroupBox->setTitle(tr("Zone view layout")); zoneViewSortByNameCheckBox->setText(tr("Sort by name")); @@ -377,6 +388,8 @@ void AppearanceSettingsPage::cardBackPicturePathButtonClicked() UserInterfaceSettingsPage::UserInterfaceSettingsPage() { + QIcon deleteIcon(":/resources/icon_delete.svg"); + doubleClickToPlayCheckBox = new QCheckBox; doubleClickToPlayCheckBox->setChecked(settingsCache->getDoubleClickToPlay()); connect(doubleClickToPlayCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setDoubleClickToPlay(int))); @@ -391,6 +404,28 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() tapAnimationCheckBox->setChecked(settingsCache->getTapAnimation()); connect(tapAnimationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setTapAnimation(int))); + soundEnabledCheckBox = new QCheckBox; + soundEnabledCheckBox->setChecked(settingsCache->getSoundEnabled()); + connect(soundEnabledCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setSoundEnabled(int))); + + soundPathLabel = new QLabel; + soundPathEdit = new QLineEdit(settingsCache->getSoundPath()); + soundPathEdit->setReadOnly(true); + QPushButton *soundPathClearButton = new QPushButton(deleteIcon, QString()); + connect(soundPathClearButton, SIGNAL(clicked()), this, SLOT(soundPathClearButtonClicked())); + QPushButton *soundPathButton = new QPushButton("..."); + connect(soundPathButton, SIGNAL(clicked()), this, SLOT(soundPathButtonClicked())); + + QGridLayout *soundGrid = new QGridLayout; + soundGrid->addWidget(soundEnabledCheckBox, 0, 0, 1, 4); + soundGrid->addWidget(soundPathLabel, 1, 0); + soundGrid->addWidget(soundPathEdit, 1, 1); + soundGrid->addWidget(soundPathClearButton, 1, 2); + soundGrid->addWidget(soundPathButton, 1, 3); + + soundGroupBox = new QGroupBox; + soundGroupBox->setLayout(soundGrid); + QGridLayout *animationGrid = new QGridLayout; animationGrid->addWidget(tapAnimationCheckBox, 0, 0); @@ -400,6 +435,7 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(generalGroupBox); mainLayout->addWidget(animationGroupBox); + mainLayout->addWidget(soundGroupBox); setLayout(mainLayout); } @@ -410,6 +446,48 @@ void UserInterfaceSettingsPage::retranslateUi() doubleClickToPlayCheckBox->setText(tr("&Double-click cards to play them (instead of single-click)")); animationGroupBox->setTitle(tr("Animation settings")); tapAnimationCheckBox->setText(tr("&Tap/untap animation")); + soundEnabledCheckBox->setText(tr("Enable &sounds")); + soundPathLabel->setText(tr("Path to sounds directory:")); +} + +void UserInterfaceSettingsPage::soundPathClearButtonClicked() +{ + soundPathEdit->setText(QString()); + settingsCache->setSoundPath(QString()); +} + +void UserInterfaceSettingsPage::soundPathButtonClicked() +{ + QString path = QFileDialog::getExistingDirectory(this, tr("Choose path")); + if (path.isEmpty()) + return; + + soundPathEdit->setText(path); + settingsCache->setSoundPath(path); +} + +DeckEditorSettingsPage::DeckEditorSettingsPage() +{ + priceTagsCheckBox = new QCheckBox; + priceTagsCheckBox->setChecked(settingsCache->getPriceTagFeature()); + connect(priceTagsCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPriceTagFeature(int))); + + QGridLayout *generalGrid = new QGridLayout; + generalGrid->addWidget(priceTagsCheckBox, 0, 0); + + generalGroupBox = new QGroupBox; + generalGroupBox->setLayout(generalGrid); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(generalGroupBox); + + setLayout(mainLayout); +} + +void DeckEditorSettingsPage::retranslateUi() +{ + priceTagsCheckBox->setText(tr("Enable &price tag feature (using data from blacklotusproject.com)")); + generalGroupBox->setTitle(tr("General")); } MessagesSettingsPage::MessagesSettingsPage() @@ -490,6 +568,7 @@ DlgSettings::DlgSettings(QWidget *parent) pagesWidget->addWidget(new GeneralSettingsPage); pagesWidget->addWidget(new AppearanceSettingsPage); pagesWidget->addWidget(new UserInterfaceSettingsPage); + pagesWidget->addWidget(new DeckEditorSettingsPage); pagesWidget->addWidget(new MessagesSettingsPage); closeButton = new QPushButton; @@ -534,6 +613,11 @@ void DlgSettings::createIcons() userInterfaceButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); userInterfaceButton->setIcon(QIcon(":/resources/icon_config_interface.svg")); + deckEditorButton = new QListWidgetItem(contentsWidget); + deckEditorButton->setTextAlignment(Qt::AlignHCenter); + deckEditorButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + deckEditorButton->setIcon(QIcon(":/resources/icon_config_deckeditor.svg")); + messagesButton = new QListWidgetItem(contentsWidget); messagesButton->setTextAlignment(Qt::AlignHCenter); messagesButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); @@ -590,6 +674,7 @@ void DlgSettings::retranslateUi() generalButton->setText(tr("General")); appearanceButton->setText(tr("Appearance")); userInterfaceButton->setText(tr("User interface")); + deckEditorButton->setText(tr("Deck editor")); messagesButton->setText(tr("Messages")); closeButton->setText(tr("&Close")); diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index 70e231f20..f7bd1a522 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -14,6 +14,7 @@ class QGroupBox; class QCheckBox; class QLabel; class QCloseEvent; +class QSpinBox; class AbstractSettingsPage : public QWidget { public: @@ -65,10 +66,11 @@ signals: void playerAreaBgChanged(const QString &path); void cardBackPicturePathChanged(const QString &path); private: - QLabel *handBgLabel, *stackBgLabel, *tableBgLabel, *playerAreaBgLabel, *cardBackPicturePathLabel; + QLabel *handBgLabel, *stackBgLabel, *tableBgLabel, *playerAreaBgLabel, *cardBackPicturePathLabel, *minPlayersForMultiColumnLayoutLabel; QLineEdit *handBgEdit, *stackBgEdit, *tableBgEdit, *playerAreaBgEdit, *cardBackPicturePathEdit; QCheckBox *displayCardNamesCheckBox, *horizontalHandCheckBox, *invertVerticalCoordinateCheckBox, *zoneViewSortByNameCheckBox, *zoneViewSortByTypeCheckBox; QGroupBox *zoneBgGroupBox, *cardsGroupBox, *handGroupBox, *tableGroupBox, *zoneViewGroupBox; + QSpinBox *minPlayersForMultiColumnLayoutEdit; public: AppearanceSettingsPage(); void retranslateUi(); @@ -76,15 +78,33 @@ public: class UserInterfaceSettingsPage : public AbstractSettingsPage { Q_OBJECT +private slots: + void soundPathClearButtonClicked(); + void soundPathButtonClicked(); +signals: + void soundPathChanged(); private: QCheckBox *doubleClickToPlayCheckBox; QCheckBox *tapAnimationCheckBox; - QGroupBox *generalGroupBox, *animationGroupBox; + QCheckBox *soundEnabledCheckBox; + QLabel *soundPathLabel; + QLineEdit *soundPathEdit; + QGroupBox *generalGroupBox, *animationGroupBox, *soundGroupBox; public: UserInterfaceSettingsPage(); void retranslateUi(); }; +class DeckEditorSettingsPage : public AbstractSettingsPage { + Q_OBJECT +public: + DeckEditorSettingsPage(); + void retranslateUi(); +private: + QCheckBox *priceTagsCheckBox; + QGroupBox *generalGroupBox; +}; + class MessagesSettingsPage : public AbstractSettingsPage { Q_OBJECT public: @@ -110,7 +130,7 @@ private slots: private: QListWidget *contentsWidget; QStackedWidget *pagesWidget; - QListWidgetItem *generalButton, *appearanceButton, *userInterfaceButton, *messagesButton; + QListWidgetItem *generalButton, *appearanceButton, *userInterfaceButton, *deckEditorButton, *messagesButton; QPushButton *closeButton; void createIcons(); void retranslateUi(); diff --git a/cockatrice/src/gamescene.cpp b/cockatrice/src/gamescene.cpp index 7b62db5d6..8a8dd17c5 100644 --- a/cockatrice/src/gamescene.cpp +++ b/cockatrice/src/gamescene.cpp @@ -3,6 +3,8 @@ #include "zoneviewwidget.h" #include "zoneviewzone.h" #include "phasestoolbar.h" +#include "settingscache.h" +#include #include #include #include @@ -13,6 +15,7 @@ GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent) { animationTimer = new QBasicTimer; addItem(phasesToolbar); + connect(settingsCache, SIGNAL(minPlayersForMultiColumnLayoutChanged()), this, SLOT(rearrange())); } GameScene::~GameScene() @@ -31,7 +34,6 @@ void GameScene::addPlayer(Player *player) qDebug("GameScene::addPlayer"); players << player; addItem(player); - rearrange(); connect(player, SIGNAL(sizeChanged()), this, SLOT(rearrange())); connect(player, SIGNAL(gameConceded()), this, SLOT(rearrange())); } @@ -46,44 +48,63 @@ void GameScene::removePlayer(Player *player) void GameScene::rearrange() { - struct PlayerProcessor { - static void processPlayer(Player *p, qreal &w, QPointF &b, bool singlePlayer) - { - if (p->getConceded()) - return; - - const QRectF br = p->boundingRect(); - if (br.width() > w) - w = br.width(); - p->setPos(b); - p->setMirrored((b.y() < playerAreaSpacing) && !singlePlayer); - b += QPointF(0, br.height() + playerAreaSpacing); - } - }; - - qreal sceneHeight = -playerAreaSpacing; + playersByColumn.clear(); + + QList playersPlaying; + int firstPlayer = -1; for (int i = 0; i < players.size(); ++i) - if (!players[i]->getConceded()) - sceneHeight += players[i]->boundingRect().height() + playerAreaSpacing; + if (!players[i]->getConceded()) { + playersPlaying.append(players[i]); + if ((firstPlayer == -1) && (players[i]->getLocal())) + firstPlayer = playersPlaying.size() - 1; + } + if (firstPlayer == -1) + firstPlayer = 0; + const int playersCount = playersPlaying.size(); + const int columns = playersCount < settingsCache->getMinPlayersForMultiColumnLayout() ? 1 : 2; + const int rows = ceil((qreal) playersCount / columns); + + qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing; + QList columnWidth; + int firstPlayerOfColumn = firstPlayer; + for (int col = 0; col < columns; ++col) { + playersByColumn.append(QList()); + columnWidth.append(0); + qreal thisColumnHeight = -playerAreaSpacing; + const int rowsInColumn = rows - (playersCount % columns); + for (int j = 0; j < rowsInColumn; ++j) { + Player *player = playersPlaying[(firstPlayerOfColumn + j) % playersCount]; + if (col == 0) + playersByColumn[col].prepend(player); + else + playersByColumn[col].append(player); + thisColumnHeight += player->boundingRect().height() + playerAreaSpacing; + if (player->boundingRect().width() > columnWidth[col]) + columnWidth[col] = player->boundingRect().width(); + } + if (thisColumnHeight > sceneHeight) + sceneHeight = thisColumnHeight; + sceneWidth += columnWidth[col] + playerAreaSpacing; + + firstPlayerOfColumn += rowsInColumn; + } + phasesToolbar->setHeight(sceneHeight); qreal phasesWidth = phasesToolbar->getWidth(); - - QPointF base(phasesWidth, 0); - qreal sceneWidth; - QList localPlayers; - - for (int i = 0; i < players.size(); ++i) - if (!players[i]->getLocal()) - PlayerProcessor::processPlayer(players[i], sceneWidth, base, players.size() == 1); - else - localPlayers.append(players[i]); - - for (int i = 0; i < localPlayers.size(); ++i) - PlayerProcessor::processPlayer(localPlayers[i], sceneWidth, base, players.size() == 1); - sceneWidth += phasesWidth; - playersRect = QRectF(0, 0, sceneWidth, sceneHeight); - + + qreal x = phasesWidth; + for (int col = 0; col < columns; ++col) { + qreal y = 0; + for (int row = 0; row < playersByColumn[col].size(); ++row) { + Player *player = playersByColumn[col][row]; + player->setPos(x, y); + player->setMirrored(row != rows - 1); + y += player->boundingRect().height() + playerAreaSpacing; + } + x += columnWidth[col] + playerAreaSpacing; + } + setSceneRect(sceneRect().x(), sceneRect().y(), sceneWidth, sceneHeight); processViewSizeChange(viewSize); } @@ -139,24 +160,33 @@ void GameScene::processViewSizeChange(const QSize &newSize) qreal newRatio = ((qreal) newSize.width()) / newSize.height(); qreal minWidth = 0; - for (int i = 0; i < players.size(); ++i) { - qreal w = players[i]->getMinimumWidth(); - if (w > minWidth) - minWidth = w; + QList minWidthByColumn; + for (int col = 0; col < playersByColumn.size(); ++col) { + minWidthByColumn.append(0); + for (int row = 0; row < playersByColumn[col].size(); ++row) { + qreal w = playersByColumn[col][row]->getMinimumWidth(); + if (w > minWidthByColumn[col]) + minWidthByColumn[col] = w; + } + minWidth += minWidthByColumn[col]; } minWidth += phasesToolbar->getWidth(); qreal minRatio = minWidth / sceneRect().height(); + qreal newWidth; if (minRatio > newRatio) { // Aspect ratio is dominated by table width. - setSceneRect(0, 0, minWidth, sceneRect().height()); + newWidth = minWidth; } else { // Aspect ratio is dominated by window dimensions. - setSceneRect(0, 0, newRatio * sceneRect().height(), sceneRect().height()); + newWidth = newRatio * sceneRect().height(); } - - for (int i = 0; i < players.size(); ++i) - players[i]->processSceneSizeChange(sceneRect().size() - QSizeF(phasesToolbar->getWidth(), 0)); + setSceneRect(0, 0, newWidth, sceneRect().height()); + + qreal extraWidthPerColumn = (newWidth - minWidth) / playersByColumn.size(); + for (int col = 0; col < playersByColumn.size(); ++col) + for (int row = 0; row < playersByColumn[col].size(); ++row) + playersByColumn[col][row]->processSceneSizeChange(minWidthByColumn[col] + extraWidthPerColumn); } void GameScene::updateHover(const QPointF &scenePos) diff --git a/cockatrice/src/gamescene.h b/cockatrice/src/gamescene.h index eee167be5..7b93a35f7 100644 --- a/cockatrice/src/gamescene.h +++ b/cockatrice/src/gamescene.h @@ -22,7 +22,7 @@ private: PhasesToolbar *phasesToolbar; QList players; - QRectF playersRect; + QList > playersByColumn; QList views; QSize viewSize; QPointer hoveredCard; @@ -33,7 +33,6 @@ public: GameScene(PhasesToolbar *_phasesToolbar, QObject *parent = 0); ~GameScene(); void retranslateUi(); - const QRectF &getPlayersRect() const { return playersRect; } void processViewSizeChange(const QSize &newSize); void startRubberBand(const QPointF &selectionOrigin); diff --git a/cockatrice/src/gameselector.cpp b/cockatrice/src/gameselector.cpp new file mode 100644 index 000000000..1feb63d07 --- /dev/null +++ b/cockatrice/src/gameselector.cpp @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dlg_creategame.h" +#include "abstractclient.h" +#include "protocol_items.h" +#include "gameselector.h" +#include "gamesmodel.h" + +GameSelector::GameSelector(AbstractClient *_client, TabRoom *_room, const QMap &_rooms, const QMap &_gameTypes, QWidget *parent) + : QGroupBox(parent), client(_client), room(_room) +{ + gameListView = new QTreeView; + gameListModel = new GamesModel(_rooms, _gameTypes, this); + gameListProxyModel = new GamesProxyModel(this); + gameListProxyModel->setSourceModel(gameListModel); + gameListProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + gameListView->setModel(gameListProxyModel); + gameListView->setSortingEnabled(true); + gameListView->setAlternatingRowColors(true); + if (_room) + gameListView->header()->hideSection(0); + gameListView->header()->setResizeMode(1, QHeaderView::ResizeToContents); + + showFullGamesCheckBox = new QCheckBox; + showRunningGamesCheckBox = new QCheckBox; + + QVBoxLayout *filterLayout = new QVBoxLayout; + filterLayout->addWidget(showFullGamesCheckBox); + filterLayout->addWidget(showRunningGamesCheckBox); + + if (room) + createButton = new QPushButton; + else + createButton = 0; + joinButton = new QPushButton; + spectateButton = new QPushButton; + + QHBoxLayout *buttonLayout = new QHBoxLayout; + if (room) + buttonLayout->addWidget(createButton); + buttonLayout->addWidget(joinButton); + buttonLayout->addWidget(spectateButton); + buttonLayout->setAlignment(Qt::AlignTop); + + QHBoxLayout *hbox = new QHBoxLayout; + hbox->addLayout(filterLayout); + hbox->addStretch(); + hbox->addLayout(buttonLayout); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(gameListView); + mainLayout->addLayout(hbox); + + retranslateUi(); + setLayout(mainLayout); + + setMinimumWidth((qreal) (gameListView->columnWidth(0) * gameListModel->columnCount()) / 1.5); + setMinimumHeight(200); + + connect(showFullGamesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(showFullGamesChanged(int))); + connect(showRunningGamesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(showRunningGamesChanged(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::showRunningGamesChanged(int state) +{ + gameListProxyModel->setRunningGamesVisible(state); +} + +void GameSelector::actCreate() +{ + DlgCreateGame dlg(client, room->getRoomId(), room->getGameTypes(), this); + dlg.exec(); +} + +void GameSelector::checkResponse(ResponseCode response) +{ + if (createButton) + createButton->setEnabled(true); + joinButton->setEnabled(true); + spectateButton->setEnabled(true); + + switch (response) { + case RespNotInRoom: QMessageBox::critical(this, tr("Error"), tr("Please join the appropriate room first.")); break; + 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; + case RespUserLevelTooLow: QMessageBox::critical(this, tr("Error"), tr("This game is only open to registered users.")); break; + case RespOnlyBuddies: QMessageBox::critical(this, tr("Error"), tr("This game is only open to its creator's buddies.")); break; + case RespInIgnoreList: QMessageBox::critical(this, tr("Error"), tr("You are being ignored by the creator of this game.")); 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->getRoomId(), game->getGameId(), password, spectator); + connect(commandJoinGame, SIGNAL(finished(ResponseCode)), this, SLOT(checkResponse(ResponseCode))); + client->sendCommand(commandJoinGame); + + if (createButton) + createButton->setEnabled(false); + joinButton->setEnabled(false); + spectateButton->setEnabled(false); +} + +void GameSelector::retranslateUi() +{ + setTitle(tr("Games")); + showFullGamesCheckBox->setText(tr("Show &full games")); + showRunningGamesCheckBox->setText(tr("Show &running games")); + if (createButton) + 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); +} + diff --git a/cockatrice/src/gameselector.h b/cockatrice/src/gameselector.h new file mode 100644 index 000000000..cf603b336 --- /dev/null +++ b/cockatrice/src/gameselector.h @@ -0,0 +1,42 @@ +#ifndef GAMESELECTOR_H +#define GAMESELECTOR_H + +#include +#include "protocol_datastructures.h" +#include "tab_room.h" +#include "gametypemap.h" + +class QTreeView; +class GamesModel; +class GamesProxyModel; +class QPushButton; +class QCheckBox; +class AbstractClient; +class TabRoom; + +class GameSelector : public QGroupBox { + Q_OBJECT +private slots: + void showFullGamesChanged(int state); + void showRunningGamesChanged(int state); + void actCreate(); + void actJoin(); + void checkResponse(ResponseCode response); +signals: + void gameJoined(int gameId); +private: + AbstractClient *client; + TabRoom *room; + + QTreeView *gameListView; + GamesModel *gameListModel; + GamesProxyModel *gameListProxyModel; + QPushButton *createButton, *joinButton, *spectateButton; + QCheckBox *showFullGamesCheckBox, *showRunningGamesCheckBox; +public: + GameSelector(AbstractClient *_client, TabRoom *_room, const QMap &_rooms, const QMap &_gameTypes, QWidget *parent = 0); + void retranslateUi(); + void processGameInfo(ServerInfo_Game *info); +}; + +#endif \ No newline at end of file diff --git a/cockatrice/src/gamesmodel.cpp b/cockatrice/src/gamesmodel.cpp index 700877f2f..fc8e7d555 100644 --- a/cockatrice/src/gamesmodel.cpp +++ b/cockatrice/src/gamesmodel.cpp @@ -1,8 +1,8 @@ #include "gamesmodel.h" #include "protocol_datastructures.h" -GamesModel::GamesModel(const QMap &_gameTypes, QObject *parent) - : QAbstractTableModel(parent), gameTypes(_gameTypes) +GamesModel::GamesModel(const QMap &_rooms, const QMap &_gameTypes, QObject *parent) + : QAbstractTableModel(parent), rooms(_rooms), gameTypes(_gameTypes) { } @@ -30,17 +30,19 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const ServerInfo_Game *g = gameList[index.row()]; switch (index.column()) { - case 0: return g->getDescription(); - case 1: return g->getCreatorInfo()->getName(); - case 2: { + case 0: return rooms.value(g->getRoomId()); + case 1: return g->getDescription(); + case 2: return g->getCreatorInfo()->getName(); + case 3: { QStringList result; QList gameTypeList = g->getGameTypes(); + GameTypeMap gameTypeMap = gameTypes.value(g->getRoomId()); for (int i = 0; i < gameTypeList.size(); ++i) - result.append(gameTypes.value(gameTypeList[i]->getData())); + result.append(gameTypeMap.value(gameTypeList[i]->getData())); return result.join(", "); } - case 3: return g->getHasPassword() ? (g->getSpectatorsNeedPassword() ? tr("yes") : tr("yes, free for spectators")) : tr("no"); - case 4: { + case 4: return g->getHasPassword() ? (g->getSpectatorsNeedPassword() ? tr("yes") : tr("yes, free for spectators")) : tr("no"); + case 5: { QStringList result; if (g->getOnlyBuddies()) result.append(tr("buddies only")); @@ -48,8 +50,8 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const result.append(tr("reg. users only")); return result.join(", "); } - case 5: return QString("%1/%2").arg(g->getPlayerCount()).arg(g->getMaxPlayers()); - case 6: return g->getSpectatorsAllowed() ? QVariant(g->getSpectatorCount()) : QVariant(tr("not allowed")); + case 6: return QString("%1/%2").arg(g->getPlayerCount()).arg(g->getMaxPlayers()); + case 7: return g->getSpectatorsAllowed() ? QVariant(g->getSpectatorCount()) : QVariant(tr("not allowed")); default: return QVariant(); } } @@ -59,13 +61,14 @@ QVariant GamesModel::headerData(int section, Qt::Orientation orientation, int ro if ((role != Qt::DisplayRole) || (orientation != Qt::Horizontal)) return QVariant(); switch (section) { - case 0: return tr("Description"); - case 1: return tr("Creator"); - case 2: return tr("Game type"); - case 3: return tr("Password"); - case 4: return tr("Restrictions"); - case 5: return tr("Players"); - case 6: return tr("Spectators"); + case 0: return tr("Room"); + case 1: return tr("Description"); + case 2: return tr("Creator"); + case 3: return tr("Game type"); + case 4: return tr("Password"); + case 5: return tr("Restrictions"); + case 6: return tr("Players"); + case 7: return tr("Spectators"); default: return QVariant(); } } @@ -82,7 +85,7 @@ void GamesModel::updateGameList(ServerInfo_Game *_game) for (int i = 0; i < oldGameTypeList.size(); ++i) gameTypeList.append(new GameTypeId(oldGameTypeList[i]->getData())); - ServerInfo_Game *game = new ServerInfo_Game(_game->getGameId(), _game->getDescription(), _game->getHasPassword(), _game->getPlayerCount(), _game->getMaxPlayers(), gameTypeList, new ServerInfo_User(_game->getCreatorInfo()), _game->getOnlyBuddies(), _game->getOnlyRegistered(), _game->getSpectatorsAllowed(), _game->getSpectatorsNeedPassword(), _game->getSpectatorCount()); + ServerInfo_Game *game = new ServerInfo_Game(_game->getRoomId(), _game->getGameId(), _game->getDescription(), _game->getHasPassword(), _game->getPlayerCount(), _game->getMaxPlayers(), _game->getStarted(), gameTypeList, new ServerInfo_User(_game->getCreatorInfo()), _game->getOnlyBuddies(), _game->getOnlyRegistered(), _game->getSpectatorsAllowed(), _game->getSpectatorsNeedPassword(), _game->getSpectatorCount()); for (int i = 0; i < gameList.size(); i++) if (gameList[i]->getGameId() == game->getGameId()) { if (game->getPlayerCount() == 0) { @@ -92,7 +95,7 @@ void GamesModel::updateGameList(ServerInfo_Game *_game) } else { delete gameList[i]; gameList[i] = game; - emit dataChanged(index(i, 0), index(i, 4)); + emit dataChanged(index(i, 0), index(i, 7)); } return; } @@ -115,17 +118,22 @@ void GamesProxyModel::setFullGamesVisible(bool _fullGamesVisible) invalidateFilter(); } +void GamesProxyModel::setRunningGamesVisible(bool _runningGamesVisible) +{ + runningGamesVisible = _runningGamesVisible; + invalidateFilter(); +} + bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &/*sourceParent*/) const { - if (fullGamesVisible) - return true; - GamesModel *model = qobject_cast(sourceModel()); if (!model) return false; ServerInfo_Game *game = model->getGame(sourceRow); - if (game->getPlayerCount() == game->getMaxPlayers()) + if ((game->getPlayerCount() == game->getMaxPlayers()) && !fullGamesVisible) + return false; + if (game->getStarted() && !runningGamesVisible) return false; return true; diff --git a/cockatrice/src/gamesmodel.h b/cockatrice/src/gamesmodel.h index a7f4fe68d..8461faf66 100644 --- a/cockatrice/src/gamesmodel.h +++ b/cockatrice/src/gamesmodel.h @@ -4,6 +4,7 @@ #include #include #include +#include "gametypemap.h" class ServerInfo_Game; @@ -11,12 +12,13 @@ class GamesModel : public QAbstractTableModel { Q_OBJECT private: QList gameList; - QMap gameTypes; + QMap rooms; + QMap gameTypes; public: - GamesModel(const QMap &_gameTypes, QObject *parent = 0); + GamesModel(const QMap &_rooms, const QMap &_gameTypes, QObject *parent = 0); ~GamesModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const { return parent.isValid() ? 0 : gameList.size(); } - int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const { return 7; } + int columnCount(const QModelIndex &/*parent*/ = QModelIndex()) const { return 8; } QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; @@ -28,9 +30,11 @@ class GamesProxyModel : public QSortFilterProxyModel { Q_OBJECT private: bool fullGamesVisible; + bool runningGamesVisible; public: GamesProxyModel(QObject *parent = 0); void setFullGamesVisible(bool _fullGamesVisible); + void setRunningGamesVisible(bool _runningGamesVisible); protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; }; diff --git a/cockatrice/src/gametypemap.h b/cockatrice/src/gametypemap.h new file mode 100644 index 000000000..fce161752 --- /dev/null +++ b/cockatrice/src/gametypemap.h @@ -0,0 +1,8 @@ +#ifndef GAMETYPEMAP_H +#define GAMETYPEMAP_H + +#include + +typedef QMap GameTypeMap; + +#endif \ No newline at end of file diff --git a/cockatrice/src/localserver.cpp b/cockatrice/src/localserver.cpp index 4cadbdf31..2793a28e2 100644 --- a/cockatrice/src/localserver.cpp +++ b/cockatrice/src/localserver.cpp @@ -10,6 +10,7 @@ LocalServer::LocalServer(QObject *parent) LocalServer::~LocalServer() { + prepareDestroy(); } LocalServerInterface *LocalServer::newConnection() diff --git a/cockatrice/src/localserver.h b/cockatrice/src/localserver.h index b68e4f25a..cf24b4385 100644 --- a/cockatrice/src/localserver.h +++ b/cockatrice/src/localserver.h @@ -11,11 +11,12 @@ class LocalServer : public Server public: LocalServer(QObject *parent = 0); ~LocalServer(); - AuthenticationResult checkUserPassword(const QString & /*user*/, const QString & /*password*/) { return UnknownUser; } + AuthenticationResult checkUserPassword(Server_ProtocolHandler * /*handler*/, const QString & /*user*/, const QString & /*password*/) { return UnknownUser; } QString getLoginMessage() const { return QString(); } bool getGameShouldPing() const { return false; } int getMaxGameInactivityTime() const { return 9999999; } int getMaxPlayerInactivityTime() const { return 9999999; } + bool getThreaded() const { return false; } LocalServerInterface *newConnection(); protected: diff --git a/cockatrice/src/localserverinterface.cpp b/cockatrice/src/localserverinterface.cpp index b4e0918d6..79734c40c 100644 --- a/cockatrice/src/localserverinterface.cpp +++ b/cockatrice/src/localserverinterface.cpp @@ -9,6 +9,7 @@ LocalServerInterface::LocalServerInterface(LocalServer *_server) LocalServerInterface::~LocalServerInterface() { + prepareDestroy(); } void LocalServerInterface::sendProtocolItem(ProtocolItem *item, bool deleteItem) diff --git a/cockatrice/src/localserverinterface.h b/cockatrice/src/localserverinterface.h index fc23b1b57..1db974129 100644 --- a/cockatrice/src/localserverinterface.h +++ b/cockatrice/src/localserverinterface.h @@ -18,14 +18,16 @@ 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; } ResponseCode cmdBanFromServer(Command_BanFromServer * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } + ResponseCode cmdShutdownServer(Command_ShutdownServer * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } + ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage * /*cmd*/, CommandContainer * /*cont*/) { return RespFunctionNotAllowed; } +protected: + bool getCompressionSupport() const { return false; } public: LocalServerInterface(LocalServer *_server); ~LocalServerInterface(); void sendProtocolItem(ProtocolItem *item, bool deleteItem = true); - signals: void itemToClient(ProtocolItem *item); public slots: diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index 5b872b69e..8ce2581b7 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -36,6 +36,7 @@ #include "settingscache.h" #include "pixmapgenerator.h" #include "rng_sfmt.h" +#include "soundengine.h" //Q_IMPORT_PLUGIN(qjpeg) @@ -43,6 +44,7 @@ CardDatabase *db; QTranslator *translator, *qtTranslator; SettingsCache *settingsCache; RNG_Abstract *rng; +SoundEngine *soundEngine; void myMessageOutput(QtMsgType /*type*/, const char *msg) { @@ -114,6 +116,8 @@ int main(int argc, char *argv[]) } if (startMainProgram) { + soundEngine = new SoundEngine; + MainWindow ui; qDebug("main(): MainWindow constructor finished"); diff --git a/cockatrice/src/main.h b/cockatrice/src/main.h index b1f30bdb8..3e7ad1ead 100644 --- a/cockatrice/src/main.h +++ b/cockatrice/src/main.h @@ -3,12 +3,13 @@ class CardDatabase; class QTranslator; +class SoundEngine; extern CardDatabase *db; extern QTranslator *translator; const QString translationPrefix = "cockatrice"; -const QString versionString = "0.20110303"; +const QString versionString = "0.20110625"; void installNewTranslator(); diff --git a/cockatrice/src/messagelogwidget.cpp b/cockatrice/src/messagelogwidget.cpp index b2907e8c5..98b61c907 100644 --- a/cockatrice/src/messagelogwidget.cpp +++ b/cockatrice/src/messagelogwidget.cpp @@ -1,11 +1,9 @@ #include "messagelogwidget.h" #include "player.h" #include "cardzone.h" -#include "cardinfowidget.h" #include "protocol_items.h" -#include -#include -#include +#include "soundengine.h" +#include QString MessageLogWidget::sanitizeHtml(QString dirty) const { @@ -15,133 +13,158 @@ QString MessageLogWidget::sanitizeHtml(QString dirty) const .replace(">", ">"); } -void MessageLogWidget::logConnecting(QString hostname) +bool MessageLogWidget::isFemale(Player *player) const { - append(tr("Connecting to %1...").arg(sanitizeHtml(hostname))); -} - -void MessageLogWidget::logConnected() -{ - append(tr("Connected.")); -} - -void MessageLogWidget::logDisconnected() -{ - append(tr("Disconnected from server.")); -} - -void MessageLogWidget::logSocketError(const QString &errorString) -{ - append(sanitizeHtml(errorString)); -} - -void MessageLogWidget::logServerError(ResponseCode response) -{ - switch (response) { - case RespWrongPassword: append(tr("Invalid password.")); break; - default: ; - } -} - -void MessageLogWidget::logProtocolVersionMismatch(int clientVersion, int serverVersion) -{ - append(tr("Protocol version mismatch. Client: %1, Server: %2").arg(clientVersion).arg(serverVersion)); -} - -void MessageLogWidget::logProtocolError() -{ - append(tr("Protocol error.")); + return player->getUserInfo()->getGender() == ServerInfo_User::Female; } void MessageLogWidget::logGameJoined(int gameId) { - append(tr("You have joined game #%1.").arg(gameId)); + if (female) + appendHtml(tr("You have joined game #%1.", "female").arg(gameId)); + else + appendHtml(tr("You have joined game #%1.", "male").arg(gameId)); } void MessageLogWidget::logJoin(Player *player) { - append(tr("%1 has joined the game.").arg(sanitizeHtml(player->getName()))); + soundEngine->cuckoo(); + if (isFemale(player)) + appendHtml(tr("%1 has joined the game.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 has joined the game.", "male").arg(sanitizeHtml(player->getName()))); } void MessageLogWidget::logLeave(Player *player) { - append(tr("%1 has left the game.").arg(sanitizeHtml(player->getName()))); + if (isFemale(player)) + appendHtml(tr("%1 has left the game.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 has left the game.", "male").arg(sanitizeHtml(player->getName()))); } void MessageLogWidget::logGameClosed() { - append(tr("The game has been closed.")); + appendHtml(tr("The game has been closed.")); } void MessageLogWidget::logJoinSpectator(QString name) { - append(tr("%1 is now watching the game.").arg(sanitizeHtml(name))); + appendHtml(tr("%1 is now watching the game.").arg(sanitizeHtml(name))); } void MessageLogWidget::logLeaveSpectator(QString name) { - append(tr("%1 is not watching the game any more.").arg(sanitizeHtml(name))); + appendHtml(tr("%1 is not watching the game any more.").arg(sanitizeHtml(name))); } void MessageLogWidget::logDeckSelect(Player *player, int deckId) { - if (deckId == -1) - append(tr("%1 has loaded a local deck.").arg(sanitizeHtml(player->getName()))); - else - append(tr("%1 has loaded deck #%2.").arg(sanitizeHtml(player->getName())).arg(deckId)); + if (deckId == -1) { + if (isFemale(player)) + appendHtml(tr("%1 has loaded a local deck.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 has loaded a local deck.", "male").arg(sanitizeHtml(player->getName()))); + } else { + if (isFemale(player)) + appendHtml(tr("%1 has loaded deck #%2.", "female").arg(sanitizeHtml(player->getName())).arg(deckId)); + else + appendHtml(tr("%1 has loaded deck #%2.", "male").arg(sanitizeHtml(player->getName())).arg(deckId)); + } } void MessageLogWidget::logReadyStart(Player *player) { - append(tr("%1 is ready to start the game.").arg(sanitizeHtml(player->getName()))); + if (isFemale(player)) + appendHtml(tr("%1 is ready to start the game.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 is ready to start the game.", "male").arg(sanitizeHtml(player->getName()))); } void MessageLogWidget::logNotReadyStart(Player *player) { - append(tr("%1 is not ready to start the game any more.").arg(sanitizeHtml(player->getName()))); + if (isFemale(player)) + appendHtml(tr("%1 is not ready to start the game any more.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 is not ready to start the game any more.", "male").arg(sanitizeHtml(player->getName()))); } void MessageLogWidget::logConcede(Player *player) { - append(tr("%1 has conceded the game.").arg(sanitizeHtml(player->getName()))); + if (isFemale(player)) + appendHtml(tr("%1 has conceded the game.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 has conceded the game.", "male").arg(sanitizeHtml(player->getName()))); } void MessageLogWidget::logGameStart() { - append(tr("The game has started.")); + appendHtml(tr("The game has started.")); +} + +void MessageLogWidget::logConnectionStateChanged(Player *player, bool connectionState) +{ + if (connectionState) { + if (isFemale(player)) + appendHtml(tr("%1 has restored connection to the game.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 has restored connection to the game.", "male").arg(sanitizeHtml(player->getName()))); + } else { + if (isFemale(player)) + appendHtml(tr("%1 has lost connection to the game.", "female").arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 has lost connection to the game.", "male").arg(sanitizeHtml(player->getName()))); + } } void MessageLogWidget::logSay(Player *player, QString message) { - append(QString("getLocal() ? "red" : "#0000fe") + QString("\">%1: %2").arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(message))); + appendMessage(player->getName(), message, QColor(), true); } void MessageLogWidget::logSpectatorSay(QString spectatorName, QString message) { - append(QString("%1: %2").arg(sanitizeHtml(spectatorName)).arg(sanitizeHtml(message))); + appendMessage(spectatorName, message, QColor(), false); } -void MessageLogWidget::logShuffle(Player *player) +void MessageLogWidget::logShuffle(Player *player, CardZone *zone) { - append(tr("%1 shuffles his library.").arg(sanitizeHtml(player->getName()))); + soundEngine->shuffle(); + if (currentContext != MessageContext_Mulligan) { + if (isFemale(player)) + appendHtml(tr("%1 shuffles %2.", "female").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative))); + else + appendHtml(tr("%1 shuffles %2.", "male").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative))); + } } void MessageLogWidget::logRollDie(Player *player, int sides, int roll) { - append(tr("%1 rolls a %2 with a %3-sided die.").arg(sanitizeHtml(player->getName())).arg(roll).arg(sides)); + if (isFemale(player)) + appendHtml(tr("%1 rolls a %2 with a %3-sided die.", "female").arg(sanitizeHtml(player->getName())).arg(roll).arg(sides)); + else + appendHtml(tr("%1 rolls a %2 with a %3-sided die.", "male").arg(sanitizeHtml(player->getName())).arg(roll).arg(sides)); } void MessageLogWidget::logDrawCards(Player *player, int number) { - append(tr("%1 draws %n card(s).", "", number).arg(sanitizeHtml(player->getName()))); + if (currentContext == MessageContext_Mulligan) + mulliganPlayer = player; + else { + soundEngine->draw(); + if (isFemale(player)) + appendHtml(tr("%1 draws %n card(s).", "female", number).arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 draws %n card(s).", "male", number).arg(sanitizeHtml(player->getName()))); + } } void MessageLogWidget::logUndoDraw(Player *player, QString cardName) { if (cardName.isEmpty()) - append(tr("%1 undoes his last draw.").arg(sanitizeHtml(player->getName()))); + appendHtml((isFemale(player) ? tr("%1 undoes her last draw.") : tr("%1 undoes his last draw.")).arg(sanitizeHtml(player->getName()))); else - append(tr("%1 undoes his last draw (%2).").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); + appendHtml((isFemale(player) ? tr("%1 undoes her last draw (%2).") : tr("%1 undoes his last draw (%2).")).arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); } QPair MessageLogWidget::getFromStr(CardZone *zone, QString cardName, int position) const @@ -161,16 +184,16 @@ QPair MessageLogWidget::getFromStr(CardZone *zone, QString car else if (startName == "deck") { if (position == zone->getCards().size() - 1) { if (cardName.isEmpty()) { - cardName = tr("the bottom card of his library"); + cardName = isFemale(zone->getPlayer()) ? tr("the bottom card of her library") : tr("the bottom card of his library"); cardNameContainsStartZone = true; } else - fromStr = tr(" from the bottom of his library"); + fromStr = isFemale(zone->getPlayer()) ? tr(" from the bottom of her library") : tr(" from the bottom of his library"); } else if (position == 0) { if (cardName.isEmpty()) { - cardName = tr("the top card of his library"); + cardName = isFemale(zone->getPlayer()) ? tr("the top card of her library") : tr("the top card of his library"); cardNameContainsStartZone = true; } else - fromStr = tr(" from the top of his library"); + fromStr = isFemale(zone->getPlayer()) ? tr(" from the top of her library") : tr(" from the top of his library"); } else fromStr = tr(" from library"); } else if (startName == "sb") @@ -206,12 +229,13 @@ void MessageLogWidget::doMoveCard(LogMoveCard &attributes) cardStr = QString("%1").arg(sanitizeHtml(cardName)); if (attributes.startZone->getPlayer() != attributes.targetZone->getPlayer()) { - append(tr("%1 gives %2 control over %3.").arg(sanitizeHtml(attributes.player->getName())).arg(sanitizeHtml(attributes.targetZone->getPlayer()->getName())).arg(cardStr)); + appendHtml(tr("%1 gives %2 control over %3.").arg(sanitizeHtml(attributes.player->getName())).arg(sanitizeHtml(attributes.targetZone->getPlayer()->getName())).arg(cardStr)); return; } QString finalStr; if (targetName == "table") { + soundEngine->playCard(); if (moveCardTapped.value(attributes.card)) finalStr = tr("%1 puts %2 into play tapped%3."); else @@ -224,19 +248,21 @@ void MessageLogWidget::doMoveCard(LogMoveCard &attributes) finalStr = tr("%1 moves %2%3 to hand."); else if (targetName == "deck") { if (attributes.newX == -1) - finalStr = tr("%1 puts %2%3 into his library."); + finalStr = isFemale(attributes.targetZone->getPlayer()) ? tr("%1 puts %2%3 into her library.") : tr("%1 puts %2%3 into his library."); else if (attributes.newX == attributes.targetZone->getCards().size() - 1) - finalStr = tr("%1 puts %2%3 on bottom of his library."); + finalStr = isFemale(attributes.targetZone->getPlayer()) ? tr("%1 puts %2%3 on bottom of her library.") : tr("%1 puts %2%3 on bottom of his library."); else if (attributes.newX == 0) - finalStr = tr("%1 puts %2%3 on top of his library."); + finalStr = isFemale(attributes.targetZone->getPlayer()) ? tr("%1 puts %2%3 on top of her library.") : tr("%1 puts %2%3 on top of his library."); else - finalStr = tr("%1 puts %2%3 into his library at position %4."); + finalStr = isFemale(attributes.targetZone->getPlayer()) ? tr("%1 puts %2%3 into her library at position %4.") : tr("%1 puts %2%3 into his library at position %4."); } else if (targetName == "sb") finalStr = tr("%1 moves %2%3 to sideboard."); - else if (targetName == "stack") + else if (targetName == "stack") { + soundEngine->playCard(); finalStr = tr("%1 plays %2%3."); + } - append(finalStr.arg(sanitizeHtml(attributes.player->getName())).arg(cardStr).arg(fromStr).arg(attributes.newX)); + appendHtml(finalStr.arg(sanitizeHtml(attributes.player->getName())).arg(cardStr).arg(fromStr).arg(attributes.newX)); } void MessageLogWidget::logMoveCard(Player *player, CardItem *card, CardZone *startZone, int oldX, CardZone *targetZone, int newX) @@ -244,55 +270,211 @@ void MessageLogWidget::logMoveCard(Player *player, CardItem *card, CardZone *sta LogMoveCard attributes = {player, card, card->getName(), startZone, oldX, targetZone, newX}; if (currentContext == MessageContext_MoveCard) moveCardQueue.append(attributes); + else if (currentContext == MessageContext_Mulligan) + mulliganPlayer = player; else doMoveCard(attributes); } +void MessageLogWidget::logMulligan(Player *player, int number) +{ + if (!player) + return; + + if (number > -1) { + if (isFemale(player)) + appendHtml(tr("%1 takes a mulligan to %n.", "female", number).arg(sanitizeHtml(player->getName()))); + else + appendHtml(tr("%1 takes a mulligan to %n.", "male", number).arg(sanitizeHtml(player->getName()))); + } else + appendHtml((isFemale(player) ? tr("%1 draws her initial hand.") : tr("%1 draws his initial hand.")).arg(sanitizeHtml(player->getName()))); +} + void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown) { - if (faceDown) - append(tr("%1 flips %2 face-down.").arg(sanitizeHtml(player->getName())).arg(cardName)); - else - append(tr("%1 flips %2 face-up.").arg(sanitizeHtml(player->getName())).arg(cardName)); + if (faceDown) { + if (isFemale(player)) + appendHtml(tr("%1 flips %2 face-down.", "female").arg(sanitizeHtml(player->getName())).arg(cardName)); + else + appendHtml(tr("%1 flips %2 face-down.", "male").arg(sanitizeHtml(player->getName())).arg(cardName)); + } else { + if (isFemale(player)) + appendHtml(tr("%1 flips %2 face-up.", "female").arg(sanitizeHtml(player->getName())).arg(cardName)); + else + appendHtml(tr("%1 flips %2 face-up.", "male").arg(sanitizeHtml(player->getName())).arg(cardName)); + } } void MessageLogWidget::logDestroyCard(Player *player, QString cardName) { - append(tr("%1 destroys %2.").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); + if (isFemale(player)) + appendHtml(tr("%1 destroys %2.", "female").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); + else + appendHtml(tr("%1 destroys %2.", "male").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); } void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName) { - append(tr("%1 attaches %2 to %3's %4.").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName))).arg(sanitizeHtml(targetPlayer->getName())).arg(QString("%1").arg(sanitizeHtml(targetCardName)))); + QString str; + if (isFemale(player)) { + if (isFemale(targetPlayer)) + str = tr("%1 attaches %2 to %3's %4.", "p1 female, p2 female"); + else + str = tr("%1 attaches %2 to %3's %4.", "p1 female, p2 male"); + } else { + if (isFemale(targetPlayer)) + str = tr("%1 attaches %2 to %3's %4.", "p1 male, p2 female"); + else + str = tr("%1 attaches %2 to %3's %4.", "p1 male, p2 male"); + } + + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName))).arg(sanitizeHtml(targetPlayer->getName())).arg(QString("%1").arg(sanitizeHtml(targetCardName)))); } void MessageLogWidget::logUnattachCard(Player *player, QString cardName) { - append(tr("%1 unattaches %2.").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); + if (isFemale(player)) + appendHtml(tr("%1 unattaches %2.", "female").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); + else + appendHtml(tr("%1 unattaches %2.", "male").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName)))); } void MessageLogWidget::logCreateToken(Player *player, QString cardName, QString pt) { - append(tr("%1 creates token: %2%3.").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName))).arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt)))); + if (isFemale(player)) + appendHtml(tr("%1 creates token: %2%3.", "female").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName))).arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt)))); + else + appendHtml(tr("%1 creates token: %2%3.", "male").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(cardName))).arg(pt.isEmpty() ? QString() : QString(" (%1)").arg(sanitizeHtml(pt)))); } void MessageLogWidget::logCreateArrow(Player *player, Player *startPlayer, QString startCard, Player *targetPlayer, QString targetCard, bool playerTarget) { - if (playerTarget) - append(tr("%1 points from %2's %3 to %4.") - .arg(sanitizeHtml(player->getName())) - .arg(sanitizeHtml(startPlayer->getName())) - .arg(sanitizeHtml(startCard)) - .arg(sanitizeHtml(targetPlayer->getName())) - ); - else - append(tr("%1 points from %2's %3 to %4's %5.") - .arg(sanitizeHtml(player->getName())) - .arg(sanitizeHtml(startPlayer->getName())) - .arg(sanitizeHtml(startCard)) - .arg(sanitizeHtml(targetPlayer->getName())) - .arg(sanitizeHtml(targetCard)) - ); + startCard = QString("%1").arg(sanitizeHtml(startCard)); + targetCard = QString("%1").arg(sanitizeHtml(targetCard)); + QString str; + if (playerTarget) { + if ((player == startPlayer) && (player == targetPlayer)) { + if (isFemale(player)) + str = tr("%1 points from her %2 to herself.", "female"); + else + str = tr("%1 points from his %2 to himself.", "male"); + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(startCard)); + } else if (player == startPlayer) { + if (isFemale(player)) { + if (isFemale(targetPlayer)) + str = tr("%1 points from her %2 to %3.", "p1 female, p2 female"); + else + str = tr("%1 points from her %2 to %3.", "p1 female, p2 male"); + } else { + if (isFemale(targetPlayer)) + str = tr("%1 points from his %2 to %3.", "p1 male, p2 female"); + else + str = tr("%1 points from his %2 to %3.", "p1 male, p2 male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(startCard).arg(sanitizeHtml(targetPlayer->getName()))); + } else if (player == targetPlayer) { + if (isFemale(player)) { + if (isFemale(startPlayer)) + str = tr("%1 points from %2's %3 to herself.", "card owner female, target female"); + else + str = tr("%1 points from %2's %3 to herself.", "card owner male, target female"); + } else { + if (isFemale(startPlayer)) + str = tr("%1 points from %2's %3 to himself.", "card owner female, target male"); + else + str = tr("%1 points from %2's %3 to himself.", "card owner male, target male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(startPlayer->getName())).arg(startCard)); + } else { + if (isFemale(player)) { + if (isFemale(startPlayer)) { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4.", "p1 female, p2 female, p3 female"); + else + str = tr("%1 points from %2's %3 to %4.", "p1 female, p2 female, p3 male"); + } else { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4.", "p1 female, p2 male, p3 female"); + else + str = tr("%1 points from %2's %3 to %4.", "p1 female, p2 male, p3 male"); + } + } else { + if (isFemale(startPlayer)) { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4.", "p1 male, p2 female, p3 female"); + else + str = tr("%1 points from %2's %3 to %4.", "p1 male, p2 female, p3 male"); + } else { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4.", "p1 male, p2 male, p3 female"); + else + str = tr("%1 points from %2's %3 to %4.", "p1 male, p2 male, p3 male"); + } + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(startPlayer->getName())).arg(startCard).arg(sanitizeHtml(targetPlayer->getName()))); + } + } else { + if ((player == startPlayer) && (player == targetPlayer)) { + if (isFemale(player)) + str = tr("%1 points from her %2 to her %3.", "female"); + else + str = tr("%1 points from his %2 to his %3.", "male"); + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(startCard).arg(targetCard)); + } else if (player == startPlayer) { + if (isFemale(player)) { + if (isFemale(targetPlayer)) + str = tr("%1 points from her %2 to %3's %4.", "p1 female, p2 female"); + else + str = tr("%1 points from her %2 to %3's %4.", "p1 female, p2 male"); + } else { + if (isFemale(targetPlayer)) + str = tr("%1 points from his %2 to %3's %4.", "p1 male, p2 female"); + else + str = tr("%1 points from his %2 to %3's %4.", "p1 male, p2 male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(startCard).arg(sanitizeHtml(targetPlayer->getName())).arg(targetCard)); + } else if (player == targetPlayer) { + if (isFemale(player)) { + if (isFemale(startPlayer)) + str = tr("%1 points from %2's %3 to her own %4.", "card owner female, target female"); + else + str = tr("%1 points from %2's %3 to her own %4.", "card owner male, target female"); + } else { + if (isFemale(startPlayer)) + str = tr("%1 points from %2's %3 to his own %4.", "card owner female, target male"); + else + str = tr("%1 points from %2's %3 to his own %4.", "card owner male, target male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(startPlayer->getName())).arg(startCard).arg(targetCard)); + } else { + if (isFemale(player)) { + if (isFemale(startPlayer)) { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4's %5.", "p1 female, p2 female, p3 female"); + else + str = tr("%1 points from %2's %3 to %4's %5.", "p1 female, p2 female, p3 male"); + } else { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4's %5.", "p1 female, p2 male, p3 female"); + else + str = tr("%1 points from %2's %3 to %4's %5.", "p1 female, p2 male, p3 male"); + } + } else { + if (isFemale(startPlayer)) { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4's %5.", "p1 male, p2 female, p3 female"); + else + str = tr("%1 points from %2's %3 to %4's %5.", "p1 male, p2 female, p3 male"); + } else { + if (isFemale(targetPlayer)) + str = tr("%1 points from %2's %3 to %4's %5.", "p1 male, p2 male, p3 female"); + else + str = tr("%1 points from %2's %3 to %4's %5.", "p1 male, p2 male, p3 male"); + } + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(sanitizeHtml(startPlayer->getName())).arg(startCard).arg(sanitizeHtml(targetPlayer->getName())).arg(targetCard)); + } + } } void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int counterId, int value, int oldValue) @@ -300,10 +482,17 @@ void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int c QString finalStr, colorStr; int delta = abs(oldValue - value); - if (value > oldValue) - finalStr = tr("%1 places %n %2 counter(s) on %3 (now %4).", "", delta); - else - finalStr = tr("%1 removes %n %2 counter(s) from %3 (now %4).", "", delta); + if (value > oldValue) { + if (isFemale(player)) + finalStr = tr("%1 places %n %2 counter(s) on %3 (now %4).", "female", delta); + else + finalStr = tr("%1 places %n %2 counter(s) on %3 (now %4).", "male", delta); + } else { + if (isFemale(player)) + finalStr = tr("%1 removes %n %2 counter(s) from %3 (now %4).", "female", delta); + else + finalStr = tr("%1 removes %n %2 counter(s) from %3 (now %4).", "male", delta); + } switch (counterId) { case 0: colorStr = tr("red", "", delta); break; @@ -312,63 +501,124 @@ void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int c default: ; } - append(finalStr.arg(sanitizeHtml(player->getName())).arg(colorStr).arg(QString("%1").arg(sanitizeHtml(cardName))).arg(value)); + appendHtml(finalStr.arg(sanitizeHtml(player->getName())).arg(colorStr).arg(QString("%1").arg(sanitizeHtml(cardName))).arg(value)); } void MessageLogWidget::logSetTapped(Player *player, CardItem *card, bool tapped) { + if (tapped) + soundEngine->tap(); + else + soundEngine->untap(); + if (currentContext == MessageContext_MoveCard) moveCardTapped.insert(card, tapped); else { - QString cardStr; - if (!card) - cardStr = tr("his permanents"); - else - cardStr = QString("%1").arg(sanitizeHtml(card->getName())); - append(tr("%1 %2 %3.").arg(sanitizeHtml(player->getName())).arg(tapped ? tr("taps") : tr("untaps")).arg(cardStr)); + QString str; + if (!card) { + if (isFemale(player)) { + if (tapped) + str = tr("%1 taps her permanents.", "female"); + else + str = tr("%1 untaps her permanents.", "female"); + } else { + if (tapped) + str = tr("%1 taps his permanents.", "male"); + else + str = tr("%1 untaps his permanents.", "male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName()))); + } else { + if (isFemale(player)) { + if (tapped) + str = tr("%1 taps %2.", "female"); + else + str = tr("%1 untaps %2.", "female"); + } else { + if (tapped) + str = tr("%1 taps %2.", "male"); + else + str = tr("%1 untaps %2.", "male"); + } + QString cardStr = QString("%1").arg(sanitizeHtml(card->getName())); + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(cardStr)); + } } } void MessageLogWidget::logSetCounter(Player *player, QString counterName, int value, int oldValue) { - append(tr("%1 sets counter %2 to %3 (%4%5).").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(counterName))).arg(QString("%1").arg(value)).arg(value > oldValue ? "+" : "").arg(value - oldValue)); + QString str; + if (isFemale(player)) + str = tr("%1 sets counter %2 to %3 (%4%5).", "female"); + else + str = tr("%1 sets counter %2 to %3 (%4%5).", "male"); + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(counterName))).arg(QString("%1").arg(value)).arg(value > oldValue ? "+" : "").arg(value - oldValue)); } void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool doesntUntap) { - QString finalStr; - if (doesntUntap) - finalStr = tr("%1 sets %2 to not untap normally."); - else - finalStr = tr("%1 sets %2 to untap normally."); - append(finalStr.arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(card->getName())))); + QString str; + if (doesntUntap) { + if (isFemale(player)) + str = tr("%1 sets %2 to not untap normally.", "female"); + else + str = tr("%1 sets %2 to not untap normally.", "male"); + } else { + if (isFemale(player)) + str = tr("%1 sets %2 to untap normally.", "female"); + else + str = tr("%1 sets %2 to untap normally.", "male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(card->getName())))); } void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT) { if (currentContext == MessageContext_MoveCard) moveCardPT.insert(card, newPT); - else - append(tr("%1 sets PT of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(card->getName()))).arg(QString("%1").arg(sanitizeHtml(newPT)))); + else { + QString str; + if (isFemale(player)) + str = tr("%1 sets PT of %2 to %3.", "female"); + else + str = tr("%1 sets PT of %2 to %3.", "male"); + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(card->getName()))).arg(QString("%1").arg(sanitizeHtml(newPT)))); + } } void MessageLogWidget::logSetAnnotation(Player *player, CardItem *card, QString newAnnotation) { - append(tr("%1 sets annotation of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(card->getName()))).arg(QString("%1").arg(sanitizeHtml(newAnnotation)))); + QString str; + if (isFemale(player)) + str = tr("%1 sets annotation of %2 to %3.", "female"); + else + str = tr("%1 sets annotation of %2 to %3.", "male"); + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(QString("%1").arg(sanitizeHtml(card->getName()))).arg(QString("%1").arg(sanitizeHtml(newAnnotation)))); } void MessageLogWidget::logDumpZone(Player *player, CardZone *zone, int numberCards) { - if (numberCards != -1) - append(tr("%1 is looking at the top %2 cards %3.").arg(sanitizeHtml(player->getName())).arg(numberCards).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseGenitive))); - else - append(tr("%1 is looking at %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseAccusative))); + if (numberCards != -1) { + if (isFemale(player)) + appendHtml(tr("%1 is looking at the top %2 cards %3.", "female").arg(sanitizeHtml(player->getName())).arg(numberCards).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseGenitive))); + else + appendHtml(tr("%1 is looking at the top %2 cards %3.", "male").arg(sanitizeHtml(player->getName())).arg(numberCards).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseGenitive))); + } else { + if (isFemale(player)) + appendHtml(tr("%1 is looking at %2.", "female").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseAccusative))); + else + appendHtml(tr("%1 is looking at %2.", "male").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(zone->getPlayer() == player, CaseAccusative))); + } } void MessageLogWidget::logStopDumpZone(Player *player, CardZone *zone) { QString zoneName = zone->getTranslatedName(zone->getPlayer() == player, CaseAccusative); - append(tr("%1 stops looking at %2.").arg(sanitizeHtml(player->getName())).arg(zoneName)); + if (isFemale(player)) + appendHtml(tr("%1 stops looking at %2.", "female").arg(sanitizeHtml(player->getName())).arg(zoneName)); + else + appendHtml(tr("%1 stops looking at %2.", "male").arg(sanitizeHtml(player->getName())).arg(zoneName)); } void MessageLogWidget::logRevealCards(Player *player, CardZone *zone, int cardId, QString cardName, Player *otherPlayer) @@ -389,33 +639,85 @@ void MessageLogWidget::logRevealCards(Player *player, CardZone *zone, int cardId else cardStr = QString("%1").arg(sanitizeHtml(cardName)); + QString str; if (cardId == -1) { - if (otherPlayer) - append(tr("%1 reveals %2 to %3.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)).arg(sanitizeHtml(otherPlayer->getName()))); - else - append(tr("%1 reveals %2.").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative))); + if (otherPlayer) { + if (isFemale(player)) { + if (isFemale(otherPlayer)) + str = tr("%1 reveals %2 to %3.", "p1 female, p2 female"); + else + str = tr("%1 reveals %2 to %3.", "p1 female, p2 male"); + } else { + if (isFemale(otherPlayer)) + str = tr("%1 reveals %2 to %3.", "p1 male, p2 female"); + else + str = tr("%1 reveals %2 to %3.", "p1 male, p2 male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative)).arg(sanitizeHtml(otherPlayer->getName()))); + } else { + if (isFemale(player)) + appendHtml(tr("%1 reveals %2.", "female").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative))); + else + appendHtml(tr("%1 reveals %2.", "male").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative))); + } } else if (cardId == -2) { - if (otherPlayer) - append(tr("%1 randomly reveals %2%3 to %4.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName()))); - else - append(tr("%1 randomly reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr)); + if (otherPlayer) { + if (isFemale(player)) { + if (isFemale(otherPlayer)) + str = tr("%1 randomly reveals %2%3 to %4.", "p1 female, p2 female"); + else + str = tr("%1 randomly reveals %2%3 to %4.", "p1 female, p2 male"); + } else { + if (isFemale(otherPlayer)) + str = tr("%1 randomly reveals %2%3 to %4.", "p1 male, p2 female"); + else + str = tr("%1 randomly reveals %2%3 to %4.", "p1 male, p2 male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName()))); + } else { + if (isFemale(player)) + appendHtml(tr("%1 randomly reveals %2%3.", "female").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative))); + else + appendHtml(tr("%1 randomly reveals %2%3.", "male").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr)); + } } else { - if (otherPlayer) - append(tr("%1 reveals %2%3 to %4.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName()))); - else - append(tr("%1 reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr)); + if (otherPlayer) { + if (isFemale(player)) { + if (isFemale(otherPlayer)) + str = tr("%1 reveals %2%3 to %4.", "p1 female, p2 female"); + else + str = tr("%1 reveals %2%3 to %4.", "p1 female, p2 male"); + } else { + if (isFemale(otherPlayer)) + str = tr("%1 reveals %2%3 to %4.", "p1 male, p2 female"); + else + str = tr("%1 reveals %2%3 to %4.", "p1 male, p2 male"); + } + appendHtml(str.arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr).arg(sanitizeHtml(otherPlayer->getName()))); + } else { + if (isFemale(player)) + appendHtml(tr("%1 reveals %2%3.", "female").arg(sanitizeHtml(player->getName())).arg(zone->getTranslatedName(true, CaseAccusative))); + else + appendHtml(tr("%1 reveals %2%3.", "male").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr)); + } } } void MessageLogWidget::logSetActivePlayer(Player *player) { - append(QString()); - append("" + tr("It is now %1's turn.").arg(player->getName()) + ""); - append(QString()); + soundEngine->notification(); + + QString str; + if (isFemale(player)) + str = tr("It is now %1's turn.", "female"); + else + str = tr("It is now %1's turn.", "male"); + appendHtml("
" + str.arg(player->getName()) + "
"); } void MessageLogWidget::logSetActivePhase(int phase) { + soundEngine->notification(); QString phaseName; switch (phase) { case 0: phaseName = tr("untap step"); break; @@ -430,13 +732,18 @@ void MessageLogWidget::logSetActivePhase(int phase) case 9: phaseName = tr("second main phase"); break; case 10: phaseName = tr("ending phase"); break; } - append("" + tr("It is now the %1.").arg(phaseName) + ""); + appendHtml("" + tr("It is now the %1.").arg(phaseName) + ""); } void MessageLogWidget::containerProcessingStarted(GameEventContext *_context) { if (qobject_cast(_context)) currentContext = MessageContext_MoveCard; + else if (qobject_cast(_context)) { + currentContext = MessageContext_Mulligan; + mulliganPlayer = 0; + mulliganNumber = static_cast(_context)->getNumber(); + } } void MessageLogWidget::containerProcessingDone() @@ -447,6 +754,10 @@ void MessageLogWidget::containerProcessingDone() moveCardQueue.clear(); moveCardPT.clear(); moveCardTapped.clear(); + } else if (currentContext == MessageContext_Mulligan) { + logMulligan(mulliganPlayer, mulliganNumber); + mulliganPlayer = 0; + mulliganNumber = 0; } currentContext = MessageContext_None; @@ -454,8 +765,9 @@ void MessageLogWidget::containerProcessingDone() void MessageLogWidget::connectToPlayer(Player *player) { + connect(player, SIGNAL(logConnectionStateChanged(Player *, bool)), this, SLOT(logConnectionStateChanged(Player *, bool))); connect(player, SIGNAL(logSay(Player *, QString)), this, SLOT(logSay(Player *, QString))); - connect(player, SIGNAL(logShuffle(Player *)), this, SLOT(logShuffle(Player *))); + connect(player, SIGNAL(logShuffle(Player *, CardZone *)), this, SLOT(logShuffle(Player *, CardZone *))); connect(player, SIGNAL(logRollDie(Player *, int, int)), this, SLOT(logRollDie(Player *, int, int))); connect(player, SIGNAL(logCreateArrow(Player *, Player *, QString, Player *, QString, bool)), this, SLOT(logCreateArrow(Player *, Player *, QString, Player *, QString, bool))); connect(player, SIGNAL(logCreateToken(Player *, QString, QString)), this, SLOT(logCreateToken(Player *, QString, QString))); @@ -477,66 +789,7 @@ void MessageLogWidget::connectToPlayer(Player *player) connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *)), this, SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *))); } -MessageLogWidget::MessageLogWidget(QWidget *parent) - : QTextEdit(parent) +MessageLogWidget::MessageLogWidget(const QString &_ownName, bool _female, QWidget *parent) + : ChatView(_ownName, false, parent), female(_female) { - setReadOnly(true); -} - -void MessageLogWidget::enterEvent(QEvent * /*event*/) -{ - setMouseTracking(true); -} - -void MessageLogWidget::leaveEvent(QEvent * /*event*/) -{ - setMouseTracking(false); -} - -QString MessageLogWidget::getCardNameUnderMouse(const QPoint &pos) const -{ - QTextCursor cursor(cursorForPosition(pos)); - QTextBlock block(cursor.block()); - QTextBlock::iterator it; - for (it = block.begin(); !(it.atEnd()); ++it) { - QTextFragment frag = it.fragment(); - if (!frag.contains(cursor.position())) - continue; - - if (frag.charFormat().foreground().color() == Qt::blue) - return frag.text(); - - break; - } - return QString(); -} - -void MessageLogWidget::mouseMoveEvent(QMouseEvent *event) -{ - QString cardName = getCardNameUnderMouse(event->pos()); - if (!cardName.isEmpty()) { - viewport()->setCursor(Qt::PointingHandCursor); - emit cardNameHovered(cardName); - } else - viewport()->setCursor(Qt::IBeamCursor); - - QTextEdit::mouseMoveEvent(event); -} - -void MessageLogWidget::mousePressEvent(QMouseEvent *event) -{ - if (event->button() == Qt::MidButton) { - QString cardName = getCardNameUnderMouse(event->pos()); - if (!cardName.isEmpty()) - emit showCardInfoPopup(event->globalPos(), cardName); - } - - QTextEdit::mousePressEvent(event); -} - -void MessageLogWidget::mouseReleaseEvent(QMouseEvent *event) -{ - emit deleteCardInfoPopup(); - - QTextEdit::mouseReleaseEvent(event); } diff --git a/cockatrice/src/messagelogwidget.h b/cockatrice/src/messagelogwidget.h index b5295c35a..37d4a2422 100644 --- a/cockatrice/src/messagelogwidget.h +++ b/cockatrice/src/messagelogwidget.h @@ -1,15 +1,13 @@ #ifndef MESSAGELOGWIDGET_H #define MESSAGELOGWIDGET_H -#include +#include "chatview.h" #include #include "translation.h" #include "protocol_datastructures.h" class Player; class CardZone; -class QMouseEvent; -class QEvent; class CardInfoWidget; class GameEventContext; class CardItem; @@ -24,31 +22,24 @@ struct LogMoveCard { int newX; }; -class MessageLogWidget : public QTextEdit { +class MessageLogWidget : public ChatView { Q_OBJECT private: - enum MessageContext { MessageContext_None, MessageContext_MoveCard }; + enum MessageContext { MessageContext_None, MessageContext_MoveCard, MessageContext_Mulligan }; - CardInfoWidget *infoWidget; QString sanitizeHtml(QString dirty) const; + bool isFemale(Player *player) const; QPair getFromStr(CardZone *zone, QString cardName, int position) const; - QString getCardNameUnderMouse(const QPoint &pos) const; MessageContext currentContext; + bool female; + QList moveCardQueue; QMap moveCardPT; QMap moveCardTapped; -signals: - void cardNameHovered(QString cardName); - void showCardInfoPopup(QPoint pos, QString cardName); - void deleteCardInfoPopup(); + + Player *mulliganPlayer; + int mulliganNumber; public slots: - void logConnecting(QString hostname); - void logConnected(); - void logDisconnected(); - void logSocketError(const QString &errorString); - void logServerError(ResponseCode response); - void logProtocolVersionMismatch(int clientVersion, int serverVersion); - void logProtocolError(); void logGameJoined(int gameId); void logJoin(Player *player); void logLeave(Player *player); @@ -60,14 +51,16 @@ public slots: void logNotReadyStart(Player *player); void logConcede(Player *player); void logGameStart(); + void logConnectionStateChanged(Player *player, bool connectionState); void logSay(Player *player, QString message); void logSpectatorSay(QString spectatorName, QString message); - void logShuffle(Player *player); + void logShuffle(Player *player, CardZone *zone); void logRollDie(Player *player, int sides, int roll); void logDrawCards(Player *player, int number); void logUndoDraw(Player *player, QString cardName); void doMoveCard(LogMoveCard &attributes); void logMoveCard(Player *player, CardItem *card, CardZone *startZone, int oldX, CardZone *targetZone, int newX); + void logMulligan(Player *player, int number); void logFlipCard(Player *player, QString cardName, bool faceDown); void logDestroyCard(Player *player, QString cardName); void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName); @@ -89,13 +82,7 @@ public slots: void containerProcessingDone(); public: void connectToPlayer(Player *player); - MessageLogWidget(QWidget *parent = 0); -protected: - void enterEvent(QEvent *event); - void leaveEvent(QEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mousePressEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); + MessageLogWidget(const QString &_ownName, bool _female, QWidget *parent = 0); }; #endif diff --git a/cockatrice/src/pixmapgenerator.cpp b/cockatrice/src/pixmapgenerator.cpp index a27b081da..1c04e9226 100644 --- a/cockatrice/src/pixmapgenerator.cpp +++ b/cockatrice/src/pixmapgenerator.cpp @@ -78,6 +78,36 @@ QPixmap PingPixmapGenerator::generatePixmap(int size, int value, int max) QMap PingPixmapGenerator::pmCache; +QPixmap GenderPixmapGenerator::generatePixmap(int height, int _gender) +{ + ServerInfo_User::Gender gender = static_cast(_gender); + if ((gender != ServerInfo_User::Male) && (gender != ServerInfo_User::Female)) + gender = ServerInfo_User::GenderUnknown; + + int key = gender * 100000 + height; + if (pmCache.contains(key)) + return pmCache.value(key); + + QString genderStr; + switch (gender) { + case ServerInfo_User::Male: genderStr = "male"; break; + case ServerInfo_User::Female: genderStr = "female"; break; + default: genderStr = "unknown"; + }; + + QSvgRenderer svg(QString(":/resources/genders/" + genderStr + ".svg")); + int width = (int) round(height * (double) svg.defaultSize().width() / (double) svg.defaultSize().height()); + QPixmap pixmap(width, height); + pixmap.fill(Qt::transparent); + QPainter painter(&pixmap); + svg.render(&painter, QRectF(0, 0, width, height)); + + pmCache.insert(key, pixmap); + return pixmap; +} + +QMap GenderPixmapGenerator::pmCache; + QPixmap CountryPixmapGenerator::generatePixmap(int height, const QString &countryCode) { if (countryCode.size() != 2) @@ -110,8 +140,8 @@ QPixmap UserLevelPixmapGenerator::generatePixmap(int height, int userLevel) QString levelString; if (userLevel & ServerInfo_User::IsAdmin) levelString = "admin"; - else if (userLevel & ServerInfo_User::IsJudge) - levelString = "judge"; + else if (userLevel & ServerInfo_User::IsModerator) + levelString = "moderator"; else if (userLevel &ServerInfo_User::IsRegistered) levelString = "registered"; else diff --git a/cockatrice/src/pixmapgenerator.h b/cockatrice/src/pixmapgenerator.h index 7f69c26dd..25fa00c96 100644 --- a/cockatrice/src/pixmapgenerator.h +++ b/cockatrice/src/pixmapgenerator.h @@ -28,6 +28,14 @@ public: static void clear() { pmCache.clear(); } }; +class GenderPixmapGenerator { +private: + static QMap pmCache; +public: + static QPixmap generatePixmap(int height, int gender); + static void clear() { pmCache.clear(); } +}; + class CountryPixmapGenerator { private: static QMap pmCache; diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 96bad5031..fc794bd3f 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -706,6 +706,11 @@ void Player::setCardAttrHelper(GameEventContext *context, CardItem *card, const } } +void Player::eventConnectionStateChanged(Event_ConnectionStateChanged *event) +{ + emit logConnectionStateChanged(this, event->getConnected()); +} + void Player::eventSay(Event_Say *event) { emit logSay(this, event->getMessage()); @@ -713,7 +718,7 @@ void Player::eventSay(Event_Say *event) void Player::eventShuffle(Event_Shuffle * /*event*/) { - emit logShuffle(this); + emit logShuffle(this, zones.value("deck")); } void Player::eventRollDie(Event_RollDie *event) @@ -862,6 +867,8 @@ void Player::eventMoveCard(Event_MoveCard *event, GameEventContext *context) CardItem *card = startZone->takeCard(position, event->getCardId(), startZone != targetZone); if (!card) return; + if (startZone != targetZone) + card->deleteCardInfoPopup(); card->setName(event->getCardName()); if (card->getAttachedTo() && (startZone != targetZone)) { @@ -891,8 +898,7 @@ void Player::eventMoveCard(Event_MoveCard *event, GameEventContext *context) if (context) switch (context->getItemId()) { case ItemId_Context_UndoDraw: emit logUndoDraw(this, card->getName()); break; - case ItemId_Context_MoveCard: emit logMoveCard(this, card, startZone, logPosition, targetZone, logX); - default: ; + default: emit logMoveCard(this, card, startZone, logPosition, targetZone, logX); } else emit logMoveCard(this, card, startZone, logPosition, targetZone, logX); @@ -1008,7 +1014,6 @@ void Player::eventDrawCards(Event_DrawCards *event) hand->reorganizeCards(); deck->reorganizeCards(); - emit logDrawCards(this, event->getNumberCards()); } @@ -1038,6 +1043,7 @@ void Player::processGameEvent(GameEvent *event, GameEventContext *context) { qDebug() << "player event: id=" << event->getItemId(); switch (event->getItemId()) { + case ItemId_Event_ConnectionStateChanged: eventConnectionStateChanged(static_cast(event)); break; case ItemId_Event_Say: eventSay(static_cast(event)); break; case ItemId_Event_Shuffle: eventShuffle(static_cast(event)); break; case ItemId_Event_RollDie: eventRollDie(static_cast(event)); break; @@ -1546,12 +1552,9 @@ void Player::setMirrored(bool _mirrored) } } -void Player::processSceneSizeChange(const QSizeF &newSize) +void Player::processSceneSizeChange(int newPlayerWidth) { - // 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 - 15 - counterAreaWidth - stack->boundingRect().width(); + qreal tableWidth = newPlayerWidth - 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 c30fc3760..72f19c260 100644 --- a/cockatrice/src/player.h +++ b/cockatrice/src/player.h @@ -26,6 +26,7 @@ class CommandContainer; class GameCommand; class GameEvent; class GameEventContext; +class Event_ConnectionStateChanged; class Event_Say; class Event_Shuffle; class Event_RollDie; @@ -69,8 +70,9 @@ class Player : public QObject, public QGraphicsItem { signals: void newCardAdded(AbstractCardItem *card); // Log events + void logConnectionStateChanged(Player *player, bool connectionState); void logSay(Player *player, QString message); - void logShuffle(Player *player); + void logShuffle(Player *player, CardZone *zone); void logRollDie(Player *player, int sides, int roll); void logCreateArrow(Player *player, Player *startPlayer, QString startCard, Player *targetPlayer, QString targetCard, bool _playerTarget); void logCreateToken(Player *player, QString cardName, QString pt); @@ -176,6 +178,7 @@ private: void initSayMenu(); + void eventConnectionStateChanged(Event_ConnectionStateChanged *event); void eventSay(Event_Say *event); void eventShuffle(Event_Shuffle *event); void eventRollDie(Event_RollDie *event); @@ -245,7 +248,7 @@ public: qreal getMinimumWidth() const; void setMirrored(bool _mirrored); - void processSceneSizeChange(const QSizeF &newSize); + void processSceneSizeChange(int newPlayerWidth); void processPlayerInfo(ServerInfo_Player *info); void processCardAttachment(ServerInfo_Player *info); diff --git a/cockatrice/src/priceupdater.cpp b/cockatrice/src/priceupdater.cpp new file mode 100644 index 000000000..e9f1a6953 --- /dev/null +++ b/cockatrice/src/priceupdater.cpp @@ -0,0 +1,81 @@ +/** + * @author Marcio Ribeiro + * @version 1.0 + */ +#include +#include + +#include +#include +#include "priceupdater.h" + +/** + * Constructor. + * + * @param _deck deck. + */ +PriceUpdater::PriceUpdater(const DeckList *_deck) +{ + nam = new QNetworkAccessManager(this); + deck = _deck; +} + +/** + * Update the prices of the cards in deckList. + */ +void PriceUpdater::updatePrices() +{ + QString q = "http://blacklotusproject.com/json/?cards="; + QStringList cards = deck->getCardList(); + for (int i = 0; i < cards.size(); ++i) { + q += cards[i] + "|"; + } + QUrl url(q.replace(' ', '+')); + + QNetworkReply *reply = nam->get(QNetworkRequest(url)); + connect(reply, SIGNAL(finished()), this, SLOT(downloadFinished())); +} + +/** + * Called when the download of the json file with the prices is finished. + */ +void PriceUpdater::downloadFinished() +{ + QMap cmap; + InnerDecklistNode *listRoot = deck->getRoot(); + for (int i = 0; i < listRoot->size(); i++) { + InnerDecklistNode *currentZone = dynamic_cast(listRoot->at(i)); + for (int j = 0; j < currentZone->size(); j++) { + DecklistCardNode *currentCard = dynamic_cast(currentZone->at(j)); + if (!currentCard) + continue; + cmap.insert(currentCard->getName().toLower(), currentCard); + currentCard->setPrice(0); + } + } + + QNetworkReply *reply = static_cast(sender()); + QByteArray result = reply->readAll(); + QScriptValue sc; + QScriptEngine engine; + sc = engine.evaluate("value = " + result); + + if (sc.property("cards").isArray()) { + QScriptValueIterator it(sc.property("cards")); + while (it.hasNext()) { + it.next(); + QString name = it.value().property("name").toString().toLower(); + float price = it.value().property("average").toString().toFloat(); + DecklistCardNode *c = cmap[name]; + if (!c) + continue; + if (c->getPrice() == 0 || c->getPrice() > price) { + c->setPrice(price); + } + } + } + + reply->deleteLater(); + deleteLater(); + emit finishedUpdate(); +} diff --git a/cockatrice/src/priceupdater.h b/cockatrice/src/priceupdater.h new file mode 100644 index 000000000..a95252eb8 --- /dev/null +++ b/cockatrice/src/priceupdater.h @@ -0,0 +1,28 @@ +#ifndef PRICEUPDATER_H +#define PRICEUPDATER_H + +#include +#include "decklist.h" + +class QNetworkAccessManager; + +/** + * Price Updater. + * + * @author Marcio Ribeiro + */ +class PriceUpdater : public QObject +{ + Q_OBJECT +private: + const DeckList *deck; + QNetworkAccessManager *nam; +signals: + void finishedUpdate(); +private slots: + void downloadFinished(); +public: + PriceUpdater(const DeckList *deck); + void updatePrices(); +}; +#endif diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index 2bb43b999..8f0844870 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "remoteclient.h" #include "protocol.h" #include "protocol_items.h" @@ -82,12 +83,13 @@ void RemoteClient::readData() xmlWriter->writeStartDocument(); xmlWriter->writeStartElement("cockatrice_client_stream"); xmlWriter->writeAttribute("version", QString::number(ProtocolItem::protocolVersion)); + xmlWriter->writeAttribute("comp", "1"); topLevelItem = new TopLevelProtocolItem; connect(topLevelItem, SIGNAL(protocolItemReceived(ProtocolItem *)), this, SLOT(processProtocolItem(ProtocolItem *))); setStatus(StatusLoggingIn); - Command_Login *cmdLogin = new Command_Login(userName, password); + Command_Login *cmdLogin = new Command_Login(userName, QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha1).toBase64()); connect(cmdLogin, SIGNAL(finished(ProtocolResponse *)), this, SLOT(loginResponse(ProtocolResponse *))); sendCommand(cmdLogin); } diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index de7cb7bf7..8c3cee479 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -19,14 +19,21 @@ SettingsCache::SettingsCache() picDownload = settings->value("personal/picturedownload", true).toBool(); doubleClickToPlay = settings->value("interface/doubleclicktoplay", true).toBool(); - cardInfoMinimized = settings->value("interface/cardinfominimized", false).toBool(); + cardInfoMinimized = settings->value("interface/cardinfominimized", 0).toInt(); + tabGameSplitterSizes = settings->value("interface/tabgame_splittersizes").toByteArray(); displayCardNames = settings->value("cards/displaycardnames", true).toBool(); horizontalHand = settings->value("hand/horizontal", true).toBool(); invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool(); + minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 5).toInt(); tapAnimation = settings->value("cards/tapanimation", true).toBool(); zoneViewSortByName = settings->value("zoneview/sortbyname", true).toBool(); zoneViewSortByType = settings->value("zoneview/sortbytype", true).toBool(); + + soundEnabled = settings->value("sound/enabled", false).toBool(); + soundPath = settings->value("sound/path").toString(); + + priceTagFeature = settings->value("deckeditor/pricetags", false).toBool(); } void SettingsCache::setLang(const QString &_lang) @@ -104,12 +111,18 @@ void SettingsCache::setDoubleClickToPlay(int _doubleClickToPlay) settings->setValue("interface/doubleclicktoplay", doubleClickToPlay); } -void SettingsCache::setCardInfoMinimized(bool _cardInfoMinimized) +void SettingsCache::setCardInfoMinimized(int _cardInfoMinimized) { - cardInfoMinimized = _cardInfoMinimized; + cardInfoMinimized = _cardInfoMinimized; settings->setValue("interface/cardinfominimized", cardInfoMinimized); } +void SettingsCache::setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes) +{ + tabGameSplitterSizes = _tabGameSplitterSizes; + settings->setValue("interface/tabgame_splittersizes", tabGameSplitterSizes); +} + void SettingsCache::setDisplayCardNames(int _displayCardNames) { displayCardNames = _displayCardNames; @@ -131,6 +144,13 @@ void SettingsCache::setInvertVerticalCoordinate(int _invertVerticalCoordinate) emit invertVerticalCoordinateChanged(); } +void SettingsCache::setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout) +{ + minPlayersForMultiColumnLayout = _minPlayersForMultiColumnLayout; + settings->setValue("interface/min_players_multicolumn", minPlayersForMultiColumnLayout); + emit minPlayersForMultiColumnLayoutChanged(); +} + void SettingsCache::setTapAnimation(int _tapAnimation) { tapAnimation = _tapAnimation; @@ -148,3 +168,22 @@ void SettingsCache::setZoneViewSortByType(int _zoneViewSortByType) zoneViewSortByType = _zoneViewSortByType; settings->setValue("zoneview/sortbytype", zoneViewSortByType); } + +void SettingsCache::setSoundEnabled(int _soundEnabled) +{ + soundEnabled = _soundEnabled; + settings->setValue("sound/enabled", soundEnabled); +} + +void SettingsCache::setSoundPath(const QString &_soundPath) +{ + soundPath = _soundPath; + settings->setValue("sound/path", soundPath); + emit soundPathChanged(); +} + +void SettingsCache::setPriceTagFeature(int _priceTagFeature) +{ + priceTagFeature = _priceTagFeature; + settings->setValue("deckeditor/pricetags", priceTagFeature); +} diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index 607d572d9..b3f1ae6c0 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -20,6 +20,8 @@ signals: void displayCardNamesChanged(); void horizontalHandChanged(); void invertVerticalCoordinateChanged(); + void minPlayersForMultiColumnLayoutChanged(); + void soundPathChanged(); private: QSettings *settings; @@ -28,12 +30,17 @@ private: QString handBgPath, stackBgPath, tableBgPath, playerBgPath, cardBackPicturePath; bool picDownload; bool doubleClickToPlay; - bool cardInfoMinimized; + int cardInfoMinimized; + QByteArray tabGameSplitterSizes; bool displayCardNames; bool horizontalHand; bool invertVerticalCoordinate; + int minPlayersForMultiColumnLayout; bool tapAnimation; bool zoneViewSortByName, zoneViewSortByType; + bool soundEnabled; + QString soundPath; + bool priceTagFeature; public: SettingsCache(); QString getLang() const { return lang; } @@ -47,13 +54,18 @@ public: QString getCardBackPicturePath() const { return cardBackPicturePath; } bool getPicDownload() const { return picDownload; } bool getDoubleClickToPlay() const { return doubleClickToPlay; } - bool getCardInfoMinimized() const { return cardInfoMinimized; } + int getCardInfoMinimized() const { return cardInfoMinimized; } + QByteArray getTabGameSplitterSizes() const { return tabGameSplitterSizes; } bool getDisplayCardNames() const { return displayCardNames; } bool getHorizontalHand() const { return horizontalHand; } bool getInvertVerticalCoordinate() const { return invertVerticalCoordinate; } + int getMinPlayersForMultiColumnLayout() const { return minPlayersForMultiColumnLayout; } bool getTapAnimation() const { return tapAnimation; } bool getZoneViewSortByName() const { return zoneViewSortByName; } bool getZoneViewSortByType() const { return zoneViewSortByType; } + bool getSoundEnabled() const { return soundEnabled; } + QString getSoundPath() const { return soundPath; } + bool getPriceTagFeature() const { return priceTagFeature; } public slots: void setLang(const QString &_lang); void setDeckPath(const QString &_deckPath); @@ -66,13 +78,18 @@ public slots: void setCardBackPicturePath(const QString &_cardBackPicturePath); void setPicDownload(int _picDownload); void setDoubleClickToPlay(int _doubleClickToPlay); - void setCardInfoMinimized(bool _cardInfoMinimized); + void setCardInfoMinimized(int _cardInfoMinimized); + void setTabGameSplitterSizes(const QByteArray &_tabGameSplitterSizes); void setDisplayCardNames(int _displayCardNames); void setHorizontalHand(int _horizontalHand); void setInvertVerticalCoordinate(int _invertVerticalCoordinate); + void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout); void setTapAnimation(int _tapAnimation); void setZoneViewSortByName(int _zoneViewSortByName); void setZoneViewSortByType(int _zoneViewSortByType); + void setSoundEnabled(int _soundEnabled); + void setSoundPath(const QString &_soundPath); + void setPriceTagFeature(int _priceTagFeature); }; extern SettingsCache *settingsCache; diff --git a/cockatrice/src/soundengine.cpp b/cockatrice/src/soundengine.cpp new file mode 100644 index 000000000..247567ccc --- /dev/null +++ b/cockatrice/src/soundengine.cpp @@ -0,0 +1,82 @@ +#include "soundengine.h" +#include "settingscache.h" +#include +#include +#include +#include + +SoundEngine::SoundEngine(QObject *parent) + : QObject(parent) +{ + inputBuffer = new QBuffer; + QAudioFormat format; + format.setFrequency(44100); + format.setChannels(1); + format.setSampleSize(16); + format.setCodec("audio/pcm"); + format.setByteOrder(QAudioFormat::LittleEndian); + format.setSampleType(QAudioFormat::SignedInt); + audio = new QAudioOutput(format, this); + + connect(settingsCache, SIGNAL(soundPathChanged()), this, SLOT(cacheData())); + cacheData(); +} + +void SoundEngine::cacheData() +{ + static const QStringList fileNames = QStringList() + << "notification" << "draw" << "playcard" << "shuffle" << "tap" << "untap" << "cuckoo"; + for (int i = 0; i < fileNames.size(); ++i) { + QFile file(settingsCache->getSoundPath() + "/" + fileNames[i] + ".raw"); + file.open(QIODevice::ReadOnly); + audioData.insert(fileNames[i], file.readAll()); + file.close(); + } +} + +void SoundEngine::playSound(const QString &fileName) +{ + if (!settingsCache->getSoundEnabled()) + return; + + audio->stop(); + inputBuffer->close(); + inputBuffer->setData(audioData[fileName]); + inputBuffer->open(QIODevice::ReadOnly); + audio->start(inputBuffer); +} + +void SoundEngine::notification() +{ + playSound("notification"); +} + +void SoundEngine::draw() +{ + playSound("draw"); +} + +void SoundEngine::playCard() +{ + playSound("playcard"); +} + +void SoundEngine::shuffle() +{ + playSound("shuffle"); +} + +void SoundEngine::tap() +{ + playSound("tap"); +} + +void SoundEngine::untap() +{ + playSound("untap"); +} + +void SoundEngine::cuckoo() +{ + playSound("cuckoo"); +} diff --git a/cockatrice/src/soundengine.h b/cockatrice/src/soundengine.h new file mode 100644 index 000000000..d65b3f2dd --- /dev/null +++ b/cockatrice/src/soundengine.h @@ -0,0 +1,33 @@ +#ifndef SOUNDENGINE_H +#define SOUNDENGINE_H + +#include +#include + +class QAudioOutput; +class QBuffer; + +class SoundEngine : public QObject { + Q_OBJECT +private: + void playSound(const QString &fileName); + QMap audioData; + QBuffer *inputBuffer; + QAudioOutput *audio; +private slots: + void cacheData(); +public: + SoundEngine(QObject *parent = 0); +public slots: + void notification(); + void draw(); + void playCard(); + void shuffle(); + void tap(); + void untap(); + void cuckoo(); +}; + +extern SoundEngine *soundEngine; + +#endif \ No newline at end of file diff --git a/cockatrice/src/tab.cpp b/cockatrice/src/tab.cpp new file mode 100644 index 000000000..2eed9b546 --- /dev/null +++ b/cockatrice/src/tab.cpp @@ -0,0 +1,32 @@ +#include "tab.h" +#include "cardinfowidget.h" +#include +#include + +Tab::Tab(TabSupervisor *_tabSupervisor, QWidget *parent) + : QWidget(parent), tabMenu(0), tabSupervisor(_tabSupervisor), contentsChanged(false), infoPopup(0) +{ +} + +void Tab::showCardInfoPopup(const QPoint &pos, const QString &cardName) +{ + infoPopup = new CardInfoWidget(CardInfoWidget::ModePopUp, 0, Qt::Widget | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); + infoPopup->setAttribute(Qt::WA_TransparentForMouseEvents); + infoPopup->setCard(cardName); + QRect screenRect = qApp->desktop()->screenGeometry(this); + infoPopup->move( + qMax(screenRect.left(), qMin(pos.x() - infoPopup->width() / 2, screenRect.left() + screenRect.width() - infoPopup->width())), + qMax(screenRect.top(), qMin(pos.y() - infoPopup->height() / 2, screenRect.top() + screenRect.height() - infoPopup->height())) + ); + infoPopup->show(); +} + +void Tab::deleteCardInfoPopup(const QString &cardName) +{ + if (infoPopup) { + if ((infoPopup->getCardName() == cardName) || (cardName == "_")) { + infoPopup->deleteLater(); + infoPopup = 0; + } + } +} diff --git a/cockatrice/src/tab.h b/cockatrice/src/tab.h index ac83ec593..3fefde1a1 100644 --- a/cockatrice/src/tab.h +++ b/cockatrice/src/tab.h @@ -5,24 +5,29 @@ class QMenu; class TabSupervisor; +class CardInfoWidget; class Tab : public QWidget { Q_OBJECT signals: - void userEvent(); + void userEvent(bool globalEvent = true); protected: QMenu *tabMenu; TabSupervisor *tabSupervisor; +protected slots: + void showCardInfoPopup(const QPoint &pos, const QString &cardName); + void deleteCardInfoPopup(const QString &cardName); private: bool contentsChanged; + CardInfoWidget *infoPopup; public: - Tab(TabSupervisor *_tabSupervisor, QWidget *parent = 0) - : QWidget(parent), tabMenu(0), tabSupervisor(_tabSupervisor), contentsChanged(false) { } + Tab(TabSupervisor *_tabSupervisor, QWidget *parent = 0); QMenu *getTabMenu() const { return tabMenu; } bool getContentsChanged() const { return contentsChanged; } void setContentsChanged(bool _contentsChanged) { contentsChanged = _contentsChanged; } virtual QString getTabText() const = 0; virtual void retranslateUi() = 0; + virtual void closeRequest() { } }; #endif diff --git a/cockatrice/src/tab_admin.cpp b/cockatrice/src/tab_admin.cpp index 4ea3a6527..082321384 100644 --- a/cockatrice/src/tab_admin.cpp +++ b/cockatrice/src/tab_admin.cpp @@ -1,19 +1,72 @@ +#include #include +#include #include #include #include +#include +#include +#include #include "tab_admin.h" #include "abstractclient.h" #include "protocol_items.h" -TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, QWidget *parent) - : Tab(_tabSupervisor, parent), locked(true), client(_client) +ShutdownDialog::ShutdownDialog(QWidget *parent) + : QDialog(parent) +{ + QLabel *reasonLabel = new QLabel(tr("&Reason for shutdown:")); + reasonEdit = new QLineEdit; + reasonLabel->setBuddy(reasonEdit); + QLabel *minutesLabel = new QLabel(tr("&Time until shutdown (minutes):")); + minutesEdit = new QSpinBox; + minutesLabel->setBuddy(minutesEdit); + minutesEdit->setMinimum(0); + minutesEdit->setValue(5); + + QPushButton *okButton = new QPushButton(tr("&OK")); + okButton->setAutoDefault(true); + okButton->setDefault(true); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + QPushButton *cancelButton = new QPushButton(tr("&Cancel")); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); + + QGridLayout *mainLayout = new QGridLayout; + mainLayout->addWidget(reasonLabel, 0, 0); + mainLayout->addWidget(reasonEdit, 0, 1); + mainLayout->addWidget(minutesLabel, 1, 0); + mainLayout->addWidget(minutesEdit, 1, 1); + mainLayout->addLayout(buttonLayout, 2, 0, 1, 2); + + setLayout(mainLayout); + setWindowTitle(tr("Shut down server")); +} + +QString ShutdownDialog::getReason() const +{ + return reasonEdit->text(); +} + +int ShutdownDialog::getMinutes() const +{ + return minutesEdit->value(); +} + +TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool _fullAdmin, QWidget *parent) + : Tab(_tabSupervisor, parent), locked(true), client(_client), fullAdmin(_fullAdmin) { updateServerMessageButton = new QPushButton; connect(updateServerMessageButton, SIGNAL(clicked()), this, SLOT(actUpdateServerMessage())); + shutdownServerButton = new QPushButton; + connect(shutdownServerButton, SIGNAL(clicked()), this, SLOT(actShutdownServer())); QVBoxLayout *vbox = new QVBoxLayout; vbox->addWidget(updateServerMessageButton); + vbox->addWidget(shutdownServerButton); vbox->addStretch(); adminGroupBox = new QGroupBox; @@ -38,6 +91,7 @@ TabAdmin::TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, QWidg void TabAdmin::retranslateUi() { updateServerMessageButton->setText(tr("Update server &message")); + shutdownServerButton->setText(tr("&Shut down server")); adminGroupBox->setTitle(tr("Server administration functions")); unlockButton->setText(tr("&Unlock functions")); @@ -49,10 +103,18 @@ void TabAdmin::actUpdateServerMessage() client->sendCommand(new Command_UpdateServerMessage()); } +void TabAdmin::actShutdownServer() +{ + ShutdownDialog dlg; + if (dlg.exec()) + client->sendCommand(new Command_ShutdownServer(dlg.getReason(), dlg.getMinutes())); +} + 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); + if (fullAdmin) + adminGroupBox->setEnabled(true); lockButton->setEnabled(true); unlockButton->setEnabled(false); locked = false; @@ -61,7 +123,8 @@ void TabAdmin::actUnlock() void TabAdmin::actLock() { - adminGroupBox->setEnabled(false); + if (fullAdmin) + adminGroupBox->setEnabled(false); lockButton->setEnabled(false); unlockButton->setEnabled(true); locked = true; diff --git a/cockatrice/src/tab_admin.h b/cockatrice/src/tab_admin.h index 8450d473b..a4982bbae 100644 --- a/cockatrice/src/tab_admin.h +++ b/cockatrice/src/tab_admin.h @@ -2,27 +2,43 @@ #define TAB_ADMIN_H #include "tab.h" +#include class AbstractClient; class QGroupBox; class QPushButton; +class QSpinBox; +class QLineEdit; + +class ShutdownDialog : public QDialog { + Q_OBJECT +private: + QLineEdit *reasonEdit; + QSpinBox *minutesEdit; +public: + ShutdownDialog(QWidget *parent = 0); + QString getReason() const; + int getMinutes() const; +}; class TabAdmin : public Tab { Q_OBJECT private: bool locked; AbstractClient *client; - QPushButton *updateServerMessageButton; + bool fullAdmin; + QPushButton *updateServerMessageButton, *shutdownServerButton; QGroupBox *adminGroupBox; QPushButton *unlockButton, *lockButton; private slots: void actUpdateServerMessage(); + void actShutdownServer(); void actUnlock(); void actLock(); public: - TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, QWidget *parent = 0); + TabAdmin(TabSupervisor *_tabSupervisor, AbstractClient *_client, bool _fullAdmin, QWidget *parent = 0); void retranslateUi(); QString getTabText() const { return tr("Administration"); } bool getLocked() const { return locked; } diff --git a/cockatrice/src/tab_game.cpp b/cockatrice/src/tab_game.cpp index fa608c29d..9b15e0deb 100644 --- a/cockatrice/src/tab_game.cpp +++ b/cockatrice/src/tab_game.cpp @@ -1,11 +1,10 @@ #include #include +#include #include #include #include #include -#include -#include #include "tab_game.h" #include "cardinfowidget.h" #include "playerlistwidget.h" @@ -159,8 +158,8 @@ void DeckViewContainer::setDeck(DeckList *deck) readyStartButton->setEnabled(true); } -TabGame::TabGame(TabSupervisor *_tabSupervisor, QList &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming) - : Tab(_tabSupervisor), clients(_clients), gameId(_gameId), gameDescription(_gameDescription), localPlayerId(_localPlayerId), spectator(_spectator), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), started(false), resuming(_resuming), currentPhase(-1), infoPopup(0) +TabGame::TabGame(TabSupervisor *_tabSupervisor, QList &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, ServerInfo_User *_userInfo, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming) + : Tab(_tabSupervisor), clients(_clients), gameId(_gameId), gameDescription(_gameDescription), localPlayerId(_localPlayerId), spectator(_spectator), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), started(false), resuming(_resuming), currentPhase(-1) { phasesToolbar = new PhasesToolbar; phasesToolbar->hide(); @@ -177,10 +176,10 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList &_client timeElapsedLabel = new QLabel; timeElapsedLabel->setAlignment(Qt::AlignCenter); - messageLog = new MessageLogWidget; + messageLog = new MessageLogWidget(_userInfo->getName(), _userInfo->getGender() == ServerInfo_User::Female); connect(messageLog, SIGNAL(cardNameHovered(QString)), cardInfo, SLOT(setCard(QString))); connect(messageLog, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString))); - connect(messageLog, SIGNAL(deleteCardInfoPopup()), this, SLOT(deleteCardInfoPopup())); + connect(messageLog, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString))); sayLabel = new QLabel; sayEdit = new QLineEdit; sayLabel->setBuddy(sayEdit); @@ -191,17 +190,23 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList &_client deckViewContainerLayout = new QVBoxLayout; - QVBoxLayout *verticalLayout = new QVBoxLayout; - verticalLayout->addWidget(cardInfo); - verticalLayout->addWidget(playerListWidget, 1); - verticalLayout->addWidget(timeElapsedLabel); - verticalLayout->addWidget(messageLog, 5); - verticalLayout->addLayout(hLayout); + QVBoxLayout *messageLogLayout = new QVBoxLayout; + messageLogLayout->addWidget(timeElapsedLabel); + messageLogLayout->addWidget(messageLog); + messageLogLayout->addLayout(hLayout); + + QWidget *messageLogLayoutWidget = new QWidget; + messageLogLayoutWidget->setLayout(messageLogLayout); + + splitter = new QSplitter(Qt::Vertical); + splitter->addWidget(cardInfo); + splitter->addWidget(playerListWidget); + splitter->addWidget(messageLogLayoutWidget); mainLayout = new QHBoxLayout; mainLayout->addWidget(gameView, 10); mainLayout->addLayout(deckViewContainerLayout, 10); - mainLayout->addLayout(verticalLayout); + mainLayout->addWidget(splitter); if (spectator && !spectatorsCanTalk) { sayLabel->hide(); @@ -253,12 +258,16 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, QList &_client retranslateUi(); setLayout(mainLayout); + + splitter->restoreState(settingsCache->getTabGameSplitterSizes()); messageLog->logGameJoined(gameId); } TabGame::~TabGame() { + settingsCache->setTabGameSplitterSizes(splitter->saveState()); + QMapIterator i(players); while (i.hasNext()) delete i.next().value(); @@ -285,6 +294,7 @@ void TabGame::retranslateUi() aConcede->setText(tr("&Concede")); aConcede->setShortcut(tr("F2")); aLeaveGame->setText(tr("&Leave game")); + aLeaveGame->setShortcut(tr("Ctrl+Q")); sayLabel->setText(tr("&Say:")); cardInfo->retranslateUi(); @@ -299,6 +309,11 @@ void TabGame::retranslateUi() scene->retranslateUi(); } +void TabGame::closeRequest() +{ + actLeaveGame(); +} + void TabGame::actConcede() { if (QMessageBox::question(this, tr("Concede"), tr("Are you sure you want to concede this game?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) @@ -309,8 +324,9 @@ void TabGame::actConcede() void TabGame::actLeaveGame() { - if (QMessageBox::question(this, tr("Leave game"), tr("Are you sure you want to leave this game?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) - return; + if (!spectator) + if (QMessageBox::question(this, tr("Leave game"), tr("Are you sure you want to leave this game?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) + return; sendGameCommand(new Command_LeaveGame); deleteLater(); @@ -729,7 +745,7 @@ void TabGame::newCardAdded(AbstractCardItem *card) { connect(card, SIGNAL(hovered(AbstractCardItem *)), cardInfo, SLOT(setCard(AbstractCardItem *))); connect(card, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString))); - connect(card, SIGNAL(deleteCardInfoPopup()), this, SLOT(deleteCardInfoPopup())); + connect(card, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString))); } CardItem *TabGame::getCard(int playerId, const QString &zoneName, int cardId) const @@ -761,25 +777,3 @@ Player *TabGame::getActiveLocalPlayer() const return 0; } - -void TabGame::showCardInfoPopup(const QPoint &pos, const QString &cardName) -{ - infoPopup = new CardInfoWidget(CardInfoWidget::ModePopUp, 0, Qt::Widget | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); - connect(infoPopup, SIGNAL(mouseReleased()), this, SLOT(deleteCardInfoPopup())); - infoPopup->setCard(cardName); - QRect screenRect = qApp->desktop()->screenGeometry(this); - infoPopup->move( - qMax(screenRect.left(), qMin(pos.x() - infoPopup->width() / 2, screenRect.left() + screenRect.width() - infoPopup->width())), - qMax(screenRect.top(), qMin(pos.y() - infoPopup->height() / 2, screenRect.top() + screenRect.height() - infoPopup->height())) - ); - infoPopup->show(); - infoPopup->grabMouse(); -} - -void TabGame::deleteCardInfoPopup() -{ - if (infoPopup) { - infoPopup->deleteLater(); - infoPopup = 0; - } -} diff --git a/cockatrice/src/tab_game.h b/cockatrice/src/tab_game.h index b11f857c0..a5eb5db9f 100644 --- a/cockatrice/src/tab_game.h +++ b/cockatrice/src/tab_game.h @@ -12,6 +12,7 @@ class DeckView; class GameScene; class CardInfoWidget; class MessageLogWidget; +class QSplitter; class QLabel; class QLineEdit; class QPushButton; @@ -98,7 +99,7 @@ private: int currentPhase; int activePlayer; - CardInfoWidget *infoPopup; + QSplitter *splitter; CardInfoWidget *cardInfo; PlayerListWidget *playerListWidget; QLabel *timeElapsedLabel; @@ -145,8 +146,6 @@ signals: void openMessageDialog(const QString &userName, bool focus); private slots: void newCardAdded(AbstractCardItem *card); - void showCardInfoPopup(const QPoint &pos, const QString &cardName); - void deleteCardInfoPopup(); void actConcede(); void actLeaveGame(); @@ -156,9 +155,10 @@ private slots: void actNextPhase(); void actNextTurn(); public: - TabGame(TabSupervisor *_tabSupervisor, QList &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming); + TabGame(TabSupervisor *_tabSupervisor, QList &_clients, int _gameId, const QString &_gameDescription, int _localPlayerId, ServerInfo_User *_userInfo, bool _spectator, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, bool _resuming); ~TabGame(); void retranslateUi(); + void closeRequest(); const QMap &getPlayers() const { return players; } CardItem *getCard(int playerId, const QString &zoneName, int cardId) const; int getGameId() const { return gameId; } diff --git a/cockatrice/src/tab_message.cpp b/cockatrice/src/tab_message.cpp index 4581ad140..f4efd7f57 100644 --- a/cockatrice/src/tab_message.cpp +++ b/cockatrice/src/tab_message.cpp @@ -11,7 +11,9 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, const QString &_ownName, const QString &_userName) : Tab(_tabSupervisor), client(_client), userName(_userName), userOnline(true) { - chatView = new ChatView(_ownName); + chatView = new ChatView(_ownName, true); + connect(chatView, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString))); + connect(chatView, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString))); sayEdit = new QLineEdit; connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage())); @@ -40,6 +42,11 @@ void TabMessage::retranslateUi() aLeave->setText(tr("&Leave")); } +void TabMessage::closeRequest() +{ + actLeave(); +} + void TabMessage::sendMessage() { if (sayEdit->text().isEmpty() || !userOnline) diff --git a/cockatrice/src/tab_message.h b/cockatrice/src/tab_message.h index 17856aa53..b8543704c 100644 --- a/cockatrice/src/tab_message.h +++ b/cockatrice/src/tab_message.h @@ -30,6 +30,7 @@ public: TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, const QString &_ownName, const QString &_userName); ~TabMessage(); void retranslateUi(); + void closeRequest(); QString getUserName() const { return userName; } QString getTabText() const { return tr("Talking to %1").arg(userName); } diff --git a/cockatrice/src/tab_room.cpp b/cockatrice/src/tab_room.cpp index 4e7770aea..7fbce5a7a 100644 --- a/cockatrice/src/tab_room.cpp +++ b/cockatrice/src/tab_room.cpp @@ -4,126 +4,17 @@ #include #include #include -#include #include #include -#include #include -#include "dlg_creategame.h" +#include #include "tab_supervisor.h" #include "tab_room.h" #include "userlist.h" #include "abstractclient.h" #include "protocol_items.h" -#include "gamesmodel.h" #include "chatview.h" - -GameSelector::GameSelector(AbstractClient *_client, TabRoom *_room, QWidget *parent) - : QGroupBox(parent), client(_client), room(_room) -{ - gameListView = new QTreeView; - gameListModel = new GamesModel(room->getGameTypes(), this); - gameListProxyModel = new GamesProxyModel(this); - gameListProxyModel->setSourceModel(gameListModel); - gameListProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); - gameListView->setModel(gameListProxyModel); - gameListView->header()->setResizeMode(0, QHeaderView::ResizeToContents); - gameListView->setSortingEnabled(true); - - 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((qreal) (gameListView->columnWidth(0) * gameListModel->columnCount()) / 1.5); - 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, room->getRoomId(), room->getGameTypes(), 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; - case RespUserLevelTooLow: QMessageBox::critical(this, tr("Error"), tr("This game is only open to registered users.")); break; - case RespOnlyBuddies: QMessageBox::critical(this, tr("Error"), tr("This game is only open to its creator's buddies.")); break; - case RespInIgnoreList: QMessageBox::critical(this, tr("Error"), tr("You are being ignored by the creator of this game.")); 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(room->getRoomId(), 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); -} +#include "gameselector.h" TabRoom::TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, const QString &_ownName, ServerInfo_Room *info) : Tab(_tabSupervisor), client(_client), roomId(info->getRoomId()), roomName(info->getName()), ownName(_ownName) @@ -132,11 +23,15 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q for (int i = 0; i < gameTypeList.size(); ++i) gameTypes.insert(gameTypeList[i]->getGameTypeId(), gameTypeList[i]->getDescription()); - gameSelector = new GameSelector(client, this); + QMap tempMap; + tempMap.insert(info->getRoomId(), gameTypes); + gameSelector = new GameSelector(client, this, QMap(), tempMap); userList = new UserList(tabSupervisor, client, UserList::RoomList); connect(userList, SIGNAL(openMessageDialog(const QString &, bool)), this, SIGNAL(openMessageDialog(const QString &, bool))); - chatView = new ChatView(ownName); + chatView = new ChatView(ownName, true); + connect(chatView, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString))); + connect(chatView, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString))); sayLabel = new QLabel; sayEdit = new QLineEdit; sayLabel->setBuddy(sayEdit); @@ -153,12 +48,12 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, const Q chatGroupBox = new QGroupBox; chatGroupBox->setLayout(chatVbox); - QVBoxLayout *vbox = new QVBoxLayout; - vbox->addWidget(gameSelector); - vbox->addWidget(chatGroupBox); + QSplitter *splitter = new QSplitter(Qt::Vertical); + splitter->addWidget(gameSelector); + splitter->addWidget(chatGroupBox); QHBoxLayout *hbox = new QHBoxLayout; - hbox->addLayout(vbox, 3); + hbox->addWidget(splitter, 3); hbox->addWidget(userList, 1); aLeaveRoom = new QAction(this); @@ -193,6 +88,11 @@ void TabRoom::retranslateUi() aLeaveRoom->setText(tr("&Leave room")); } +void TabRoom::closeRequest() +{ + actLeaveRoom(); +} + QString TabRoom::sanitizeHtml(QString dirty) const { return dirty @@ -256,5 +156,5 @@ void TabRoom::processLeaveRoomEvent(Event_LeaveRoom *event) void TabRoom::processSayEvent(Event_RoomSay *event) { chatView->appendMessage(event->getPlayerName(), event->getMessage()); - emit userEvent(); + emit userEvent(false); } diff --git a/cockatrice/src/tab_room.h b/cockatrice/src/tab_room.h index 1b0133067..37e6a3d14 100644 --- a/cockatrice/src/tab_room.h +++ b/cockatrice/src/tab_room.h @@ -2,20 +2,16 @@ #define TAB_ROOM_H #include "tab.h" -#include "protocol_datastructures.h" #include +#include class AbstractClient; class UserList; class QLabel; class ChatView; class QLineEdit; -class QTreeView; class QPushButton; class QTextTable; -class QCheckBox; -class GamesModel; -class GamesProxyModel; class RoomEvent; class ServerInfo_Room; class ServerInfo_Game; @@ -24,31 +20,7 @@ class Event_JoinRoom; class Event_LeaveRoom; class Event_RoomSay; class ProtocolResponse; -class TabRoom; - -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; - TabRoom *room; - - QTreeView *gameListView; - GamesModel *gameListModel; - GamesProxyModel *gameListProxyModel; - QPushButton *createButton, *joinButton, *spectateButton; - QCheckBox *showFullGamesCheckBox; -public: - GameSelector(AbstractClient *_client, TabRoom *_room, QWidget *parent = 0); - void retranslateUi(); - void processGameInfo(ServerInfo_Game *info); -}; +class GameSelector; class TabRoom : public Tab { Q_OBJECT @@ -84,6 +56,7 @@ public: TabRoom(TabSupervisor *_tabSupervisor, AbstractClient *_client, const QString &_ownName, ServerInfo_Room *info); ~TabRoom(); void retranslateUi(); + void closeRequest(); void processRoomEvent(RoomEvent *event); int getRoomId() const { return roomId; } const QMap &getGameTypes() const { return gameTypes; } diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index 2d09bb124..824d149d9 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -11,8 +11,60 @@ #include "protocol_items.h" #include "pixmapgenerator.h" #include +#include -TabSupervisor:: TabSupervisor(QWidget *parent) +CloseButton::CloseButton(QWidget *parent) + : QAbstractButton(parent) +{ + setFocusPolicy(Qt::NoFocus); + setCursor(Qt::ArrowCursor); + resize(sizeHint()); +} + +QSize CloseButton::sizeHint() const +{ + ensurePolished(); + int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this); + int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this); + return QSize(width, height); +} + +void CloseButton::enterEvent(QEvent *event) +{ + update(); + QAbstractButton::enterEvent(event); +} + +void CloseButton::leaveEvent(QEvent *event) +{ + update(); + QAbstractButton::leaveEvent(event); +} + +void CloseButton::paintEvent(QPaintEvent * /*event*/) +{ + QPainter p(this); + QStyleOption opt; + opt.init(this); + opt.state |= QStyle::State_AutoRaise; + if (isEnabled() && underMouse() && !isChecked() && !isDown()) + opt.state |= QStyle::State_Raised; + if (isChecked()) + opt.state |= QStyle::State_On; + if (isDown()) + opt.state |= QStyle::State_Sunken; + + if (const QTabBar *tb = qobject_cast(parent())) { + int index = tb->currentIndex(); + QTabBar::ButtonPosition position = (QTabBar::ButtonPosition) style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tb); + if (tb->tabButton(index, position) == this) + opt.state |= QStyle::State_Selected; + } + + style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this); +} + +TabSupervisor::TabSupervisor(QWidget *parent) : QTabWidget(parent), client(0), tabServer(0), tabDeckStorage(0), tabAdmin(0) { tabChangedIcon = new QIcon(":/resources/icon_tab_changed.svg"); @@ -47,17 +99,16 @@ void TabSupervisor::retranslateUi() } } -void TabSupervisor::myAddTab(Tab *tab) +int TabSupervisor::myAddTab(Tab *tab) { - connect(tab, SIGNAL(userEvent()), this, SLOT(tabUserEvent())); - addTab(tab, tab->getTabText()); + connect(tab, SIGNAL(userEvent(bool)), this, SLOT(tabUserEvent(bool))); + return addTab(tab, tab->getTabText()); } -void TabSupervisor::start(AbstractClient *_client, ServerInfo_User *userInfo) +void TabSupervisor::start(AbstractClient *_client, ServerInfo_User *_userInfo) { client = _client; - userName = userInfo->getName(); - userLevel = userInfo->getUserLevel(); + userInfo = new ServerInfo_User(_userInfo); connect(client, SIGNAL(roomEventReceived(RoomEvent *)), this, SLOT(processRoomEvent(RoomEvent *))); connect(client, SIGNAL(gameEventContainerReceived(GameEventContainer *)), this, SLOT(processGameEventContainer(GameEventContainer *))); @@ -83,8 +134,8 @@ void TabSupervisor::start(AbstractClient *_client, ServerInfo_User *userInfo) } else tabDeckStorage = 0; - if (userInfo->getUserLevel() & ServerInfo_User::IsAdmin) { - tabAdmin = new TabAdmin(this, client); + if (userInfo->getUserLevel() & ServerInfo_User::IsModerator) { + tabAdmin = new TabAdmin(this, client, (userInfo->getUserLevel() & ServerInfo_User::IsAdmin)); myAddTab(tabAdmin); } else tabAdmin = 0; @@ -94,6 +145,7 @@ void TabSupervisor::start(AbstractClient *_client, ServerInfo_User *userInfo) void TabSupervisor::startLocal(const QList &_clients) { + userInfo = new ServerInfo_User; localClients = _clients; for (int i = 0; i < localClients.size(); ++i) connect(localClients[i], SIGNAL(gameEventContainerReceived(GameEventContainer *)), this, SLOT(processGameEventContainer(GameEventContainer *))); @@ -140,6 +192,9 @@ void TabSupervisor::stop() while (messageIterator.hasNext()) messageIterator.next().value()->deleteLater(); messageTabs.clear(); + + delete userInfo; + userInfo = 0; } void TabSupervisor::updatePingTime(int value, int max) @@ -152,21 +207,38 @@ void TabSupervisor::updatePingTime(int value, int max) setTabIcon(0, QIcon(PingPixmapGenerator::generatePixmap(15, value, max))); } +void TabSupervisor::closeButtonPressed() +{ + Tab *tab = static_cast(static_cast(sender())->property("tab").value()); + tab->closeRequest(); +} + +void TabSupervisor::addCloseButtonToTab(Tab *tab, int tabIndex) +{ + QTabBar::ButtonPosition closeSide = (QTabBar::ButtonPosition) tabBar()->style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tabBar()); + CloseButton *closeButton = new CloseButton; + connect(closeButton, SIGNAL(clicked()), this, SLOT(closeButtonPressed())); + closeButton->setProperty("tab", qVariantFromValue((QObject *) tab)); + tabBar()->setTabButton(tabIndex, closeSide, closeButton); +} + void TabSupervisor::gameJoined(Event_GameJoined *event) { - TabGame *tab = new TabGame(this, QList() << client, event->getGameId(), event->getGameDescription(), event->getPlayerId(), event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming()); + TabGame *tab = new TabGame(this, QList() << client, event->getGameId(), event->getGameDescription(), event->getPlayerId(), userInfo, event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming()); connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *))); connect(tab, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool))); - myAddTab(tab); + int tabIndex = myAddTab(tab); + addCloseButtonToTab(tab, tabIndex); gameTabs.insert(event->getGameId(), tab); setCurrentWidget(tab); } void TabSupervisor::localGameJoined(Event_GameJoined *event) { - TabGame *tab = new TabGame(this, localClients, event->getGameId(), event->getGameDescription(), event->getPlayerId(), event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming()); + TabGame *tab = new TabGame(this, localClients, event->getGameId(), event->getGameDescription(), event->getPlayerId(), userInfo, event->getSpectator(), event->getSpectatorsCanTalk(), event->getSpectatorsSeeEverything(), event->getResuming()); connect(tab, SIGNAL(gameClosing(TabGame *)), this, SLOT(gameLeft(TabGame *))); - myAddTab(tab); + int tabIndex = myAddTab(tab); + addCloseButtonToTab(tab, tabIndex); gameTabs.insert(event->getGameId(), tab); setCurrentWidget(tab); @@ -189,10 +261,11 @@ void TabSupervisor::gameLeft(TabGame *tab) void TabSupervisor::addRoomTab(ServerInfo_Room *info, bool setCurrent) { - TabRoom *tab = new TabRoom(this, client, userName, info); + TabRoom *tab = new TabRoom(this, client, userInfo->getName(), info); connect(tab, SIGNAL(roomClosing(TabRoom *)), this, SLOT(roomLeft(TabRoom *))); connect(tab, SIGNAL(openMessageDialog(const QString &, bool)), this, SLOT(addMessageTab(const QString &, bool))); - myAddTab(tab); + int tabIndex = myAddTab(tab); + addCloseButtonToTab(tab, tabIndex); roomTabs.insert(info->getRoomId(), tab); if (setCurrent) setCurrentWidget(tab); @@ -208,12 +281,13 @@ void TabSupervisor::roomLeft(TabRoom *tab) TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus) { - if (receiverName == userName) + if (receiverName == userInfo->getName()) return 0; - TabMessage *tab = new TabMessage(this, client, userName, receiverName); + TabMessage *tab = new TabMessage(this, client, userInfo->getName(), receiverName); connect(tab, SIGNAL(talkClosing(TabMessage *)), this, SLOT(talkLeft(TabMessage *))); - myAddTab(tab); + int tabIndex = myAddTab(tab); + addCloseButtonToTab(tab, tabIndex); messageTabs.insert(receiverName, tab); if (focus) setCurrentWidget(tab); @@ -228,14 +302,15 @@ void TabSupervisor::talkLeft(TabMessage *tab) removeTab(indexOf(tab)); } -void TabSupervisor::tabUserEvent() +void TabSupervisor::tabUserEvent(bool globalEvent) { Tab *tab = static_cast(sender()); if (tab != currentWidget()) { tab->setContentsChanged(true); setTabIcon(indexOf(tab), *tabChangedIcon); } - QApplication::alert(this); + if (globalEvent) + QApplication::alert(this); } void TabSupervisor::processRoomEvent(RoomEvent *event) @@ -300,3 +375,8 @@ bool TabSupervisor::getAdminLocked() const return true; return tabAdmin->getLocked(); } + +int TabSupervisor::getUserLevel() const +{ + return userInfo->getUserLevel(); +} diff --git a/cockatrice/src/tab_supervisor.h b/cockatrice/src/tab_supervisor.h index 087d93270..0a38d5f83 100644 --- a/cockatrice/src/tab_supervisor.h +++ b/cockatrice/src/tab_supervisor.h @@ -3,6 +3,7 @@ #include #include +#include class QMenu; class AbstractClient; @@ -21,11 +22,22 @@ class Event_Message; class ServerInfo_Room; class ServerInfo_User; +class CloseButton : public QAbstractButton { + Q_OBJECT +public: + CloseButton(QWidget *parent = 0); + QSize sizeHint() const; + inline QSize minimumSizeHint() const { return sizeHint(); } +protected: + void enterEvent(QEvent *event); + void leaveEvent(QEvent *event); + void paintEvent(QPaintEvent *event); +}; + class TabSupervisor : public QTabWidget { Q_OBJECT private: - QString userName; - int userLevel; + ServerInfo_User *userInfo; QIcon *tabChangedIcon; AbstractClient *client; QList localClients; @@ -36,7 +48,8 @@ private: QMap roomTabs; QMap gameTabs; QMap messageTabs; - void myAddTab(Tab *tab); + int myAddTab(Tab *tab); + void addCloseButtonToTab(Tab *tab, int tabIndex); public: TabSupervisor(QWidget *parent = 0); ~TabSupervisor(); @@ -47,11 +60,12 @@ public: int getGameCount() const { return gameTabs.size(); } TabUserLists *getUserListsTab() const { return tabUserLists; } bool getAdminLocked() const; - int getUserLevel() const { return userLevel; } + int getUserLevel() const; signals: void setMenu(QMenu *menu); void localGameEnded(); private slots: + void closeButtonPressed(); void updateCurrent(int index); void updatePingTime(int value, int max); void gameJoined(Event_GameJoined *event); @@ -63,7 +77,7 @@ private slots: void processUserLeft(const QString &userName); void processUserJoined(const QString &userName); void talkLeft(TabMessage *tab); - void tabUserEvent(); + void tabUserEvent(bool globalEvent); void processRoomEvent(RoomEvent *event); void processGameEventContainer(GameEventContainer *cont); void processMessageEvent(Event_Message *event); diff --git a/cockatrice/src/userinfobox.cpp b/cockatrice/src/userinfobox.cpp index 40b4b0126..53b319c09 100644 --- a/cockatrice/src/userinfobox.cpp +++ b/cockatrice/src/userinfobox.cpp @@ -17,6 +17,8 @@ UserInfoBox::UserInfoBox(AbstractClient *_client, bool _fullInfo, QWidget *paren nameLabel->setFont(nameFont); realNameLabel1 = new QLabel; realNameLabel2 = new QLabel; + genderLabel1 = new QLabel; + genderLabel2 = new QLabel; countryLabel1 = new QLabel; countryLabel2 = new QLabel; userLevelLabel1 = new QLabel; @@ -28,11 +30,13 @@ UserInfoBox::UserInfoBox(AbstractClient *_client, bool _fullInfo, QWidget *paren 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->addWidget(genderLabel1, 3, 0, 1, 1); + mainLayout->addWidget(genderLabel2, 3, 1, 1, 2); + mainLayout->addWidget(countryLabel1, 4, 0, 1, 1); + mainLayout->addWidget(countryLabel2, 4, 1, 1, 2); + mainLayout->addWidget(userLevelLabel1, 5, 0, 1, 1); + mainLayout->addWidget(userLevelLabel2, 5, 1, 1, 1); + mainLayout->addWidget(userLevelLabel3, 5, 2, 1, 1); mainLayout->setColumnStretch(2, 10); setWindowTitle(tr("User information")); @@ -43,6 +47,7 @@ UserInfoBox::UserInfoBox(AbstractClient *_client, bool _fullInfo, QWidget *paren void UserInfoBox::retranslateUi() { realNameLabel1->setText(tr("Real name:")); + genderLabel1->setText(tr("Gender:")); countryLabel1->setText(tr("Location:")); userLevelLabel1->setText(tr("User level:")); } @@ -58,13 +63,14 @@ void UserInfoBox::updateInfo(ServerInfo_User *user) nameLabel->setText(user->getName()); realNameLabel2->setText(user->getRealName()); + genderLabel2->setPixmap(GenderPixmapGenerator::generatePixmap(15, user->getGender())); 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::IsModerator) + userLevelText = tr("Moderator"); else if (userLevel & ServerInfo_User::IsRegistered) userLevelText = tr("Registered user"); else diff --git a/cockatrice/src/userinfobox.h b/cockatrice/src/userinfobox.h index adf5f832c..ee4fd6043 100644 --- a/cockatrice/src/userinfobox.h +++ b/cockatrice/src/userinfobox.h @@ -13,7 +13,7 @@ class UserInfoBox : public QWidget { private: AbstractClient *client; bool fullInfo; - QLabel *avatarLabel, *nameLabel, *realNameLabel1, *realNameLabel2, *countryLabel1, *countryLabel2, *userLevelLabel1, *userLevelLabel2, *userLevelLabel3; + QLabel *avatarLabel, *nameLabel, *realNameLabel1, *realNameLabel2, *genderLabel1, *genderLabel2, *countryLabel1, *countryLabel2, *userLevelLabel1, *userLevelLabel2, *userLevelLabel3; public: UserInfoBox(AbstractClient *_client, bool fullInfo, QWidget *parent = 0, Qt::WindowFlags flags = 0); void retranslateUi(); diff --git a/cockatrice/src/userlist.cpp b/cockatrice/src/userlist.cpp index b63c68054..71101f481 100644 --- a/cockatrice/src/userlist.cpp +++ b/cockatrice/src/userlist.cpp @@ -5,11 +5,59 @@ #include "pixmapgenerator.h" #include "userinfobox.h" #include "protocol_items.h" +#include "gameselector.h" #include #include #include #include #include +#include +#include +#include +#include +#include + +BanDialog::BanDialog(QWidget *parent) + : QDialog(parent) +{ + QLabel *durationLabel = new QLabel(tr("Please enter the duration of the ban (in minutes).\nEnter 0 for an indefinite ban.")); + durationEdit = new QSpinBox; + durationEdit->setMinimum(0); + durationEdit->setValue(5); + QLabel *reasonLabel = new QLabel(tr("Please enter the reason for the ban.\nThis is only saved for moderators and cannot be seen by the banned person.")); + reasonEdit = new QPlainTextEdit; + + QPushButton *okButton = new QPushButton(tr("&OK")); + okButton->setAutoDefault(true); + connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); + QPushButton *cancelButton = new QPushButton(tr("&Cancel")); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout; + buttonLayout->addStretch(); + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); + + QVBoxLayout *vbox = new QVBoxLayout; + vbox->addWidget(durationLabel); + vbox->addWidget(durationEdit); + vbox->addWidget(reasonLabel); + vbox->addWidget(reasonEdit); + vbox->addLayout(buttonLayout); + + setLayout(vbox); + setWindowTitle(tr("Ban user from server")); +} + +int BanDialog::getMinutes() const +{ + return durationEdit->value(); +} + +QString BanDialog::getReason() const +{ + return reasonEdit->toPlainText(); +} UserListItemDelegate::UserListItemDelegate(QObject *const parent) : QStyledItemDelegate(parent) @@ -59,6 +107,7 @@ UserList::UserList(TabSupervisor *_tabSupervisor, AbstractClient *_client, UserL userTree->setRootIsDecorated(false); userTree->setIconSize(QSize(20, 12)); userTree->setItemDelegate(itemDelegate); + userTree->setAlternatingRowColors(true); connect(userTree, SIGNAL(itemActivated(QTreeWidgetItem *, int)), this, SLOT(userClicked(QTreeWidgetItem *, int))); QVBoxLayout *vbox = new QVBoxLayout; @@ -163,6 +212,35 @@ void UserList::userClicked(QTreeWidgetItem *item, int /*column*/) emit openMessageDialog(item->data(2, Qt::UserRole).toString(), true); } +void UserList::gamesOfUserReceived(ProtocolResponse *resp) +{ + Command_GetGamesOfUser *command = static_cast(sender()); + Response_GetGamesOfUser *response = qobject_cast(resp); + if (!response) + return; + + QMap gameTypeMap; + QMap roomMap; + const QList roomList = response->getRoomList(); + for (int i = 0; i < roomList.size(); ++i) { + roomMap.insert(roomList[i]->getRoomId(), roomList[i]->getName()); + const QList gameTypeList = roomList[i]->getGameTypeList(); + GameTypeMap tempMap; + for (int j = 0; j < gameTypeList.size(); ++j) + tempMap.insert(gameTypeList[j]->getGameTypeId(), gameTypeList[j]->getDescription()); + gameTypeMap.insert(roomList[i]->getRoomId(), tempMap); + } + + GameSelector *selector = new GameSelector(client, 0, roomMap, gameTypeMap); + const QList gameList = response->getGameList(); + for (int i = 0; i < gameList.size(); ++i) + selector->processGameInfo(gameList[i]); + + selector->setWindowTitle(tr("%1's games").arg(command->getUserName())); + selector->setAttribute(Qt::WA_DeleteOnClose); + selector->show(); +} + void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index) { const QString &userName = index.sibling(index.row(), 2).data(Qt::UserRole).toString(); @@ -172,6 +250,7 @@ void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index) aUserName->setEnabled(false); QAction *aDetails = new QAction(tr("User &details"), this); QAction *aChat = new QAction(tr("Direct &chat"), this); + QAction *aShowGames = new QAction(tr("Show this user's &games"), this); QAction *aAddToBuddyList = new QAction(tr("Add to &buddy list"), this); QAction *aRemoveFromBuddyList = new QAction(tr("Remove from &buddy list"), this); QAction *aAddToIgnoreList = new QAction(tr("Add to &ignore list"), this); @@ -182,6 +261,7 @@ void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index) menu->addAction(aUserName); menu->addSeparator(); menu->addAction(aDetails); + menu->addAction(aShowGames); menu->addAction(aChat); if ((userLevel & ServerInfo_User::IsRegistered) && (tabSupervisor->getUserLevel() & ServerInfo_User::IsRegistered)) { menu->addSeparator(); @@ -210,14 +290,18 @@ void UserList::showContextMenu(const QPoint &pos, const QModelIndex &index) client->sendCommand(new Command_AddToList("buddy", userName)); else if (actionClicked == aRemoveFromBuddyList) client->sendCommand(new Command_RemoveFromList("buddy", userName)); - else if (actionClicked == aAddToIgnoreList) + else if (actionClicked == aShowGames) { + Command *cmd = new Command_GetGamesOfUser(userName); + connect(cmd, SIGNAL(finished(ProtocolResponse *)), this, SLOT(gamesOfUserReceived(ProtocolResponse *))); + client->sendCommand(cmd); + } else if (actionClicked == aAddToIgnoreList) client->sendCommand(new Command_AddToList("ignore", userName)); else if (actionClicked == aRemoveFromIgnoreList) client->sendCommand(new Command_RemoveFromList("ignore", userName)); else if (actionClicked == aBan) { - bool ok; - int minutes = QInputDialog::getInt(this, tr("Duration"), tr("Please enter the duration of the ban (in minutes).\nEnter 0 for an indefinite ban."), 0, 0, 2147483647, 10, &ok); - client->sendCommand(new Command_BanFromServer(userName, minutes)); + BanDialog dlg(this); + if (dlg.exec()) + client->sendCommand(new Command_BanFromServer(userName, dlg.getMinutes(), dlg.getReason())); } delete menu; diff --git a/cockatrice/src/userlist.h b/cockatrice/src/userlist.h index a611bf5de..c71ddc31e 100644 --- a/cockatrice/src/userlist.h +++ b/cockatrice/src/userlist.h @@ -1,6 +1,7 @@ #ifndef USERLIST_H #define USERLIST_H +#include #include #include #include @@ -9,6 +10,20 @@ class QTreeWidget; class ServerInfo_User; class AbstractClient; class TabSupervisor; +class QSpinBox; +class QPlainTextEdit; +class ProtocolResponse; + +class BanDialog : public QDialog { + Q_OBJECT +private: + QSpinBox *durationEdit; + QPlainTextEdit *reasonEdit; +public: + BanDialog(QWidget *parent = 0); + int getMinutes() const; + QString getReason() const; +}; class UserListItemDelegate : public QStyledItemDelegate { public: @@ -38,6 +53,7 @@ private: void setUserOnline(QTreeWidgetItem *user, bool online); private slots: void userClicked(QTreeWidgetItem *item, int column); + void gamesOfUserReceived(ProtocolResponse *resp); signals: void openMessageDialog(const QString &userName, bool focus); void addBuddy(const QString &userName); diff --git a/cockatrice/src/window_deckeditor.cpp b/cockatrice/src/window_deckeditor.cpp index 2822df52d..acb3bf541 100644 --- a/cockatrice/src/window_deckeditor.cpp +++ b/cockatrice/src/window_deckeditor.cpp @@ -26,6 +26,7 @@ #include "dlg_load_deck_from_clipboard.h" #include "main.h" #include "settingscache.h" +#include "priceupdater.h" void SearchLineEdit::keyPressEvent(QKeyEvent *event) { @@ -68,6 +69,7 @@ WndDeckEditor::WndDeckEditor(QWidget *parent) databaseView = new QTreeView(); databaseView->setModel(databaseDisplayModel); databaseView->setUniformRowHeights(true); + databaseView->setRootIsDecorated(false); databaseView->setAlternatingRowColors(true); databaseView->setSortingEnabled(true); databaseView->sortByColumn(0, Qt::AscendingOrder); @@ -112,15 +114,37 @@ WndDeckEditor::WndDeckEditor(QWidget *parent) commentsEdit->setMaximumHeight(70); commentsLabel->setBuddy(commentsEdit); connect(commentsEdit, SIGNAL(textChanged()), this, SLOT(updateComments())); + QGridLayout *grid = new QGridLayout; grid->addWidget(nameLabel, 0, 0); grid->addWidget(nameEdit, 0, 1); + grid->addWidget(commentsLabel, 1, 0); grid->addWidget(commentsEdit, 1, 1); + // Update price + aUpdatePrices = new QAction(tr("&Update prices"), this); + aUpdatePrices->setShortcut(tr("Ctrl+U")); + aUpdatePrices->setIcon(QIcon(":/resources/icon_update.png")); + connect(aUpdatePrices, SIGNAL(triggered()), this, SLOT(actUpdatePrices())); + if (!settingsCache->getPriceTagFeature()) + aUpdatePrices->setVisible(false); + + QToolBar *deckToolBar = new QToolBar; + deckToolBar->setOrientation(Qt::Vertical); + deckToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + deckToolBar->setIconSize(QSize(24, 24)); + deckToolBar->addAction(aUpdatePrices); + QHBoxLayout *deckToolbarLayout = new QHBoxLayout; + deckToolbarLayout->addStretch(); + deckToolbarLayout->addWidget(deckToolBar); + deckToolbarLayout->addStretch(); + + QVBoxLayout *rightFrame = new QVBoxLayout; rightFrame->addLayout(grid); rightFrame->addWidget(deckView); + rightFrame->addLayout(deckToolbarLayout); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addLayout(leftFrame, 10); @@ -456,6 +480,21 @@ void WndDeckEditor::actDecrement() setWindowModified(true); } +void WndDeckEditor::actUpdatePrices() +{ + aUpdatePrices->setDisabled(true); + PriceUpdater *up = new PriceUpdater(deckModel->getDeckList()); + connect(up, SIGNAL(finishedUpdate()), this, SLOT(finishedUpdatingPrices())); + up->updatePrices(); +} + +void WndDeckEditor::finishedUpdatingPrices() +{ + deckModel->pricesUpdated(); + setWindowModified(true); + aUpdatePrices->setDisabled(false); +} + void WndDeckEditor::setDeck(DeckList *_deck, const QString &_lastFileName, DeckList::FileFormat _lastFileFormat) { deckModel->setDeckList(_deck); diff --git a/cockatrice/src/window_deckeditor.h b/cockatrice/src/window_deckeditor.h index e14c16331..92a90bb99 100644 --- a/cockatrice/src/window_deckeditor.h +++ b/cockatrice/src/window_deckeditor.h @@ -52,6 +52,9 @@ private slots: void actRemoveCard(); void actIncrement(); void actDecrement(); + void actUpdatePrices(); + + void finishedUpdatingPrices(); private: void addCardHelper(const QString &zoneName); void recursiveExpand(const QModelIndex &index); @@ -74,7 +77,7 @@ private: QMenu *deckMenu, *dbMenu; QAction *aNewDeck, *aLoadDeck, *aSaveDeck, *aSaveDeckAs, *aLoadDeckFromClipboard, *aSaveDeckToClipboard, *aPrintDeck, *aClose; QAction *aEditSets, *aSearch, *aClearSearch; - QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement; + QAction *aAddCard, *aAddCardToSideboard, *aRemoveCard, *aIncrement, *aDecrement, *aUpdatePrices; public: WndDeckEditor(QWidget *parent = 0); ~WndDeckEditor(); diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index df1fedbc4..7acbe5510 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -56,11 +56,18 @@ void MainWindow::processConnectionClosedEvent(Event_ConnectionClosed *event) reasonStr = tr("There are too many concurrent connections from your address."); else if (reason == "banned") reasonStr = tr("Banned by moderator."); + else if (reason == "server_shutdown") + reasonStr = tr("Scheduled server shutdown."); else reasonStr = tr("Unknown reason."); QMessageBox::critical(this, tr("Connection closed"), tr("The server has terminated your connection.\nReason: %1").arg(reasonStr)); } +void MainWindow::processServerShutdownEvent(Event_ServerShutdown *event) +{ + QMessageBox::information(this, tr("Scheduled server shutdown"), tr("The server is going to be restarted in %n minute(s).\nAll running games will be lost.\nReason for shutdown: %1", "", event->getMinutes()).arg(event->getReason())); +} + void MainWindow::statusChanged(ClientStatus _status) { setClientStatusTitle(); @@ -178,6 +185,8 @@ void MainWindow::actAbout() + tr("French:") + " Yannick Hammer, Arnaud Faes
" + tr("Japanese:") + " Nagase Task
" + tr("Russian:") + " Alexander Davidov
" + + tr("Czech:") + " Ondřej Trhoň
" + + tr("Slovak:") + " Ganjalf Rendy
" )); } @@ -288,6 +297,7 @@ MainWindow::MainWindow(QWidget *parent) client = new RemoteClient(this); connect(client, SIGNAL(connectionClosedEventReceived(Event_ConnectionClosed *)), this, SLOT(processConnectionClosedEvent(Event_ConnectionClosed *))); + connect(client, SIGNAL(serverShutdownEventReceived(Event_ServerShutdown *)), this, SLOT(processServerShutdownEvent(Event_ServerShutdown *))); connect(client, SIGNAL(serverError(ResponseCode)), this, SLOT(serverError(ResponseCode))); connect(client, SIGNAL(socketError(const QString &)), this, SLOT(socketError(const QString &))); connect(client, SIGNAL(serverTimeout()), this, SLOT(serverTimeout())); diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index 9ca62ba84..4d8b45d60 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -36,6 +36,7 @@ private slots: void updateTabMenu(QMenu *menu); void statusChanged(ClientStatus _status); void processConnectionClosedEvent(Event_ConnectionClosed *event); + void processServerShutdownEvent(Event_ServerShutdown *event); void serverTimeout(); void serverError(ResponseCode r); void socketError(const QString &errorStr); diff --git a/cockatrice/translations/cockatrice_cs.ts b/cockatrice/translations/cockatrice_cs.ts new file mode 100644 index 000000000..61567e4fb --- /dev/null +++ b/cockatrice/translations/cockatrice_cs.ts @@ -0,0 +1,4423 @@ + + + + + AbstractCounter + + + &Set counter... + &Nastavit žeton... + + + + Ctrl+L + Ctrl+L + + + + F11 + F11 + + + + F12 + F12 + + + + Set counter + Nastavit žeton + + + + New value for counter '%1': + Nová hodnota pro žeton '%1': + + + + AppearanceSettingsPage + + + Zone background pictures + Pozadí zón + + + + Path to hand background: + Cesta k pozadí ruky: + + + + Path to stack background: + Cesta k pozadí stacku: + + + + Path to table background: + Cesta k pozadí stolu: + + + + Path to player info background: + Cesta k pozadí informací o uživateli: + + + + Path to picture of card back: + Cesta k rubu karet: + + + + Card rendering + Vykreslování karet + + + + Display card names on cards having a picture + Zobrazit jména karet na kartách s obrázky + + + + Hand layout + Rozvržení ruky + + + + Display hand horizontally (wastes space) + Zobrazit ruku horizontálně (zabírá více místa) + + + + Table grid layout + Rozložení herní mřížky + + + + Invert vertical coordinate + Převrátit vertikální souřadnice + + + + Minimum player count for multi-column layout: + + + + + Zone view layout + Rozvržení zón + + + + Sort by name + Seřadit dle jména + + + + Sort by type + Seřadit dle typu + + + + + + + + Choose path + Vyberte cestu + + + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Vložte dobu trvání banu (v minutách). +Hodnota 0 je pro ban bez omezení. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + &OK + + + + &Cancel + + + + + Ban user from server + + + + + CardDatabaseModel + + + Name + Jméno + + + + Sets + Sady + + + + Mana cost + Sesílací cena + + + + Card type + Typ karty + + + + P/T + S/O + + + + CardInfoWidget + + + Hide card info + Skrýt informace o kartě + + + + Show card only + Zobrazit pouze kartu + + + + Show text only + Zobrazit pouze text + + + + Show full info + Zobrazit všechny informace + + + + Name: + Jméno: + + + + Mana cost: + Sesílací cena: + + + + Card type: + Typ karty: + + + + P / T: + S / O: + + + + CardItem + + + &Play + &Zahrát + + + + &Hide + &Skrýt + + + + &Tap + &Tapnout + + + + &Untap + &Odtapnout + + + + Toggle &normal untapping + Přepnout &normální odtapnutí + + + + &Flip + &Otočit + + + + &Clone + &Zdvojit + + + + Ctrl+H + Ctrl+H + + + + &Attach to card... + Připojit ke k&artě... + + + + Ctrl+A + Ctrl+A + + + + Unattac&h + Od&pojit + + + + &Draw arrow... + + + + + &Power / toughness + &Síla / odolnost + + + + &Increase power + &Zvýšit sílu + + + + Ctrl++ + Ctrl++ + + + + &Decrease power + &Snížit sílu + + + + Ctrl+- + Ctrl+- + + + + I&ncrease toughness + &Zvýšit odolnost + + + + Alt++ + Alt++ + + + + D&ecrease toughness + &Snížit sílu + + + + Alt+- + Alt+- + + + + In&crease power and toughness + &Zvýšit sílu a odolnost + + + + Ctrl+Alt++ + Ctrl+Alt++ + + + + Dec&rease power and toughness + &Snížit sílu a odolnost + + + + Ctrl+Alt+- + Ctrl+Alt+- + + + + Set &power and toughness... + Nastavit &sílu a odolnost... + + + + Ctrl+P + Ctrl+P + + + + &Set annotation... + Na&stavit poznámku... + + + + red + červená + + + + yellow + žlutá + + + + green + zelená + + + + &Add counter (%1) + Přid&at žeton (%1) + + + + &Remove counter (%1) + Odst&ranit žeton (%1) + + + + &Set counters (%1)... + Na&stavit žetony (%1)... + + + + &top of library + &vršek knihovny + + + + &bottom of library + &spodek knihovny + + + + &graveyard + &hřbitov + + + + Ctrl+Del + Ctrl+Del + + + + &exile + &exilnout + + + + &Move to + &Přesunout + + + + CardZone + + his hand + nominative + jeho ruka + + + %1's hand + nominative + ruka hráče %1 + + + of his hand + genitive + jeho ruky + + + of %1's hand + genitive + ruky hráče %1 + + + his hand + accusative + jeho ruka + + + %1's hand + accusative + ruka hráče %1 + + + his library + nominative + knihovna + + + %1's library + nominative + knihovna hráče %1 + + + of his library + genitive + jeho knihovny + + + of %1's library + genitive + knihovny hráče %1 + + + his library + accusative + knihovnu + + + %1's library + accusative + knihovna hráče %1 + + + his graveyard + nominative + jeho hřbitov + + + %1's graveyard + nominative + hřbitov hráče %1 + + + of his graveyard + genitive + jeho hřbitova + + + of %1's graveyard + genitive + hřbitova hráče %1 + + + his graveyard + accusative + jeho hřbitov + + + %1's graveyard + accusative + hřbitov hráče %1 + + + his exile + nominative + jeho exilnuté karty + + + %1's exile + nominative + exilnuté karty hráče %1 + + + of his exile + genitive + exilnutých karet + + + of %1's exile + genitive + exilnutých karet hráče %1 + + + his exile + accusative + jeho exilnuté karty + + + %1's exile + accusative + exilnuté karty hráče %1 + + + his sideboard + nominative + jeho sideboard + + + %1's sideboard + nominative + sideboard hráče %1 + + + of his sideboard + genitive + sideboardu hráče + + + of %1's sideboard + genitive + sideboardu hráče %1 + + + his sideboard + accusative + jeho sideboard + + + %1's sideboard + accusative + sideboard hráče %1 + + + + her hand + nominative, female owner + + + + + %1's hand + nominative, female owner + ruka hráče %1 + + + + his hand + nominative, male owner + jeho ruka + + + + %1's hand + nominative, male owner + ruka hráče %1 + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + ruky hráče %1 + + + + of his hand + genitive, male owner + jeho ruky + + + + of %1's hand + genitive, male owner + ruky hráče %1 + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + ruka hráče %1 + + + + his hand + accusative, male owner + jeho ruka + + + + %1's hand + accusative, male owner + ruka hráče %1 + + + + her library + nominative, female owner + + + + + %1's library + nominative, female owner + knihovna hráče %1 + + + + his library + nominative, male owner + + + + + %1's library + nominative, male owner + knihovna hráče %1 + + + + of her library + genitive, female owner + + + + + of %1's library + genitive, female owner + knihovny hráče %1 + + + + of his library + genitive, male owner + jeho knihovny + + + + of %1's library + genitive, male owner + knihovny hráče %1 + + + + her library + accusative, female owner + + + + + %1's library + accusative, female owner + knihovna hráče %1 + + + + his library + accusative, male owner + + + + + %1's library + accusative, male owner + knihovna hráče %1 + + + + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + hřbitov hráče %1 + + + + his graveyard + nominative, male owner + jeho hřbitov + + + + %1's graveyard + nominative, male owner + hřbitov hráče %1 + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + hřbitova hráče %1 + + + + of his graveyard + genitive, male owner + jeho hřbitova + + + + of %1's graveyard + genitive, male owner + hřbitova hráče %1 + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + hřbitov hráče %1 + + + + his graveyard + accusative, male owner + jeho hřbitov + + + + %1's graveyard + accusative, male owner + hřbitov hráče %1 + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + exilnuté karty hráče %1 + + + + his exile + nominative, male owner + jeho exilnuté karty + + + + %1's exile + nominative, male owner + exilnuté karty hráče %1 + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + exilnutých karet hráče %1 + + + + of his exile + genitive, male owner + exilnutých karet + + + + of %1's exile + genitive, male owner + exilnutých karet hráče %1 + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + exilnuté karty hráče %1 + + + + his exile + accusative, male owner + jeho exilnuté karty + + + + %1's exile + accusative, male owner + exilnuté karty hráče %1 + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + sideboard hráče %1 + + + + his sideboard + nominative, male owner + jeho sideboard + + + + %1's sideboard + nominative, male owner + sideboard hráče %1 + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + sideboardu hráče %1 + + + + of his sideboard + genitive, male owner + sideboardu hráče + + + + of %1's sideboard + genitive, male owner + sideboardu hráče %1 + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + sideboard hráče %1 + + + + his sideboard + accusative, male owner + jeho sideboard + + + + %1's sideboard + accusative, male owner + sideboard hráče %1 + + + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + &Povolit zobrazovaní cen (použijí se data z blacklotusproject.com) + + + + General + Obecné + + + + DeckListModel + + + Number + Počet + + + + Card + Karta + + + + Price + Cena + + + + DeckViewContainer + + + Load &local deck + Nahrát &lokální balíček + + + + Load d&eck from server + Nahrát &balíček ze serveru + + + + Ready to s&tart + Připraven ke &hře + + + + Load deck + Nahrát balíček + + + + DlgCardSearch + + + Card name: + Jméno karty: + + + + Card text: + Text karty: + + + + Card type (OR): + Typ karty (NEBO): + + + + Color (OR): + Barva (NEBO): + + + + O&K + O&K + + + + &Cancel + &Cancel + + + + Card search + Hledat kartu + + + + DlgConnect + + + &Host: + &Hostitel: + + + + &Port: + &Port: + + + + Player &name: + Jméno &hráče: + + + + P&assword: + H&eslo: + + + + &OK + &OK + + + + &Cancel + &Zrušit + + + + Connect to server + Připojit k serveru + + + + DlgCreateGame + + + &Description: + &Popis: + + + + P&layers: + H&ráči: + + + + Game type + Formát + + + + &Password: + &Heslo: + + + + Only &buddies can join + Jen pro &přátele + + + + Only &registered users can join + Jen pro &registrované + + + + Joining restrictions + Omezení připojení + + + + &Spectators allowed + &Diváci povoleni + + + + Spectators &need a password to join + Diváci &musí znát heslo + + + + Spectators can &chat + Diváci mohou &chatovat + + + + Spectators see &everything + Diváci vidí &všechno + + + + Spectators + Diváci + + + + &OK + &OK + + + + &Cancel + &Zrušit + + + + Create game + Vytvořit hru + + + + Error + Chyba + + + + Server error. + Chyba serveru. + + + + DlgCreateToken + + + &Name: + &Jméno: + + + + Token + Token + + + + C&olor: + B&arva: + + + + white + bílá + + + + blue + modrá + + + + black + černá + + + + red + červená + + + + green + zelená + + + + multicolor + multicolor + + + + colorless + bezbarvý + + + + &P/T: + &S/O: + + + + &Annotation: + &Poznámka: + + + + &Destroy token when it leaves the table + &Token se při odchodu z bojiště zničí + + + + &OK + &OK + + + + &Cancel + &Zrušit + + + + Create token + Vytvořit token + + + + DlgLoadDeckFromClipboard + + + &Refresh + &Obnovit + + + + &OK + &OK + + + + &Cancel + &Zrušit + + + + Load deck from clipboard + Nahrát balíček ze schránky + + + + Error + Chyba + + + + Invalid deck list. + Neplatný formát balíčku. + + + + DlgLoadRemoteDeck + + + O&K + O&K + + + + &Cancel + &Zrušit + + + + Load deck + Nahrát balíček + + + + DlgSettings + + + + + Error + Chyba + + + + Your card database is invalid. Would you like to go back and set the correct path? + Cesta k databázi je neplatná. Chcete se vrátit a nastavit správnou? + + + + The path to your deck directory is invalid. Would you like to go back and set the correct path? + Cesta k adresáři s balíčky je neplatná. Chcete se vrátit a nastavit správnou? + + + + The path to your card pictures directory is invalid. Would you like to go back and set the correct path? + Cesta k adresáři s obrázky je neplatná. Chcete se vrátit a nastavit správnou? + + + + Settings + Nastavení + + + + General + Obecné + + + + Appearance + Vzhled + + + + User interface + Uživatelské rozhraní + + + + Deck editor + Editor balíčků + + + + Messages + Zprávy + + + + &Close + &Zavřít + + + + GameSelector + + + + + + + + + + Error + Chyba + + + + Please join the appropriate room first. + + + + + Wrong password. + Špatné heslo. + + + + Spectators are not allowed in this game. + Do této hry je divákům přístup zakázán. + + + + The game is already full. + Hra je plná. + + + + The game does not exist any more. + Hra již neexistuje. + + + + This game is only open to registered users. + Hra je určena jen pro registrované. + + + + This game is only open to its creator's buddies. + Hra je dostupná jen pro přátele zakládajícícho. + + + + You are being ignored by the creator of this game. + Zakladatel hry vás ignoruje. + + + + Join game + Připojit ke hře + + + + Password: + Heslo: + + + + Games + Hry + + + + Show &full games + Ukázat &plné hry + + + + Show &running games + + + + + C&reate + V&ytvořit + + + + &Join + &Připojit + + + + J&oin as spectator + P&řipojit se jako divák + + + + GameView + + + Esc + Esc + + + + GamesModel + + + yes + ano + + + + yes, free for spectators + diváci povoleni + + + + no + ne + + + + buddies only + jen pro přátele + + + + reg. users only + jen pro registrované + + + + not allowed + nepovolené + + + + Room + Místnost + + + + Description + Popis + + + + Creator + Zakladatel + + + + Game type + Formát + + + + Password + Heslo + + + + Restrictions + Omezení + + + + Players + Hráči + + + + Spectators + Diváci + + + + GeneralSettingsPage + + + + English + Česky + + + + + + Choose path + Vyberte cestu + + + + Personal settings + Osobní nastavení + + + + Language: + Jazyk: + + + + Download card pictures on the fly + Stahovat obrázky karet za běhu + + + + Paths + Cesty + + + + Decks directory: + Adresář s balíčky: + + + + Pictures directory: + Adresář s obrázky: + + + + Path to card database: + Karetní databáze: + + + + MainWindow + + + There are too many concurrent connections from your address. + Z vaší adresy jde mnoho současných připojení. + + + + Banned by moderator. + Zabanován moderátorem. + + + + Scheduled server shutdown. + + + + + Unknown reason. + Neznámý důvod. + + + + Connection closed + Připojení uzavřeno + + + + The server has terminated your connection. +Reason: %1 + Server přerušil spojení. +Důvod: %1 + + + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + + + Number of players + Počet hráčů + + + + Please enter the number of players. + Vložte počet hráčů. + + + + + Player %1 + Hráč %1 + + + + About Cockatrice + O Cockatrice + + + + Version %1 + Verze %1 + + + + Authors: + Autoři: + + + + Translators: + Překlad: + + + + Spanish: + Španělština: + + + + Portugese (Portugal): + Portugalština (Portugalsko): + + + + Portugese (Brazil): + Portugalština (Brazílie): + + + + French: + Francouzština: + + + + Japanese: + Japonština: + + + + Russian: + Ruština: + + + + Czech: + Čeština: + + + + Slovak: + Slovenština: + + + + + + + + + Error + Chyba + + + + Server timeout + Vypršel časový limit + + + + Invalid login data. + Nesprávné údaje uživatele. + + + + There is already an active session using this user name. +Please close that session first and re-login. + S tímto uživatelským jménem jste již připojeni. +Přerušte spojení a znovu se přihlašte. + + + + Socket error: %1 + Chyba socketu: %1 + + + + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. +Local version is %1, remote version is %2. + Snažíte se připojit na zastaralý server. Prosíme, stáhněte si nižší verzi Cockatrice, nebo se připojte k odpovídajícímu serveru. +Lokální verze je %1, verze serveru je %2. + + + + Your Cockatrice client is obsolete. Please update your Cockatrice version. +Local version is %1, remote version is %2. + Váš klient je zastaralý. Prosíme, aktualizujte Cockatrice na vyšší verzi. +Lokální verze je %1, verze serveru je %2. + + + + Connecting to %1... + Připojování k %1... + + + + Disconnected + Odpojeno + + + + Logged in at %1 + Přihlášeno k %1 + + + + &Connect... + &Připojit... + + + + &Disconnect + &Odpojit + + + + Start &local game... + Spustit &lokální hru... + + + + &Deck editor + &Editor balíčků + + + + &Full screen + &Celá obrazovka + + + + Ctrl+F + CTRL+F + + + + &Settings... + &Nastavení... + + + + &Exit + &Konec + + + + &Cockatrice + &Cockatrice + + + + &About Cockatrice + &O Cockatrice + + + + &Help + &Nápověda + + + + Are you sure? + Jste si jisti? + + + + There are still open games. Are you sure you want to quit? + Některé hry jsou stále otevřené. Opravdu chcete odejít? + + + + MessageLogWidget + + Connecting to %1... + Připojování k %1... + + + Connected. + Připojeno. + + + Disconnected from server. + Odpojeno. + + + Invalid password. + Nesprávné heslo. + + + Protocol version mismatch. Client: %1, Server: %2 + Neodpovídá verze protokolu. Klient: %1, Server: %2 + + + Protocol error. + Chyba protokolu. + + + You have joined game #%1. + Připojili jste se ke hře #%1. + + + %1 has joined the game. + %1 se připojil ke hře. + + + %1 has left the game. + %1 opustil hru. + + + + The game has been closed. + Hra byla ukončena. + + + + %1 is now watching the game. + %1 nyní sleduje hru. + + + + %1 is not watching the game any more. + %1 přestal sledovat hru. + + + %1 has loaded a local deck. + %1 nahrál lokální balíček. + + + %1 has loaded deck #%2. + %1 nahrál balíček #%2. + + + %1 is ready to start the game. + %1 je připraven ke hře. + + + %1 is not ready to start the game any more. + %1 již není připraven ke hře. + + + %1 has conceded the game. + %1 ukončil hru. + + + + The game has started. + Hra začíná. + + + %1 shuffles his library. + %1 míchá knihovnu. + + + %1 rolls a %2 with a %3-sided die. + %1 hodil kostkou %2 (%3 stěn). + + + %1 draws %n card(s). + + %1 si lízl %n kartu. + %1 si lízl %n karty. + %1 si lízl %n karet. + + + + + You have joined game #%1. + female + Připojili jste se ke hře #%1. + + + + You have joined game #%1. + male + Připojili jste se ke hře #%1. + + + + %1 has joined the game. + female + %1 se připojil ke hře. + + + + %1 has joined the game. + male + %1 se připojil ke hře. + + + + %1 has left the game. + female + %1 opustil hru. + + + + %1 has left the game. + male + %1 opustil hru. + + + + %1 has loaded a local deck. + female + %1 nahrál lokální balíček. + + + + %1 has loaded a local deck. + male + %1 nahrál lokální balíček. + + + + %1 has loaded deck #%2. + female + %1 nahrál balíček #%2. + + + + %1 has loaded deck #%2. + male + %1 nahrál balíček #%2. + + + + %1 is ready to start the game. + female + %1 je připraven ke hře. + + + + %1 is ready to start the game. + male + %1 je připraven ke hře. + + + + %1 is not ready to start the game any more. + female + %1 již není připraven ke hře. + + + + %1 is not ready to start the game any more. + male + %1 již není připraven ke hře. + + + + %1 has conceded the game. + female + %1 ukončil hru. + + + + %1 has conceded the game. + male + %1 ukončil hru. + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + + %1 rolls a %2 with a %3-sided die. + female + %1 hodil kostkou %2 (%3 stěn). + + + + %1 rolls a %2 with a %3-sided die. + male + %1 hodil kostkou %2 (%3 stěn). + + + + %1 draws %n card(s). + female + + %1 si lízl %n kartu. + %1 si lízl %n karty. + %1 si lízl %n karet. + + + + + %1 draws %n card(s). + male + + %1 si lízl %n kartu. + %1 si lízl %n karty. + %1 si lízl %n karet. + + + + + %1 undoes his last draw. + %1 vrátil zpět svoje poslední líznutí. + + + + %1 undoes her last draw. + + + + + %1 undoes his last draw (%2). + %1 vrátil svoje poslední líznutí (%2). + + + + %1 undoes her last draw (%2). + + + + + from table + z bojiště + + + + from graveyard + ze hřbitova + + + + from exile + z exilnutých karet + + + + from hand + z ruky + + + + the bottom card of his library + spodní kartu knihovny + + + + the bottom card of her library + + + + + from the bottom of his library + ze spodku knihovny + + + + from the bottom of her library + + + + + the top card of his library + vrchní kartu knihovny + + + + the top card of her library + + + + + from the top of his library + z vršku knihovny + + + + from the top of her library + + + + + from library + z knihovny + + + + from sideboard + ze sideboardu + + + + from the stack + ze stacku + + + + + a card + kartu + + + + %1 gives %2 control over %3. + %1 předává kontrolu hráči %2 karty %3. + + + + %1 puts %2 into play tapped%3. + %1 dává kartu %2 do hry %3 tapnutou. + + + + %1 puts %2 into play%3. + %1 dává kartu %2 %3 do hry. + + + + %1 puts %2%3 into graveyard. + %1 dává kartu %2%3 do hřbitova. + + + + %1 exiles %2%3. + %1 exiluje %2%3. + + + + %1 moves %2%3 to hand. + %1 přesouvá %2%3 do ruky. + + + + %1 puts %2%3 into his library. + %1 dává %2%3 do knihovny. + + + + %1 puts %2%3 into her library. + + + + + %1 puts %2%3 on bottom of his library. + %1 dává %2%3 na spodek knihovny. + + + + %1 puts %2%3 on bottom of her library. + + + + + %1 puts %2%3 on top of his library. + %1 dává %2%3 na vršek knihovny. + + + + %1 puts %2%3 on top of her library. + + + + + %1 puts %2%3 into his library at position %4. + %1 dává %2%3 knihovny na pozici %4. + + + + %1 puts %2%3 into her library at position %4. + + + + + %1 moves %2%3 to sideboard. + %1 přesouvá %2%3 do sideboardu. + + + + %1 plays %2%3. + %1 sesílá %2%3. + + + + %1 takes a mulligan to %n. + female + + %1 mulliganuje do %n. + %1 mulliganuje do %n. + %1 mulliganuje do %n. + + + + + %1 takes a mulligan to %n. + male + + %1 mulliganuje do %n. + %1 mulliganuje do %n. + %1 mulliganuje do %n. + + + + + %1 draws her initial hand. + + + + + %1 flips %2 face-down. + female + %1 otáčí %2 lícem dolů. + + + + %1 flips %2 face-down. + male + %1 otáčí %2 lícem dolů. + + + + %1 flips %2 face-up. + female + %1 otáčí %2 lícem vzhůru. + + + + %1 flips %2 face-up. + male + %1 otáčí %2 lícem vzhůru. + + + + %1 destroys %2. + female + %1 ničí %2. + + + + %1 destroys %2. + male + %1 ničí %2. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + %1 připojuje %2 k %3 %4. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + %1 připojuje %2 k %3 %4. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + %1 připojuje %2 k %3 %4. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + %1 připojuje %2 k %3 %4. + + + + %1 unattaches %2. + female + %1 odpojuje %2. + + + + %1 unattaches %2. + male + %1 odpojuje %2. + + + + %1 creates token: %2%3. + female + %1 vykládá token %2%3. + + + + %1 creates token: %2%3. + male + %1 vykládá token %2%3. + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + %1 ukazuje kartou %3 (hráče %2) na %4. + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + %1 pokládá %n %2 žeton na %3 (nyní %4). + %1 pokládá %n %2 žetony na %3 (nyní %4). + %1 pokládá %n %2 žetonů na %3 (nyní %4). + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 pokládá %n %2 žeton na %3 (nyní %4). + %1 pokládá %n %2 žetony na %3 (nyní %4). + %1 pokládá %n %2 žetonů na %3 (nyní %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 odebírá %n %2 žeton z %3 (nyní %4). + %1 odebírá %n %2 žetony z %3 (nyní %4). + %1 odebírá %n %2 žetonů z %3 (nyní %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + %1 odebírá %n %2 žeton z %3 (nyní %4). + %1 odebírá %n %2 žetony z %3 (nyní %4). + %1 odebírá %n %2 žetonů z %3 (nyní %4). + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + %1 nastavuje počet %2 žetonů na %3 (%4%5). + + + + %1 sets counter %2 to %3 (%4%5). + male + %1 nastavuje počet %2 žetonů na %3 (%4%5). + + + + %1 sets %2 to not untap normally. + female + %1 nastavuje %2 na neodtapování. + + + + %1 sets %2 to not untap normally. + male + %1 nastavuje %2 na neodtapování. + + + + %1 sets %2 to untap normally. + female + %1 nastavuje %2 na standardní odtapnutí. + + + + %1 sets %2 to untap normally. + male + %1 nastavuje %2 na standardní odtapnutí. + + + + %1 sets PT of %2 to %3. + female + %1 nastavuje sílu a odolnost pro %2 na %3. + + + + %1 sets PT of %2 to %3. + male + %1 nastavuje sílu a odolnost pro %2 na %3. + + + + %1 sets annotation of %2 to %3. + female + %1 nastavuje poznámku pro %2 na %3. + + + + %1 sets annotation of %2 to %3. + male + %1 nastavuje poznámku pro %2 na %3. + + + + %1 is looking at the top %2 cards %3. + female + %1 si prohlíží %2 vrchních karet %3. + + + + %1 is looking at the top %2 cards %3. + male + %1 si prohlíží %2 vrchních karet %3. + + + + %1 is looking at %2. + female + %1 si prohlíží %2. + + + + %1 is looking at %2. + male + %1 si prohlíží %2. + + + + %1 stops looking at %2. + female + %1 si přestává prohlížet %2. + + + + %1 stops looking at %2. + male + %1 si přestává prohlížet %2. + + + + %1 reveals %2 to %3. + p1 female, p2 female + %1 ukazuje %2 hráči %3. + + + + %1 reveals %2 to %3. + p1 female, p2 male + %1 ukazuje %2 hráči %3. + + + + %1 reveals %2 to %3. + p1 male, p2 female + %1 ukazuje %2 hráči %3. + + + + %1 reveals %2 to %3. + p1 male, p2 male + %1 ukazuje %2 hráči %3. + + + + %1 reveals %2. + female + %1 ukazuje %2. + + + + %1 reveals %2. + male + %1 ukazuje %2. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + %1 náhodně ukazuje %2%3 hráči %4. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + %1 náhodně ukazuje %2%3 hráči %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + %1 náhodně ukazuje %2%3 hráči %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + %1 náhodně ukazuje %2%3 hráči %4. + + + + %1 randomly reveals %2%3. + female + %1 náhodně ukazuje %2%3. + + + + %1 randomly reveals %2%3. + male + %1 náhodně ukazuje %2%3. + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + %1 ukazuje %2%3 hráči %4. + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + %1 ukazuje %2%3 hráči %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + %1 ukazuje %2%3 hráči %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + %1 ukazuje %2%3 hráči %4. + + + + %1 reveals %2%3. + female + %1 ukazuje %2%3. + + + + %1 reveals %2%3. + male + %1 ukazuje %2%3. + + + + It is now %1's turn. + female + Nyní je kolo hráče %1. + + + + It is now %1's turn. + male + Nyní je kolo hráče %1. + + + %1 takes a mulligan to %n. + + %1 mulliganuje do %n. + %1 mulliganuje do %n. + %1 mulliganuje do %n. + + + + + %1 draws his initial hand. + %1 líže startovní ruku. + + + %1 flips %2 face-down. + %1 otáčí %2 lícem dolů. + + + %1 flips %2 face-up. + %1 otáčí %2 lícem vzhůru. + + + %1 destroys %2. + %1 ničí %2. + + + %1 attaches %2 to %3's %4. + %1 připojuje %2 k %3 %4. + + + %1 unattaches %2. + %1 odpojuje %2. + + + %1 creates token: %2%3. + %1 vykládá token %2%3. + + + %1 points from %2's %3 to %4. + %1 ukazuje kartou %3 (hráče %2) na %4. + + + %1 points from %2's %3 to %4's %5. + %1 ukazuje kartou %3 (hráče %2) na %5 (hráče %4). + + + %1 places %n %2 counter(s) on %3 (now %4). + + %1 pokládá %n %2 žeton na %3 (nyní %4). + %1 pokládá %n %2 žetony na %3 (nyní %4). + %1 pokládá %n %2 žetonů na %3 (nyní %4). + + + + %1 removes %n %2 counter(s) from %3 (now %4). + + %1 odebírá %n %2 žeton z %3 (nyní %4). + %1 odebírá %n %2 žetony z %3 (nyní %4). + %1 odebírá %n %2 žetonů z %3 (nyní %4). + + + + + red + + červený + červené + červených + + + + + yellow + + žlutý + žluté + žlutých + + + + + green + + zelený + zelené + zelených + + + + his permanents + permanenty + + + %1 %2 %3. + %1 %2 %3. + + + taps + tapuje + + + untaps + odtapuje + + + %1 sets counter %2 to %3 (%4%5). + %1 nastavuje počet %2 žetonů na %3 (%4%5). + + + %1 sets %2 to not untap normally. + %1 nastavuje %2 na neodtapování. + + + %1 sets %2 to untap normally. + %1 nastavuje %2 na standardní odtapnutí. + + + %1 sets PT of %2 to %3. + %1 nastavuje sílu a odolnost pro %2 na %3. + + + %1 sets annotation of %2 to %3. + %1 nastavuje poznámku pro %2 na %3. + + + %1 is looking at the top %2 cards %3. + %1 si prohlíží %2 vrchních karet %3. + + + %1 is looking at %2. + %1 si prohlíží %2. + + + %1 stops looking at %2. + %1 si přestává prohlížet %2. + + + %1 reveals %2 to %3. + %1 ukazuje %2 hráči %3. + + + %1 reveals %2. + %1 ukazuje %2. + + + %1 randomly reveals %2%3 to %4. + %1 náhodně ukazuje %2%3 hráči %4. + + + %1 randomly reveals %2%3. + %1 náhodně ukazuje %2%3. + + + %1 reveals %2%3 to %4. + %1 ukazuje %2%3 hráči %4. + + + %1 reveals %2%3. + %1 ukazuje %2%3. + + + It is now %1's turn. + Nyní je kolo hráče %1. + + + + untap step + Odtapovací fáze + + + + upkeep step + Upkeep + + + + draw step + Lízací fáze + + + + first main phase + První hlavní fáze + + + + beginning of combat step + Začátek bojové fáze + + + + declare attackers step + Oznámení útočníků + + + + declare blockers step + Oznámení blokujících + + + + combat damage step + Udělení bojového zranění + + + + end of combat step + Konec bojové fáze + + + + second main phase + Druhá hlavní fáze + + + + ending phase + Konec kola + + + + It is now the %1. + Nyní je %1. + + + + MessagesSettingsPage + + + Add message + Přidat zprávu + + + + Message: + Zpráva: + + + + &Add + &Přidat + + + + &Remove + &Odstranit + + + + PhasesToolbar + + + Untap step + Odtapovací fáze + + + + Upkeep step + Upkeep + + + + Draw step + Lízací fáze + + + + First main phase + První hlavní fáze + + + + Beginning of combat step + Začátek bojové fáze + + + + Declare attackers step + Oznámení útočníků + + + + Declare blockers step + Oznámení blokujících + + + + Combat damage step + Udělení bojového zranění + + + + End of combat step + Konec bojové fáze + + + + Second main phase + Druhá hlavní fáze + + + + End of turn step + Konec kola + + + + Player + + + &View graveyard + &Zobrazit hřbitov + + + + &View exile + &Zobrazit exilnuté karty + + + + Player "%1" + Hráč "%1" + + + + &Graveyard + &Hřbitov + + + + &Exile + &Exilnuté karty + + + + + + Move to &top of library + Přesunout na &vršek knihovny + + + + + + Move to &bottom of library + Přesunout na &spodek knihovny + + + + + Move to &graveyard + Přesunout do &hřbitova + + + + + Move to &exile + &Exilnout + + + + + Move to &hand + Přesunout do &ruky + + + + &View library + &Zobrazit knihovnu + + + + View &top cards of library... + Zobrazit &vrchní karty knihovny... + + + + Reveal &library to + Ukázat &knihovnu + + + + Reveal t&op card to + Ukázat v&rchní kartu + + + + &View sideboard + &Zobrazit sideboard + + + + &Draw card + &Líznout kartu + + + + D&raw cards... + L&íznout karty... + + + + &Undo last draw + &Vrátit zpět poslední líznutí + + + + Take &mulligan + &Mulliganovat + + + + &Shuffle + &Zamíchat + + + + Move top cards to &graveyard... + Přesunout vrchní karty do &hřbitova... + + + + Move top cards to &exile... + &Exilnout vrchní karty... + + + + Put top card on &bottom + Dát kartu na &spodek + + + + &Hand + &Ruka + + + + &Reveal to + &Ukázat + + + + Reveal r&andom card to + Ukázat kartu n&áhodně + + + + &Sideboard + &Sideboard + + + + &Library + &Knihovna + + + + &Counters + &Žetony + + + + &Untap all permanents + &Odtapnout všechny permanenty + + + + R&oll die... + H&odit kostkou... + + + + &Create token... + &Vytvořit token... + + + + C&reate another token + V&ytvořit další token + + + + S&ay + &Chat + + + + C&ard + K&arta + + + + &All players + &Všem hráčům + + + + Ctrl+F3 + Ctrl+F3 + + + + F3 + F3 + + + + Ctrl+W + Ctrl+W + + + + F4 + F4 + + + + Ctrl+D + Ctrl+D + + + + Ctrl+E + Ctrl+E + + + + Ctrl+Shift+D + Ctrl+Shift+D + + + + 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 + Zobrazit vrchní karty knihovny + + + + Number of cards: + Počet karet: + + + + Draw cards + Líznout karty + + + + + + + Number: + Počet: + + + + Move top cards to grave + Přesunout vrchní karty do hřbitova + + + + Move top cards to exile + Exilnout vrchní karty + + + + Roll die + Hodit kostkou + + + + Number of sides: + Počet stran: + + + + Set power/toughness + Nastavit sílu/odolnost + + + + Please enter the new PT: + Vložte novou odolnost/sílu: + + + + Set annotation + Nastavit poznámku + + + + Please enter the new annotation: + Vložte novou poznámku: + + + + Set counters + Nastavit žetony + + + + PlayerListWidget + + + local deck + lokální balíček + + + + deck #%1 + bal94ek #%1 + + + + User &details + Detaily &uživatele + + + + Direct &chat + &Chatovat + + + + Add to &buddy list + Přidat mezi &přátele + + + + Remove from &buddy list + Odstranit z &přátel + + + + Add to &ignore list + Přidat do &ignorovaných + + + + Remove from &ignore list + Odstranit z &ignorovaných + + + + Kick from &game + Vyhodit ze &hry + + + + QObject + + + Maindeck + Maindeck + + + + Sideboard + Sideboard + + + + Cockatrice decks (*.cod) + Balíčky cockatrice (*.cod) + + + + Plain text decks (*.dec *.mwDeck) + Čistý text (*.dec*.mwDeck) + + + + All files (*.*) + Všechny soubory (*.*) + + + + RemoteDeckList_TreeModel + + + Name + Jméno + + + + ID + ID + + + + Upload time + Průběh nahrávání + + + + RoomSelector + + + Rooms + Místnosti + + + + Joi&n + &Připojit + + + + Room + Místnost + + + + Description + Popis + + + + Players + Hráči + + + + Games + Hry + + + + SetsModel + + + Short name + Krátký název + + + + Long name + Dlouhý název + + + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + &OK + + + + &Cancel + + + + + Shut down server + + + + + TabAdmin + + + Update server &message + Aktualizovat &zprávu serveru + + + + &Shut down server + + + + + Server administration functions + Administrační funkce serveru + + + + &Unlock functions + &Odemknout funkce + + + + &Lock functions + &Zamknout funkce + + + + Unlock administration functions + Odemknout administrační funkce + + + + Do you really want to unlock the administration functions? + Opravdu chcete odemknout administrační funkce? + + + + Administration + Administrace + + + + TabDeckStorage + + + Local file system + Lokální systém souborů + + + + Server deck storage + Balíčky na serveru + + + + + Open in deck editor + Otevřít v editoru balíčků + + + + Upload deck + Nahrát balíček + + + + Download deck + Stáhnout balíček + + + + + New folder + Nová složka + + + + Delete + Smazat + + + + Enter deck name + Vložit jméno balíčku + + + + This decklist does not have a name. +Please enter a name: + Tentobalíček nemá jméno. +Prosím vložte jméno: + + + + + Unnamed deck + Bezejmenný balíček + + + + Name of new folder: + Název nové složky: + + + + Deck storage + Uložiště balíčků + + + + TabGame + + + F5 + F5 + + + + F6 + F6 + + + + F7 + F7 + + + + F8 + F8 + + + + F9 + F9 + + + + F10 + F10 + + + + &Phases + &Fáze + + + + &Game + &Hra + + + + Next &phase + Další &fáze + + + + Ctrl+Space + Ctrl+Space + + + + Next &turn + Další &kolo + + + + Ctrl+Return + Ctrl+Return + + + + Ctrl+Enter + Ctrl+Enter + + + + &Remove all local arrows + &Odstranit všechny lokální šipky + + + + Ctrl+R + CTRL+R + + + + &Concede + &Ukončit hru + + + + F2 + F2 + + + + &Leave game + &Opustit hru + + + + Ctrl+Q + CTRL+Q + + + + &Say: + &Chat: + + + + Concede + Ukončit hru + + + + Are you sure you want to concede this game? + Opravdu chcete ukončit tuto hru? + + + + Leave game + Opustit hru + + + + Are you sure you want to leave this game? + Opravdu chcete opustit tuto hru? + + + + Kicked + Vyhozen + + + + You have been kicked out of the game. + Byli jste vyhozeni ze hry. + + + + Game %1: %2 + Hra %1: %2 + + + + TabMessage + + + Personal &talk + Osobní &diskuze + + + + &Leave + &Odejít + + + + This user is ignoring you. + Tento uživatel vás ignoruje. + + + + %1 has left the server. + %1 opustil server. + + + + %1 has joined the server. + %1 se připojil k serveru. + + + + Talking to %1 + Mlávíte k %1 + + + + TabRoom + + + &Say: + &Chat: + + + + Chat + Chatovat + + + + &Room + &Místnost + + + + &Leave room + &Opustit místnost + + + + You are flooding the chat. Please wait a couple of seconds. + Píšete příliš intenzivně. Počkejte pár sekund. + + + + TabServer + + + Server + Server + + + + TabUserLists + + + User lists + Seznam uživatelů + + + + UserInfoBox + + + User information + Informace o uživateli + + + + Real name: + Pravé jméno: + + + + Gender: + + + + + Location: + Místo: + + + + User level: + Úroveň: + + + + Administrator + Administrátor + + + + Moderator + + + + Judge + Judge + + + + Registered user + Registrovaný + + + + Unregistered user + Neregistrovaný + + + + UserInterfaceSettingsPage + + + General interface settings + Obecné + + + + &Double-click cards to play them (instead of single-click) + &Pro zahraní karty je třeba dvojklik + + + + Animation settings + Animace + + + + &Tap/untap animation + &Animace tapnutí/odtapnutí + + + + Enable &sounds + Povolit &zvuky + + + + Path to sounds directory: + Adresář se zvuky: + + + + Choose path + Vyberte cestu + + + + UserList + + + Users online: %1 + Připojených uživatelů: %1 + + + + Users in this room: %1 + Uživatelů v této místnosti: %1 + + + + Buddies online: %1 / %2 + Přátelé online: %1 / %2 + + + + Ignored users online: %1 / %2 + Ignorovaných online: %1 / %2 + + + + %1's games + + + + + User &details + &Detaily uživatele + + + + Direct &chat + &Chatovat + + + + Show this user's &games + + + + + Add to &buddy list + Přidat mezi &přátele + + + + Remove from &buddy list + Odstranit z &přátel + + + + Add to &ignore list + Přidat mezi &ignorované + + + + Remove from &ignore list + Odstranit z &ignorovaných + + + + Ban from &server + &Zabanovat + + + Duration + Délka + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Vložte dobu trvání banu (v minutách). +Hodnota 0 je pro ban bez omezení. + + + + WndDeckEditor + + + &Search... + &Hledat... + + + + &Clear search + &Vyčistit hledání + + + + &Search for: + &Vyhledat: + + + + Deck &name: + &Název balíčku: + + + + &Comments: + &Komentář: + + + + &Update prices + Akt&ualizovat ceny + + + + Ctrl+U + CTRL+U + + + + Deck editor [*] + Editor balíčků [*] + + + + &New deck + &Nový balíček + + + + &Load deck... + &Nahrát balíček... + + + + &Save deck + &Uložit balíček + + + + Save deck &as... + Uložit balíček &jako... + + + + Load deck from cl&ipboard... + Nahrát balíček ze s&chránky... + + + + Save deck to clip&board + Vložit balíček do &schránky + + + + &Print deck... + &Vytisknout balíček... + + + + &Close + &Zavřít + + + + Ctrl+Q + CTRL+Q + + + + &Edit sets... + &Upravit sasy... + + + + &Deck + &Balíček + + + + &Card database + Databáze &karet + + + + Add card to &maindeck + Přidat kartu do &balíčku + + + + Return + Return + + + + Enter + Enter + + + + Add card to &sideboard + Přidat kartu do &sideboardu + + + + Ctrl+Return + Ctrl+Return + + + + Ctrl+Enter + Ctrl+Enter + + + + &Remove row + &Smazat řádek + + + + Del + Del + + + + &Increment number + &Zvýšit počet + + + + + + + + + + + &Decrement number + &Snížit počet + + + + - + - + + + + Are you sure? + Jste si jisti? + + + + The decklist has been modified. +Do you want to save the changes? + Balíček byl upraven. +Chcete uložit změny? + + + + Load deck + Nahrát balíček + + + + + Error + Chyba + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + Balíček nebylo možné uložit. +Zkontrolujte, jestli lze zapisovat do cílového adresáře a zkuste to znovu. + + + + Save deck + Uložit balíček + + + + WndSets + + + Edit sets + Upravit edice + + + + ZoneViewWidget + + + sort by name + seřadit dle jména + + + + sort by type + seřadit dle typu + + + + shuffle when closing + zamíchat po zavření + + + diff --git a/cockatrice/translations/cockatrice_de.ts b/cockatrice/translations/cockatrice_de.ts index ebf01d7f8..cd581e185 100644 --- a/cockatrice/translations/cockatrice_de.ts +++ b/cockatrice/translations/cockatrice_de.ts @@ -60,66 +60,71 @@ 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: - + Card rendering Kartendarstellung - + Display card names on cards having a picture Kartennamen darstellen auch bei Karten, die Bilder haben - + Hand layout Kartenhand - + Display hand horizontally (wastes space) Hand horizonal anzeigen (verschwendet Platz) - + Table grid layout Spielfeldraster + + + Minimum player count for multi-column layout: + Mindestspielerzahl für mehrspaltige Anordnung: + Economical layout Platzsparende Anordnung - + Invert vertical coordinate Vertikale Koordinate umkehren @@ -128,17 +133,17 @@ Platzsparende Anordnung - + Zone view layout Aussehen des Zonenbetrachters - + Sort by name nach Namen sortieren - + Sort by type nach Kartentypen sortieren @@ -147,15 +152,51 @@ standardmäßig alphabetisch sortieren - - - - - + + + + + Choose path Pfad auswählen + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Bitte geben Sie die Dauer des Banns ein (in Minuten). +Geben Sie 0 ein für einen unbefristeten Bann. + + + Please enter the reason for the ban. This is only saved for moderators and cannot be seen by the banned person. + Bitte geben Sie den Grund für den Bann ein. Dies wird nur für Moderatoren gespeichert und kann von der gebannten Person nicht gesehen werden. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + Bitte geben Sie den Grund für den Bann ein. +Dies wird nur für Moderatoren gespeichert und kann von der gebannten Person nicht gesehen werden. + + + + &OK + &OK + + + + &Cancel + &Abbrechen + + + + Ban user from server + Benutzer vom Server bannen + + CardDatabaseModel @@ -187,22 +228,42 @@ CardInfoWidget - + + Hide card info + Nichts anzeigen + + + + Show card only + nur Kartenbild + + + + Show text only + nur Kartentext + + + + Show full info + Alles anzeigen + + + Name: Name: - + Mana cost: Manakosten: - + Card type: Kartentyp: - + P / T: S/W: @@ -218,57 +279,57 @@ CardItem - + &Play &Ausspielen - + &Hide &Verstecken - + &Tap &Tappen - + &Untap E&nttappen - + Toggle &normal untapping N&ormales Enttappen umschalten - + &Flip &Umdrehen - + &Clone &Kopieren - + Ctrl+H Ctrl+H - + &Attach to card... &An Karte anlegen... - + Ctrl+A Ctrl+A - + Unattac&h &Von Karte lösen @@ -277,142 +338,147 @@ &Kampfwerte setzen... - + + &Draw arrow... + &Pfeil zeichnen... + + + &Power / toughness &Kampfwerte - + &Increase power &Stärke erhöhen - + Ctrl++ Ctrl++ - + &Decrease power S&tärke senken - + Ctrl+- Ctrl+- - + I&ncrease toughness &Widerstandskraft erhöhen - + Alt++ Alt++ - + D&ecrease toughness W&iderstandskraft senken - + Alt+- Alt+- - + In&crease power and toughness Stärke und Widerstandskraft &erhöhen - + Ctrl+Alt++ Ctrl+Alt++ - + Dec&rease power and toughness Stärke und Widerstandskraft s&enken - + Ctrl+Alt+- Ctrl+Alt+- - + Set &power and toughness... &Kampfwerte setzen... - + Ctrl+P Ctrl+P - + &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 @@ -500,40 +566,34 @@ von %1s Sideboard - his hand nominative - seine Hand + seine Hand - %1's hand nominative - %1s Hand + %1s Hand - of his hand genitive - seiner Hand + seiner Hand - of %1's hand genitive - von %1s Hand + von %1s Hand - his hand accusative - seine Hand + seine Hand - %1's hand accusative - %1s Hand + %1s Hand his hand @@ -546,40 +606,34 @@ %1s Hand - his library nominative - seine Bibliothek + seine Bibliothek - %1's library nominative - %1s Bibliothek + %1s Bibliothek - of his library genitive - seiner Bibliothek + seiner Bibliothek - of %1's library genitive - von %1s Bibliothek + von %1s Bibliothek - his library accusative - seine Bibliothek + seine Bibliothek - %1's library accusative - %1s Bibliothek + %1s Bibliothek his library @@ -592,40 +646,394 @@ %1s Bibliothek - - his graveyard - nominative - sein Friedhof + + her hand + nominative, female owner + ihre Hand - + + %1's hand + nominative, female owner + %1s Hand + + + + his hand + nominative, male owner + seine Hand + + + + %1's hand + nominative, male owner + %1s Hand + + + + of her hand + genitive, female owner + ihrer Hand + + + + of %1's hand + genitive, female owner + von %1s Hand + + + + of his hand + genitive, male owner + seiner Hand + + + + of %1's hand + genitive, male owner + von %1s Hand + + + + her hand + accusative, female owner + ihre Hand + + + + %1's hand + accusative, female owner + %1s Hand + + + + his hand + accusative, male owner + seine Hand + + + + %1's hand + accusative, male owner + %1s Hand + + + + her library + nominative, female owner + ihre Bibliothek + + + + %1's library + nominative, female owner + %1s Bibliothek + + + + his library + nominative, male owner + seine Bibliothek + + + + %1's library + nominative, male owner + %1s Bibliothek + + + + of her library + genitive, female owner + ihrer Bibliothek + + + + of %1's library + genitive, female owner + von %1s Bibliothek + + + + of his library + genitive, male owner + seiner Bibliothek + + + + of %1's library + genitive, male owner + von %1s Bibliothek + + + + her library + accusative, female owner + ihre Bibliothek + + + + %1's library + accusative, female owner + %1s Bibliothek + + + + his library + accusative, male owner + seine Bibliothek + + + + %1's library + accusative, male owner + %1s Bibliothek + + + + her graveyard + nominative, female owner + ihr Friedhof + + + %1's graveyard - nominative + nominative, female owner %1s Friedhof - of his graveyard - genitive - seines Friedhofs + his graveyard + nominative, male owner + sein Friedhof + %1's graveyard + nominative, male owner + %1s Friedhof + + + + of her graveyard + genitive, female owner + ihres Friedhofs + + + of %1's graveyard - genitive + genitive, female owner von %1s Friedhof - his graveyard - accusative - sein Friedhof + of his graveyard + genitive, male owner + seines Friedhofs + of %1's graveyard + genitive, male owner + von %1s Friedhof + + + + her graveyard + accusative, female owner + ihren Friedhof + + + + %1's graveyard + accusative, female owner + %1s Friedhof + + + + his graveyard + accusative, male owner + seinen Friedhof + + + + %1's graveyard + accusative, male owner + %1s Friedhof + + + + her exile + nominative, female owner + ihr Exil + + + + %1's exile + nominative, female owner + %1s Exil + + + + his exile + nominative, male owner + sein Exil + + + + %1's exile + nominative, male owner + %1s Exil + + + + of her exile + genitive, female owner + ihres Exils + + + + of %1's exile + genitive, female owner + von %1s Exil + + + + of his exile + genitive, male owner + seines Exils + + + + of %1's exile + genitive, male owner + von %1s Exil + + + + her exile + accusative, female owner + ihr Exil + + + + %1's exile + accusative, female owner + %1s Exil + + + + his exile + accusative, male owner + sein Exil + + + + %1's exile + accusative, male owner + %1s Exil + + + + her sideboard + nominative, female owner + ihr Sideboard + + + + %1's sideboard + nominative, female owner + %1s Sideboard + + + + his sideboard + nominative, male owner + sein Sideboard + + + + %1's sideboard + nominative, male owner + %1s Sideboard + + + + of her sideboard + genitive, female owner + ihres Sideboards + + + + of %1's sideboard + genitive, female owner + von %1s Sideboard + + + + of his sideboard + genitive, male owner + seines Sideboards + + + + of %1's sideboard + genitive, male owner + von %1s Sideboard + + + + her sideboard + accusative, female owner + ihr Sideboard + + + + %1's sideboard + accusative, female owner + %1s Sideboard + + + + his sideboard + accusative, male owner + sein Sideboard + + + + %1's sideboard + accusative, male owner + %1s Sideboard + + + his graveyard + nominative + sein Friedhof + + + %1's graveyard + nominative + %1s Friedhof + + + of his graveyard + genitive + seines Friedhofs + + + of %1's graveyard + genitive + von %1s Friedhof + + + his graveyard + accusative + sein Friedhof + + %1's graveyard accusative - %1s Friedhof + %1s Friedhof his graveyard @@ -638,40 +1046,34 @@ %1s Friedhof - his exile nominative - sein Exil + sein Exil - %1's exile nominative - %1s Exil + %1s Exil - of his exile genitive - seines Exils + seines Exils - of %1's exile genitive - von %1s Exil + von %1s Exil - his exile accusative - sein Exil + sein Exil - %1's exile accusative - %1s Exil + %1s Exil his exile @@ -684,40 +1086,34 @@ %1s Exil - his sideboard nominative - sein Sideboard + sein Sideboard - %1's sideboard nominative - %1s Sideboard + %1s Sideboard - of his sideboard genitive - seines Sideboards + seines Sideboards - of %1's sideboard genitive - von %1s Sideboard + von %1s Sideboard - his sideboard accusative - sein Sideboard + sein Sideboard - %1's sideboard accusative - %1s Sideboard + %1s Sideboard his sideboard @@ -810,6 +1206,19 @@ Neuer Wert für den Zähler '%1': + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + Karten&preisfunktionen anschalten (benutzt Daten von blacklotusproject.com) + + + + General + Allgemeines + + DeckList @@ -828,35 +1237,40 @@ DeckListModel - + Number Nummer - + Card Karte + + + Price + Preis + DeckViewContainer - + Load &local deck &Lokales Deck laden - + Load d&eck from server Deck vom Server l&aden - + Ready to s&tart Bereit zum S&tarten - + Load deck Deck laden @@ -952,42 +1366,42 @@ &Beschreibung: - + &Password: &Passwort: - + P&layers: &Spieler: - + Game type Spieltyp - + Only &buddies can join Nur &Freunde können teilnehmen - + Only &registered users can join Nur &registrierte Benutzer können teilnehmen - + Joining restrictions Teilnahmebedingungen - + &Spectators allowed &Zuschauer zugelassen - + Spectators &need a password to join Zuschauer brauchen &auch ein Passwort @@ -996,37 +1410,37 @@ Zuschauer können sp&rechen - + Spectators can &chat Zuschauer können s&chreiben - + Spectators see &everything Zuschauer sehen &alles - + Spectators Zuschauer - + &OK &OK - + &Cancel &Abbruch - + Create game Spiel erstellen - + Error Fehler @@ -1035,7 +1449,7 @@ Ungültige Anzahl an Spielern. - + Server error. Serverfehler. @@ -1208,9 +1622,9 @@ DlgSettings - - - + + + Error Fehler @@ -1227,47 +1641,52 @@ 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 - + + Deck editor + Deckeditor + + + Messages Nachrichten - + &Close S&chließen @@ -1533,23 +1952,24 @@ GameSelector - + C&reate Spiel e&rstellen - + &Join &Teilnehmen - - - - - - - + + + + + + + + Error Fehler @@ -1558,66 +1978,76 @@ XXX - + + Please join the appropriate room first. + Bitte betreten Sie erst den entsprechenden Raum. + + + 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. - + This game is only open to registered users. Dieses Spiel kann nur von registrierten Benutzern betreten werden. - + This game is only open to its creator's buddies. Dieses Spiel kann nur von Freunden des Erstellers betreten werden. - + You are being ignored by the creator of this game. Der Ersteller dieses Spiels ignoriert Sie. - + Join game Spiel beitreten - + Password: Passwort: - + Games Spiele - + Show &full games &Volle Spiele anzeigen + + + Show &running games + &Laufende Spiele anzeigen + &Show full games &Volle Spiele anzeigen - + J&oin as spectator &Zuschauen @@ -1633,12 +2063,12 @@ GamesModel - + yes ja - + no nein @@ -1647,57 +2077,62 @@ Spiel ID - + Creator Ersteller - + Description Beschreibung - + yes, free for spectators ja, außer für Zuschauer - + buddies only nur Freunde - + reg. users only nur reg. Benutzer - + not allowed nicht erlaubt + Room + Raum + + + Game type Spieltyp - + Password Passwort - + Restrictions Bedingungen - + Players Spieler - + Spectators Zuschauer @@ -1705,50 +2140,50 @@ GeneralSettingsPage - - - + + + Choose path Pfad auswählen - + Personal settings Persönliche Einstellungen - + Language: Sprache: - + Download card pictures on the fly Kartenbilder dynamisch herunterladen - + Paths Pfade - + Decks directory: Verzeichnis mit Decklisten: - + Pictures directory: Verzeichnis mit Bilddateien: - + Path to card database: Pfad zur Kartendatenbank: - - + + English Deutsch @@ -1767,128 +2202,162 @@ + Scheduled server shutdown. + Planmäßige Serverabschaltung. + + + Unknown reason. Unbekannter Grund. - + Connection closed Verbindung geschlossen - + The server has terminated your connection. Reason: %1 Der Server hat Ihre Verbindung beendet. Grund: %1 - + + Scheduled server shutdown + Planmäßige Serverabschaltung + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + Der Server wird in %n Minute neu gestartet. +Alle laufenden Spiele werden beendet. +Grund für die Abschaltung: %1 + Der Server wird in %n Minuten neu gestartet. +Alle laufenden Spiele werden beendet. +Grund für die Abschaltung: %1 + + + + Number of players Spieleranzahl - + Please enter the number of players. Bitte die Spieleranzahl eingeben: - - + + Player %1 Spieler %1 - + About Cockatrice Ü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: - + Russian: Russisch: - - - - - - + + Czech: + Tschechisch: + + + + Slovak: + Slowakisch: + + + + + + + + Error Fehler - + Server timeout Server Zeitüberschreitung - + Invalid login data. Ungültige Anmeldedaten. - + There is already an active session using this user name. Please close that session first and re-login. Es gibt bereits eine aktive Verbindung mit diesem Benutzernamen. Bitte schließen Sie diese Verbindung zuerst und versuchen Sie es dann erneut. - + Socket error: %1 Netzwerkfehler: %1 - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. Sie versuchen sich an einem veralteten Server anzumelden. Bitte verwenden Sie eine ältere Cockatrice-Version oder melden Sie sich an einem aktuellen Server an. Lokale Version ist %1, Serverversion ist %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. Ihr Cockatrice-Client ist veraltet. Bitte laden Sie sich die neueste Version herunter. @@ -1899,52 +2368,52 @@ Lokale Version ist %1, Serverversion ist %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? @@ -1961,27 +2430,27 @@ Lokale Version ist %1, Serverversion ist %2. Spiel ver&lassen - + &Deck editor &Deck-Editor - + &Full screen &Vollbild - + Ctrl+F Ctrl+F - + &Settings... &Einstellungen... - + &Exit &Beenden @@ -1994,7 +2463,7 @@ Lokale Version ist %1, Serverversion ist %2. Esc - + &Cockatrice &Cockatrice @@ -2022,24 +2491,20 @@ Lokale Version ist %1, Serverversion ist %2. MessageLogWidget - Connecting to %1... - Verbinde zu %1... + Verbinde zu %1... - Connected. - Verbunden. + Verbunden. - Disconnected from server. - Verbindung zum Server getrennt. + Verbindung zum Server getrennt. - Invalid password. - Ungültiges Passwort. + Ungültiges Passwort. You have joined the game. Player list: @@ -2078,8 +2543,8 @@ Lokale Version ist %1, Serverversion ist %2. %1 zieht %2 Karten - - + + a card eine Karte @@ -2136,14 +2601,13 @@ Lokale Version ist %1, Serverversion ist %2. %1s Sideboard - + The game has started. Das Spiel hat begonnen. - %1 shuffles his library. - %1 mischt seine Bibliothek. + %1 mischt seine Bibliothek. %1 rolls a %2 with a %3-sided dice. @@ -2158,74 +2622,71 @@ Lokale Version ist %1, Serverversion ist %2. Protokollversion stimmt nicht überein. - - Protocol version mismatch. Client: %1, Server: %2 - - - - Protocol error. - Protokollfehler. + Protokollfehler. - You have joined game #%1. - Sie sind dem Spiel %1 beigetreten. + Sie sind dem Spiel %1 beigetreten. - %1 has joined the game. - %1 ist dem Spiel beigetreten. + %1 ist dem Spiel beigetreten. - %1 has left the game. - %1 hat das Spiel verlassen. + %1 hat das Spiel verlassen. - + The game has been closed. Das Spiel wurde geschlossen. - + %1 is now watching the game. %1 schaut nun dem Spiel zu. - + %1 is not watching the game any more. %1 schaut dem Spiel nicht mehr zu. - %1 has loaded a local deck. - %1 hat ein lokales Deck geladen. + %1 hat ein lokales Deck geladen. - %1 has loaded deck #%2. - %1 hat das Deck Nr. %2 geladen. + %1 hat das Deck Nr. %2 geladen. - %1 is ready to start the game. - %1 ist bereit, das Spiel zu starten. + %1 ist bereit, das Spiel zu starten. - %1 is not ready to start the game any more. - %1 ist nicht mehr bereit, das Spiel zu starten. + %1 ist nicht mehr bereit, das Spiel zu starten. - %1 has conceded the game. - %1 hat das Spiel aufgegeben. + %1 hat das Spiel aufgegeben. + + + %1 has restored connection to the game. + %1 ist wieder mit dem Spiel verbunden. + + + %1 has lost connection to the game. + %1 hat die Verbindung zum Spiel verloren. + + + %1 shuffles %2. + %1 mischt %2. - %1 rolls a %2 with a %3-sided die. - %1 würfelt eine %2 mit einem %3-seitigen Würfel. + %1 würfelt eine %2 mit einem %3-seitigen Würfel. %1 draws a card. @@ -2236,217 +2697,1063 @@ Lokale Version ist %1, Serverversion ist %2. %1 zieht %2 Karten. - %1 draws %n card(s). + + %1 zieht eine Karte. + %1 zieht %n Karten. + + + + + You have joined game #%1. + female + Sie sind dem Spiel %1 beigetreten. + + + + You have joined game #%1. + male + Sie sind dem Spiel %1 beigetreten. + + + + %1 has joined the game. + female + %1 ist dem Spiel beigetreten. + + + + %1 has joined the game. + male + %1 ist dem Spiel beigetreten. + + + + %1 has left the game. + female + %1 hat das Spiel verlassen. + + + + %1 has left the game. + male + %1 hat das Spiel verlassen. + + + + %1 has loaded a local deck. + female + %1 hat ein lokales Deck geladen. + + + + %1 has loaded a local deck. + male + %1 hat ein lokales Deck geladen. + + + + %1 has loaded deck #%2. + female + %1 hat das Deck Nr. %2 geladen. + + + + %1 has loaded deck #%2. + male + %1 hat das Deck Nr. %2 geladen. + + + + %1 is ready to start the game. + female + %1 ist bereit, das Spiel zu starten. + + + + %1 is ready to start the game. + male + %1 ist bereit, das Spiel zu starten. + + + + %1 is not ready to start the game any more. + female + %1 ist nicht mehr bereit, das Spiel zu starten. + + + + %1 is not ready to start the game any more. + male + %1 ist nicht mehr bereit, das Spiel zu starten. + + + + %1 has conceded the game. + female + %1 hat das Spiel aufgegeben. + + + + %1 has conceded the game. + male + %1 hat das Spiel aufgegeben. + + + + %1 has restored connection to the game. + female + %1 ist wieder mit dem Spiel verbunden. + + + + %1 has restored connection to the game. + male + %1 ist wieder mit dem Spiel verbunden. + + + + %1 has lost connection to the game. + female + %1 hat die Verbindung zum Spiel verloren. + + + + %1 has lost connection to the game. + male + %1 hat die Verbindung zum Spiel verloren. + + + + %1 shuffles %2. + female + %1 mischt %2. + + + + %1 shuffles %2. + male + %1 mischt %2. + + + + %1 rolls a %2 with a %3-sided die. + female + %1 würfelt eine %2 mit einem %3-seitigen Würfel. + + + + %1 rolls a %2 with a %3-sided die. + male + %1 würfelt eine %2 mit einem %3-seitigen Würfel. + + + + %1 draws %n card(s). + female + + %1 zieht eine Karte. + %1 zieht %n Karten. + + + + + %1 draws %n card(s). + male %1 zieht eine Karte. %1 zieht %n Karten. - + %1 undoes his last draw. %1 legt die zuletzt gezogene Karte zurück. - + + %1 undoes her last draw. + %1 legt die zuletzt gezogene Karte zurück. + + + %1 undoes his last draw (%2). %1 legt die zuletzt gezogene Karte zurück (%2). - + + %1 undoes her last draw (%2). + %1 legt die zuletzt gezogene Karte zurück (%2). + + + from table vom Spielfeld - + from graveyard aus dem Friedhof - + from exile aus dem Exil - + from hand von der Hand - + the bottom card of his library die unterste Karte seiner Bibliothek - + + the bottom card of her library + die unterste Karte ihrer Bibliothek + + + from the bottom of his library , die unterste Karte seiner Bibliothek, - + + from the bottom of her library + , die unterste Karte ihrer Bibliothek, + + + the top card of his library die oberste Karte seiner Bibliothek - + + the top card of her library + die oberste Karte ihrer Bibliothek + + + from the top of his library , die oberste Karte seiner Bibliothek, - + + from the top of her library + , die oberste Karte ihrer Bibliothek, + + + from library aus der Bibliothek - + from sideboard aus dem Sideboard - + from the stack vom Stapel - + %1 gives %2 control over %3. %1 überlässt %2 die Kontrolle über %3. - + %1 puts %2 into play tapped%3. %1 bringt %2 getappt%3 ins Spiel. - + %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 into her library. + %1 legt %2%3 in ihre Bibliothek. + + + %1 puts %2%3 on bottom of his library. %1 legt %2%3 unter seine Bibliothek. - + + %1 puts %2%3 on bottom of her library. + %1 legt %2%3 unter ihre Bibliothek. + + + %1 puts %2%3 on top of his library. %1 legt %2%3 auf die Bibliothek. - + + %1 puts %2%3 on top of her 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 puts %2%3 into her library at position %4. + %1 legt %2%3 in ihre 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 takes a mulligan to %n. + female + + %1 nimmt einen Mulligan auf %n. + %1 nimmt einen Mulligan auf %n. + + + + + %1 takes a mulligan to %n. + male + + %1 nimmt einen Mulligan auf %n. + %1 nimmt einen Mulligan auf %n. + + - + %1 flips %2 face-down. + female %1 wendet %2 auf die Rückseite. - + + %1 flips %2 face-down. + male + %1 wendet %2 auf die Rückseite. + + + %1 flips %2 face-up. + female %1 wendet %2 auf die Vorderseite. - + + %1 flips %2 face-up. + male + %1 wendet %2 auf die Vorderseite. + + + %1 destroys %2. + female + %1 zerstört %2. + + + + %1 destroys %2. + male %1 zerstört %2. - %1 attaches %2 to %3's %4. + female + %1 legt %2 an %3s %4 an. + + + %1 attaches %2 to %3's %4. + male + %1 legt %2 an %3s %4 an. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female %1 legt %2 an %3s %4 an. - + + %1 attaches %2 to %3's %4. + p1 female, p2 male + %1 legt %2 an %3s %4 an. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + %1 legt %2 an %3s %4 an. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + %1 legt %2 an %3s %4 an. + + + %1 unattaches %2. + female %1 löst %2 ab. - + + %1 unattaches %2. + male + %1 löst %2 ab. + + + %1 creates token: %2%3. + female %1 erstellt Token: %2%3. - + + %1 creates token: %2%3. + male + %1 erstellt Token: %2%3. + + + + %1 points from her %2 to herself. + female + %1 zeigt von ihrem %2 auf sich selbst. + + + + %1 points from his %2 to himself. + male + %1 zeigt von seinem %2 auf sich selbst. + + + + %1 points from her %2 to %3. + p1 female, p2 female + %1 zeigt von ihrem %2 auf %3. + + + + %1 points from her %2 to %3. + p1 female, p2 male + %1 zeigt von ihrem %2 auf %3. + + + + %1 points from his %2 to %3. + p1 male, p2 female + %1 zeigt von seinem %2 auf %3. + + + + %1 points from his %2 to %3. + p1 male, p2 male + %1 zeigt von seinem %2 auf %3. + + + + %1 points from %2's %3 to herself. + card owner female, target female + %1 zeigt von %2s %3 auf sich selbst. + + + + %1 points from %2's %3 to herself. + card owner male, target female + %1 zeigt von %2s %3 auf sich selbst. + + + + %1 points from %2's %3 to himself. + card owner female, target male + %1 zeigt von %2s %3 auf sich selbst. + + + + %1 points from %2's %3 to himself. + card owner male, target male + %1 zeigt von %2s %3 auf sich selbst. + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female %1 zeigt von %2s %3 auf %4. + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + %1 zeigt von %2s %3 auf %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + %1 zeigt von %2s %3 auf %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + %1 zeigt von %2s %3 auf %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + %1 zeigt von %2s %3 auf %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + %1 zeigt von %2s %3 auf %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + %1 zeigt von %2s %3 auf %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + %1 zeigt von %2s %3 auf %4. + + + + %1 points from her %2 to her %3. + female + %1 zeigt von ihrem %2 auf ihren %3. + + + + %1 points from his %2 to his %3. + male + %1 zeigt von seinem %2 auf seinen %3. + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + %1 zeigt von ihrem %2 auf %3s %4. + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + %1 zeigt von ihrem %2 auf %3s %4. + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + %1 zeigt von seinem %2 auf %3s %4. + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + %1 zeigt von seinem %2 auf %3s %4. + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + %1 zeigt von %2s %3 auf ihren eigenen %4. + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + %1 zeigt von %2s %3 auf ihren eigenen %4. + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + %1 zeigt von %2s %3 auf seinen eigenen %4. + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + %1 zeigt von %2s %3 auf seinen eigenen %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + %1 zeigt von %2s %3 auf %4s %5. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + %1 zeigt von %2s %3 auf %4s %5. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + %1 zeigt von %2s %3 auf %4s %5. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + %1 zeigt von %2s %3 auf %4s %5. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + %1 zeigt von %2s %3 auf %4s %5. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + %1 zeigt von %2s %3 auf %4s %5. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + %1 zeigt von %2s %3 auf %4s %5. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + %1 zeigt von %2s %3 auf %4s %5. + - + %1 places %n %2 counter(s) on %3 (now %4). + female %1 legt eine %2 Marke auf %3 (jetzt %4). %1 legt %n %2 Marken auf %3 (jetzt %4). - + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 legt eine %2 Marke auf %3 (jetzt %4). + %1 legt %n %2 Marken auf %3 (jetzt %4). + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 entfernt eine %2 Marke von %3 (jetzt %4). + %1 entfernt %n %2 Marken von %3 (jetzt %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male %1 entfernt eine %2 Marke von %3 (jetzt %4). %1 entfernt %n %2 Marken von %3 (jetzt %4). - + + %1 taps her permanents. + female + %1 tappt ihre bleibenden Karten. + + + + %1 untaps her permanents. + female + %1 enttappt ihre bleibenden Karten. + + + + %1 taps his permanents. + male + %1 tappt seine bleibenden Karten. + + + + %1 untaps his permanents. + male + %1 enttappt seine bleibenden Karten. + + + + %1 taps %2. + female + %1 tappt %2. + + + + %1 untaps %2. + female + %1 enttappt %2. + + + + %1 taps %2. + male + %1 tappt %2. + + + + %1 untaps %2. + male + %1 enttappt %2. + + + + %1 sets counter %2 to %3 (%4%5). + female + %1 setzt Zähler %2 auf %3 (%4%5). + + + + %1 sets counter %2 to %3 (%4%5). + male + %1 setzt Zähler %2 auf %3 (%4%5). + + + + %1 sets %2 to not untap normally. + female + %1 setzt %2 auf explizites Enttappen. + + + + %1 sets %2 to not untap normally. + male + %1 setzt %2 auf explizites Enttappen. + + + + %1 sets %2 to untap normally. + female + %1 setzt %2 auf normales Enttappen. + + + + %1 sets %2 to untap normally. + male + %1 setzt %2 auf normales Enttappen. + + + + %1 sets PT of %2 to %3. + female + %1 setzt Kampfwerte von %2 auf %3. + + + + %1 sets PT of %2 to %3. + male + %1 setzt Kampfwerte von %2 auf %3. + + + + %1 sets annotation of %2 to %3. + female + %1 versieht %2 mit dem Hinweis %3. + + + + %1 sets annotation of %2 to %3. + male + %1 versieht %2 mit dem Hinweis %3. + + + + %1 is looking at the top %2 cards %3. + female + %1 sieht sich die obersten %2 Karten %3 an. + + + + %1 is looking at the top %2 cards %3. + male + %1 sieht sich die obersten %2 Karten %3 an. + + + + %1 is looking at %2. + female + %1 sieht sich %2 an. + + + + %1 is looking at %2. + male + %1 sieht sich %2 an. + + + + %1 stops looking at %2. + female + %1 sieht sich %2 nicht mehr an. + + + + %1 stops looking at %2. + male + %1 sieht sich %2 nicht mehr an. + + + + %1 reveals %2 to %3. + p1 female, p2 female + %1 zeigt %3 %2. + + + + %1 reveals %2 to %3. + p1 female, p2 male + %1 zeigt %3 %2. + + + + %1 reveals %2 to %3. + p1 male, p2 female + %1 zeigt %3 %2. + + + + %1 reveals %2 to %3. + p1 male, p2 male + %1 zeigt %3 %2. + + + + %1 reveals %2. + female + %1 zeigt %2 offen vor. + + + + %1 reveals %2. + male + %1 zeigt %2 offen vor. + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female %1 zeigt %4 zufällig %2%3 vor. - + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + %1 zeigt %4 zufällig %2%3 vor. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + %1 zeigt %4 zufällig %2%3 vor. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + %1 zeigt %4 zufällig %2%3 vor. + + + %1 randomly reveals %2%3. + female %1 zeigt zufällig %2%3 offen vor. - + + %1 randomly reveals %2%3. + male + %1 zeigt zufällig %2%3 offen vor. + + + %1 reveals %2%3 to %4. + p1 female, p2 female %1 zeigt %4 %2%3 vor. - + + %1 reveals %2%3 to %4. + p1 female, p2 male + %1 zeigt %4 %2%3 vor. + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + %1 zeigt %4 %2%3 vor. + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + %1 zeigt %4 %2%3 vor. + + + %1 reveals %2%3. + female %1 zeigt %2%3 offen vor. + + + %1 reveals %2%3. + male + %1 zeigt %2%3 offen vor. + + + + It is now %1's turn. + female + %1 ist am Zug. + + + + It is now %1's turn. + male + %1 ist am Zug. + + + %1 takes a mulligan to %n. + + %1 nimmt einen Mulligan auf %n. + %1 nimmt einen Mulligan auf %n. + + + + + %1 draws his initial hand. + %1 zieht seine Starthand. + + + + %1 draws her initial hand. + %1 zieht ihre Starthand. + + + %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 places %n %2 counter(s) on %3 (now %4). + + %1 legt eine %2 Marke auf %3 (jetzt %4). + %1 legt %n %2 Marken auf %3 (jetzt %4). + + + + %1 removes %n %2 counter(s) from %3 (now %4). + + %1 entfernt eine %2 Marke von %3 (jetzt %4). + %1 entfernt %n %2 Marken von %3 (jetzt %4). + + + + her permanents + ihre bleibenden Karten + + + %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. + %1 creates token: %2 (%3). %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 zeigt von %2s %3 auf %4s %5. %1 places %n counter(s) (%2) on %3 (now %4). @@ -2463,7 +3770,7 @@ Lokale Version ist %1, Serverversion ist %2. - + red rote @@ -2471,7 +3778,7 @@ Lokale Version ist %1, Serverversion ist %2. - + yellow gelbe @@ -2479,7 +3786,7 @@ Lokale Version ist %1, Serverversion ist %2. - + green grüne @@ -2487,24 +3794,20 @@ Lokale Version ist %1, Serverversion ist %2. - %1 sets counter %2 to %3 (%4%5). - %1 setzt Zähler %2 auf %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 setzt Kampfwerte von %2 auf %3. - %1 sets annotation of %2 to %3. - %1 versieht %2 mit dem Hinweis %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. + %1 sieht sich die obersten %2 Karten %3 an. from graveyard @@ -2599,9 +3902,8 @@ Lokale Version ist %1, Serverversion ist %2. %1 entfernt %2 Zählmarken von %3 (jetzt %4). - %1 %2 %3. - %1 %2 %3. + %1 %2 %3. %1 sets counter "%2" to %3 (%4%5). @@ -2612,24 +3914,20 @@ Lokale Version ist %1, Serverversion ist %2. %1 sieht sich die obersten %2 Karten %3 an. - %1 is looking at %2. - %1 sieht sich %2 an. + %1 sieht sich %2 an. - %1 stops looking at %2. - %1 sieht sich %2 nicht mehr an. + %1 sieht sich %2 nicht mehr an. - %1 reveals %2 to %3. - %1 zeigt %3 %2. + %1 zeigt %3 %2. - %1 reveals %2. - %1 zeigt %2 offen vor. + %1 zeigt %2 offen vor. %1 randomly reveals %2 from %3 to %4. @@ -2648,7 +3946,7 @@ Lokale Version ist %1, Serverversion ist %2. %1 zeigt %2 aus %3 offen vor. - + ending phase die Zugendphase @@ -2677,57 +3975,56 @@ Lokale Version ist %1, Serverversion ist %2. %1 sieht sich %2s %3 nicht mehr an - It is now %1's turn. - %1 ist am Zug. + %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 @@ -2736,7 +4033,7 @@ Lokale Version ist %1, Serverversion ist %2. das Ende-des-Zuges-Segment - + It is now the %1. Es ist nun %1. @@ -2745,14 +4042,12 @@ Lokale Version ist %1, Serverversion ist %2. %1 bewegt %2 %3 nach %4 - taps - tappt + tappt - untaps - enttappt + enttappt %1 creates token: <font color="blue">%2</font> @@ -2775,9 +4070,8 @@ Lokale Version ist %1, Serverversion ist %2. %1 entfernt %2 Zählmarken von %3 (jetzt %4) - his permanents - seine bleibenden Karten + seine bleibenden Karten %1 %2 %3 @@ -2788,14 +4082,12 @@ Lokale Version ist %1, Serverversion ist %2. %1 setzt Zähler "%2" auf %3 (%4%5) - %1 sets %2 to not untap normally. - %1 setzt %2 auf explizites Enttappen. + %1 setzt %2 auf explizites Enttappen. - %1 sets %2 to untap normally. - %1 setzt %2 auf normales Enttappen. + %1 setzt %2 auf normales Enttappen. %1 is looking at the top %2 cards of %3's %4 @@ -2809,12 +4101,12 @@ Lokale Version ist %1, Serverversion ist %2. MessagesSettingsPage - + &Add &Hinzufügen - + &Remove &Entfernen @@ -2827,12 +4119,12 @@ Lokale Version ist %1, Serverversion ist %2. Entfernen - + Add message Nachricht hinzufügen - + Message: Nachricht: @@ -2898,21 +4190,21 @@ Lokale Version ist %1, Serverversion ist %2. 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 @@ -2921,37 +4213,37 @@ Lokale Version ist %1, Serverversion ist %2. 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 - + Ctrl+F3 Ctrl+F3 - + F4 F4 @@ -2960,73 +4252,73 @@ Lokale Version ist %1, Serverversion ist %2. 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 - + &Undo last draw Zuletzt gezogene Karte zur&ücklegen - + 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 @@ -3035,7 +4327,7 @@ Lokale Version ist %1, Serverversion ist %2. Entfe&rnte Karten - + &Sideboard &Sideboard @@ -3048,33 +4340,33 @@ Lokale Version ist %1, Serverversion ist %2. &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 @@ -3083,28 +4375,28 @@ Lokale Version ist %1, Serverversion ist %2. 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 @@ -3113,37 +4405,37 @@ Lokale Version ist %1, Serverversion ist %2. &Mulligan nehmen... - + Ctrl+M Ctrl+M - + &Shuffle Mi&schen - + Ctrl+S Ctrl+S - + &Counters &Zähler - + &Untap all permanents &Enttappe alle bleibenden Karten - + Ctrl+Shift+D Ctrl+Shift+D - + Ctrl+U Ctrl+U @@ -3172,42 +4464,42 @@ Lokale Version ist %1, Serverversion ist %2. 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 @@ -3300,50 +4592,50 @@ Lokale Version ist %1, Serverversion ist %2. 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 @@ -3356,12 +4648,12 @@ Lokale Version ist %1, Serverversion ist %2. Neue Lebenspunkte insgesamt: - + Roll die Würfeln - + Number of sides: Anzahl der Seiten: @@ -3475,17 +4767,17 @@ Lokale Version ist %1, Serverversion ist %2. Sideboard - + Cockatrice decks (*.cod) Cockatrice Decks (*.cod) - + Plain text decks (*.dec *.mwDeck) Text Decks (*.dec *.mwDeck) - + All files (*.*) Alle Dateien (*.*) @@ -3561,40 +4853,77 @@ Lokale Version ist %1, Serverversion ist %2. Langer Name + + ShutdownDialog + + + &Reason for shutdown: + G&rund für die Abschaltung: + + + + &Time until shutdown (minutes): + &Zeit bis zur Abschaltung (Minuten): + + + + &OK + &OK + + + + &Cancel + &Abbrechen + + + + Shut down server + Server abschalten + + TabAdmin - + Update server &message Server&nachricht aktualisieren - + Shut down server + Server abschalten + + + + &Shut down server + &Server abschalten + + + 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 @@ -3689,102 +5018,107 @@ Bitte geben Sie einen Namen ein: TabGame - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + &Phases &Phasen - + &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 - + + Ctrl+Q + Ctrl+Q + + + Kicked Herausgeworfen - + You have been kicked out of the game. Sie wurden aus dem Spiel geworfen. @@ -3805,7 +5139,7 @@ Bitte geben Sie einen Namen ein: Spiel s&tarten - + &Say: &Sagen: @@ -3818,22 +5152,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? @@ -3850,32 +5184,32 @@ Bitte geben Sie einen Namen ein: TabMessage - + Personal &talk Persönliches &Gespräch - + &Leave Ver&lassen - + This user is ignoring you. Dieser Benutzer ignoriert Sie. - + %1 has left the server. %1 hat den Server verlassen. - + %1 has joined the server. %1 hat den Server betreten. - + Talking to %1 Gespräch mit %1 @@ -3883,27 +5217,27 @@ Bitte geben Sie einen Namen ein: TabRoom - + &Say: &Sagen: - + Chat Unterhaltung - + &Room &Raum - + &Leave room Raum ver&lassen - + You are flooding the chat. Please wait a couple of seconds. Sie überfluten den Chatraum. Bitte warten Sie ein paar Sekunden. @@ -3950,42 +5284,51 @@ Bitte geben Sie einen Namen ein: UserInfoBox - + User information Benutzerinformationen - + Real name: Richtiger Name: - + + Gender: + Geschlecht: + + + Location: Ort: - + User level: Nutzerstatus: - + Administrator Administrator - - Judge - Schiedsrichter + + Moderator + Moderator - + Judge + Schiedsrichter + + + Registered user Registrierter Benutzer - + Unregistered user Unregistrierter Benutzer @@ -3993,130 +5336,153 @@ Bitte geben Sie einen Namen ein: 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 + + + Enable &sounds + &Sound anschalten + + + + Path to sounds directory: + Pfad zum Verzeichnis mit den Sounddateien: + + + + Choose path + Pfad auswählen + UserList - + Users online: %1 Benutzer online: %1 - + Users in this room: %1 Benutzer in diesem Raum: %1 - + Buddies online: %1 / %2 Freunde online: %1 / %2 - + Ignored users online: %1 / %2 Ignorierte Benutzer online: %1 / %2 - + + %1's games + %1s Spiele + + + User &details Benutzer&details - + Direct &chat &Persönliches Gespräch - + + Show this user's &games + Spiele dieses &Benutzers anzeigen + + + Add to &buddy list Zur &Freundesliste hinzufügen - + Remove from &buddy list Von &Freundesliste entfernen - + Add to &ignore list &Ignorieren - + Remove from &ignore list Nicht mehr &ignorieren - + Ban from &server Vom &Server bannen - Duration - Dauer + Dauer - Please enter the duration of the ban (in minutes). Enter 0 for an indefinite ban. - Bitte geben Sie die Dauer des Banns ein (in Minuten). + Bitte geben Sie die Dauer des Banns ein (in Minuten). Geben Sie 0 ein für einen unbefristeten Bann. WndDeckEditor - + &Search for: &Suchen nach: - + Deck &name: Deck &Name: - + &Comments: &Kommentare: - + Deck editor [*] Deck-Editor [*] - + &New deck &Neues Deck - + &Load deck... Deck &laden... - + &Save deck Deck &speichern @@ -4125,37 +5491,37 @@ Geben Sie 0 ein für einen unbefristeten Bann. Deck &speichern unter... - + Save deck &as... Deck s&peichern unter... - + Save deck to clip&board Deck in Z&wischenablage speichern - + &Print deck... Deck &drucken... - + &Close S&chließen - + Ctrl+Q Ctrl+Q - + &Edit sets... &Editionen bearbeiten... - + &Deck &Deck @@ -4164,27 +5530,27 @@ Geben Sie 0 ein für einen unbefristeten Bann. &Editionen - + Add card to &maindeck Karte zu&m Hauptdeck hinzufügen - + Return Return - + Enter Enter - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter @@ -4193,7 +5559,7 @@ Geben Sie 0 ein für einen unbefristeten Bann. Ctrl+M - + Add card to &sideboard Karte zum &Sideboard hinzufügen @@ -4202,88 +5568,98 @@ Geben Sie 0 ein für einen unbefristeten Bann. Ctrl+N - + &Search... &Suchen... - + &Clear search Suche a&ufheben - + + &Update prices + &Preise aktualisieren + + + + Ctrl+U + Ctrl+U + + + Load deck from cl&ipboard... Deck aus &Zwischenablage laden... - + &Card database &Kartendatenbank - + &Remove row Zeile entfe&rnen - + Del Entf - + &Increment number Anzahl er&höhen - + + + - + &Decrement number Anzahl v&erringern - + - - - + Are you sure? Bist du sicher? - + The decklist has been modified. Do you want to save the changes? Die Deckliste wurde verändert. Willst du die Änderungen speichern? - + Load deck 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 f4912678f..4c6421f19 100644 --- a/cockatrice/translations/cockatrice_en.ts +++ b/cockatrice/translations/cockatrice_en.ts @@ -37,90 +37,125 @@ 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: - + Card rendering - + Display card names on cards having a picture - + Hand layout - + Display hand horizontally (wastes space) - + Table grid layout - + Invert vertical coordinate - + + Minimum player count for multi-column layout: + + + + Zone view layout - + Sort by name - + Sort by type - - - - - + + + + + Choose path + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + + + + + &Cancel + + + + + Ban user from server + + + CardDatabaseModel @@ -152,22 +187,42 @@ CardInfoWidget - + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + Name: - + Mana cost: - + Card type: - + P / T: @@ -175,197 +230,202 @@ CardItem - + &Play - + &Hide - + &Tap - + &Untap - + Toggle &normal untapping - + &Flip - + &Clone - + Ctrl+H - + &Attach to card... - + Ctrl+A - + Unattac&h - - - &Power / toughness - - - - - &Increase power - - - - - Ctrl++ - - - - - &Decrease power - - - - - Ctrl+- - - - - - I&ncrease toughness - - - Alt++ + &Draw arrow... - D&ecrease toughness + &Power / toughness - Alt+- + &Increase power - In&crease power and toughness + Ctrl++ - Ctrl+Alt++ + &Decrease power - Dec&rease power and toughness + Ctrl+- - Ctrl+Alt+- + I&ncrease toughness - Set &power and toughness... + Alt++ - Ctrl+P + D&ecrease toughness - &Set annotation... + Alt+- + + + + + In&crease power and toughness - red + Ctrl+Alt++ - yellow + Dec&rease power and toughness - green + Ctrl+Alt+- + + + + + Set &power and toughness... - &Add counter (%1) + Ctrl+P - - &Remove counter (%1) + + &Set annotation... + + + + + red - &Set counters (%1)... + yellow - &top of library - - - - - &bottom of library + green - &graveyard - - - - - Ctrl+Del + &Add counter (%1) - &exile + &Remove counter (%1) + &Set counters (%1)... + + + + + &top of library + + + + + &bottom of library + + + + + &graveyard + + + + + Ctrl+Del + + + + + &exile + + + + &Move to @@ -373,218 +433,416 @@ CardZone - - his hand - nominative + + her hand + nominative, female owner - + %1's hand - nominative + nominative, female owner - of his hand - genitive + his hand + nominative, male owner + %1's hand + nominative, male owner + + + + + of her hand + genitive, female owner + + + + of %1's hand - genitive + genitive, female owner - his hand - accusative + of his hand + genitive, male owner + of %1's hand + genitive, male owner + + + + + her hand + accusative, female owner + + + + %1's hand - accusative + accusative, female owner - - his library - nominative + + his hand + accusative, male owner - + + %1's hand + accusative, male owner + + + + + her library + nominative, female owner + + + + %1's library - nominative + nominative, female owner - of his library - genitive + his library + nominative, male owner + %1's library + nominative, male owner + + + + + of her library + genitive, female owner + + + + of %1's library - genitive + genitive, female owner - his library - accusative + of his library + genitive, male owner + of %1's library + genitive, male owner + + + + + her library + accusative, female owner + + + + %1's library - accusative + accusative, female owner - - his graveyard - nominative + + his library + accusative, male owner - + + %1's library + accusative, male owner + + + + + her graveyard + nominative, female owner + + + + %1's graveyard - nominative + nominative, female owner - of his graveyard - genitive + his graveyard + nominative, male owner + %1's graveyard + nominative, male owner + + + + + of her graveyard + genitive, female owner + + + + of %1's graveyard - genitive + genitive, female owner - his graveyard - accusative + of his graveyard + genitive, male owner + of %1's graveyard + genitive, male owner + + + + + her graveyard + accusative, female owner + + + + %1's graveyard - accusative + accusative, female owner - - his exile - nominative + + his graveyard + accusative, male owner - + + %1's graveyard + accusative, male owner + + + + + her exile + nominative, female owner + + + + %1's exile - nominative + nominative, female owner - of his exile - genitive + his exile + nominative, male owner + %1's exile + nominative, male owner + + + + + of her exile + genitive, female owner + + + + of %1's exile - genitive + genitive, female owner - his exile - accusative + of his exile + genitive, male owner + of %1's exile + genitive, male owner + + + + + her exile + accusative, female owner + + + + %1's exile - accusative + accusative, female owner - - his sideboard - nominative + + his exile + accusative, male owner - + + %1's exile + accusative, male owner + + + + + her sideboard + nominative, female owner + + + + %1's sideboard - nominative + nominative, female owner - of his sideboard - genitive + his sideboard + nominative, male owner + %1's sideboard + nominative, male owner + + + + + of her sideboard + genitive, female owner + + + + of %1's sideboard - genitive + genitive, female owner - his sideboard - accusative + of his sideboard + genitive, male owner + of %1's sideboard + genitive, male owner + + + + + her sideboard + accusative, female owner + + + + %1's sideboard - accusative + accusative, female owner + + + + + his sideboard + accusative, male owner + + + + + %1's sideboard + accusative, male owner + + + + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General DeckListModel - + Number - + Card + + + Price + + DeckViewContainer - + Load &local deck - + Load d&eck from server - + Ready to s&tart - + Load deck @@ -673,82 +931,82 @@ - + &Password: - + P&layers: - + Game type - + Only &buddies can join - + Only &registered users can join - + Joining restrictions - + &Spectators allowed - + Spectators &need a password to join - + Spectators can &chat - + Spectators see &everything - + Spectators - + &OK - + &Cancel - + Create game - + Error - + Server error. @@ -890,54 +1148,59 @@ 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 - + + Deck editor + + + + Messages - + &Close @@ -945,83 +1208,94 @@ GameSelector - + C&reate - + &Join - - - - - - - + + + + + + + + Error - + + Please join the appropriate room first. + + + + Wrong password. - + Spectators are not allowed in this game. - + The game is already full. - + The game does not exist any more. - + This game is only open to registered users. - + This game is only open to its creator's buddies. - + You are being ignored by the creator of this game. - + Join game - + Password: - + Games - + Show &full games - + + Show &running games + + + + J&oin as spectator @@ -1037,67 +1311,72 @@ GamesModel - + yes - + no - + Creator - + Description - + yes, free for spectators - + buddies only - + reg. users only - + not allowed - Game type - - - - - Password - - - - - Restrictions + Room - Players + Game type + Password + + + + + Restrictions + + + + + Players + + + + Spectators @@ -1105,50 +1384,50 @@ GeneralSettingsPage - - - + + + Choose path - + Personal settings - + Language: - + Download card pictures on the fly - + Paths - + Decks directory: - + Pictures directory: - + Path to card database: - - + + English English @@ -1167,206 +1446,236 @@ + Scheduled server shutdown. + + + + Unknown reason. - + Connection closed - + The server has terminated your connection. Reason: %1 - + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + Number of players - + Please enter the number of players. - - + + Player %1 - + About Cockatrice - + Version %1 - + Authors: - + Translators: - + Spanish: - + Portugese (Portugal): - + Portugese (Brazil): - + French: - + Japanese: - + Russian: - - - - - - + + Czech: + + + + + Slovak: + + + + + + + + + Error - + Server timeout - + Invalid login data. - + There is already an active session using this user name. Please close that session first and re-login. - + Socket error: %1 - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %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? @@ -1374,212 +1683,962 @@ Local version is %1, remote version is %2. 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. - - - %1 draws %n card(s). - + %1 draws a card. %1 draws %n cards. - - %1 undoes his last draw. + + You have joined game #%1. + female + + + + + You have joined game #%1. + male + + + + + %1 has joined the game. + female + + + + + %1 has joined the game. + male + + + + + %1 has left the game. + female + + + + + %1 has left the game. + male + + + + + %1 has loaded a local deck. + female + + + + + %1 has loaded a local deck. + male + + + + + %1 has loaded deck #%2. + female + + + + + %1 has loaded deck #%2. + male + + + + + %1 is ready to start the game. + female + + + + + %1 is ready to start the game. + male + + + + + %1 is not ready to start the game any more. + female + + + + + %1 is not ready to start the game any more. + male + + + + + %1 has conceded the game. + female + + + + + %1 has conceded the game. + male + + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male - %1 undoes his last draw (%2). + %1 rolls a %2 with a %3-sided die. + female - - from table + + %1 rolls a %2 with a %3-sided die. + male - + - from graveyard - + %1 draws %n card(s). + female + + %1 draws a card. + %1 draws %n cards. + - + - from exile + %1 draws %n card(s). + male + + %1 draws a card. + %1 draws %n cards. + + + + + %1 undoes his last draw. - - from hand - - - - - the bottom card of his library + + %1 undoes her last draw. - from the bottom of his library + %1 undoes his last draw (%2). - - the top card of his library - - - - - from the top of his library - - - - - from library + + %1 undoes her last draw (%2). - from sideboard + from table + from graveyard + + + + + from exile + + + + + from hand + + + + + the bottom card of his library + + + + + the bottom card of her library + + + + + from the bottom of his library + + + + + from the bottom of her library + + + + + the top card of his library + + + + + the top card of her library + + + + + from the top of his library + + + + + from the top of her library + + + + + from library + + + + + from sideboard + + + + from the stack - + %1 gives %2 control over %3. - + %1 puts %2 into play tapped%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 into her library. + + + + %1 puts %2%3 on bottom of his library. - + + %1 puts %2%3 on bottom of her library. + + + + %1 puts %2%3 on top of his library. - + + %1 puts %2%3 on top of her library. + + + + %1 puts %2%3 into his library at position %4. - + + %1 puts %2%3 into her library at position %4. + + + + %1 moves %2%3 to sideboard. - + %1 plays %2%3. - - - - a card - + + + %1 takes a mulligan to %n. + female + + + + + + + + %1 takes a mulligan to %n. + male + + + + - + %1 flips %2 face-down. + female - + + %1 flips %2 face-down. + male + + + + %1 flips %2 face-up. + female - - %1 attaches %2 to %3's %4. + + %1 flips %2 face-up. + male - + + %1 destroys %2. + female + + + + + %1 destroys %2. + male + + + + %1 unattaches %2. + female - + + %1 unattaches %2. + male + + + + + %1 creates token: %2%3. + female + + + + + %1 creates token: %2%3. + male + + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + %1 places a %2 counter on %3 (now %4). + %1 places %n %2 counters on %3 (now %4). + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 places a %2 counter on %3 (now %4). + %1 places %n %2 counters on %3 (now %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 removes a %2 counter from %3 (now %4). + %1 removes %n %2 counters from %3 (now %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + %1 removes a %2 counter from %3 (now %4). + %1 removes %n %2 counters from %3 (now %4). + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + + + + + %1 sets counter %2 to %3 (%4%5). + male + + + + + %1 sets %2 to not untap normally. + female + + + + + %1 sets %2 to not untap normally. + male + + + + + %1 sets %2 to untap normally. + female + + + + + %1 sets %2 to untap normally. + male + + + + + %1 sets PT of %2 to %3. + female + + + + + %1 sets PT of %2 to %3. + male + + + + + %1 sets annotation of %2 to %3. + female + + + + + %1 sets annotation of %2 to %3. + male + + + + + %1 is looking at the top %2 cards %3. + female + + + + + %1 is looking at the top %2 cards %3. + male + + + + + %1 is looking at %2. + female + + + + + %1 is looking at %2. + male + + + + + %1 stops looking at %2. + female + + + + + %1 stops looking at %2. + male + + + + + %1 reveals %2 to %3. + p1 female, p2 female + + + + + %1 reveals %2 to %3. + p1 female, p2 male + + + + + %1 reveals %2 to %3. + p1 male, p2 female + + + + + %1 reveals %2 to %3. + p1 male, p2 male + + + + + %1 reveals %2. + female + + + + + %1 reveals %2. + male + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 randomly reveals %2%3. + female + + + + + %1 randomly reveals %2%3. + male + + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 reveals %2%3. + female + + + + + %1 reveals %2%3. + male + + + + + It is now %1's turn. + female + + + + + It is now %1's turn. + male + + + + + + a card @@ -1597,7 +2656,7 @@ Local version is %1, remote version is %2. - + red @@ -1605,7 +2664,7 @@ Local version is %1, remote version is %2. - + yellow @@ -1613,7 +2672,7 @@ Local version is %1, remote version is %2. - + green @@ -1621,266 +2680,138 @@ Local version is %1, remote version is %2. - - %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. + + %1 draws his initial hand. - - 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 destroys %2. - - - - - %1 creates token: %2%3. - - - - - %1 points from %2's %3 to %4. + + %1 draws her initial hand. - %1 places %n %2 counter(s) on %3 (now %4). - + %1 places a %2 counter on %3 (now %4). %1 places %n %2 counters on %3 (now %4). - %1 removes %n %2 counter(s) from %3 (now %4). - + %1 removes a %2 counter from %3 (now %4). %1 removes %n %2 counters from %3 (now %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 - + + %1 attaches %2 to %3's %4. + p1 female, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + + + + 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: @@ -1946,322 +2877,322 @@ Local version is %1, remote version is %2. Player - - - + + + Move to &top of library - - - + + + Move to &bottom of library - - + + Move to &graveyard - + &View library - + Reveal &library to - + Reveal t&op card to - + Move top cards to &graveyard... - + F3 - + View &top cards of library... - + &View graveyard - + F4 - + &View sideboard - + Player "%1" - + &Hand - + &Library - + &Graveyard - + &Sideboard - + View top cards of library - + Number of cards: - + &Draw card - + &View exile - + &Exile - - + + Move to &hand - - + + Move to &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 - + &Undo last draw - + Move top cards to &exile... - + Put top card on &bottom - + &Reveal to - + Reveal r&andom card to - + C&ard - + &All players - + Ctrl+F3 - + Ctrl+Shift+D - + 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 @@ -2327,17 +3258,17 @@ Local version is %1, remote version is %2. - + Cockatrice decks (*.cod) - + Plain text decks (*.dec *.mwDeck) - + All files (*.*) @@ -2406,40 +3337,73 @@ Local version is %1, remote version is %2. + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + + + + + &Cancel + + + + + Shut down server + + + TabAdmin - + Update server &message - + + &Shut down server + + + + Server administration functions - + &Unlock functions - + &Lock functions - + Unlock administration functions - + Do you really want to unlock the administration functions? - + Administration @@ -2514,127 +3478,132 @@ Please enter a name: TabGame - + F5 - + F6 - + F7 - + F8 - + F9 - + F10 - + &Phases - + &Game - + Next &phase - + Ctrl+Space - + Next &turn - + Ctrl+Return - + Ctrl+Enter - + &Remove all local arrows - + Ctrl+R - + &Concede - + F2 - + &Leave game - + + Ctrl+Q + + + + &Say: - + Concede - + Are you sure you want to concede this game? - + Leave game - + Are you sure you want to leave this game? - + Kicked - + You have been kicked out of the game. @@ -2647,32 +3616,32 @@ Please enter a name: TabMessage - + Personal &talk - + &Leave - + This user is ignoring you. - + %1 has left the server. - + %1 has joined the server. - + Talking to %1 @@ -2680,27 +3649,27 @@ Please enter a name: TabRoom - + &Say: - + Chat - + &Room - + &Leave room - + You are flooding the chat. Please wait a couple of seconds. @@ -2724,42 +3693,47 @@ Please enter a name: UserInfoBox - + User information - + Real name: - + + Gender: + + + + Location: - + User level: - + Administrator - - Judge + + Moderator - + Registered user - + Unregistered user @@ -2767,277 +3741,301 @@ Please enter a name: UserInterfaceSettingsPage - + General interface settings - + &Double-click cards to play them (instead of single-click) - + Animation settings - + &Tap/untap animation + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + + UserList - + Users online: %1 - + Users in this room: %1 - + Buddies online: %1 / %2 - + Ignored users online: %1 / %2 - + + %1's games + + + + User &details - + Direct &chat - + + Show this user's &games + + + + Add to &buddy list - + Remove from &buddy list - + Add to &ignore list - + Remove from &ignore list - + Ban from &server - - - Duration - - - - - Please enter the duration of the ban (in minutes). -Enter 0 for an indefinite ban. - - WndDeckEditor - + &Search for: - + Deck &name: - + &Comments: - + Deck editor [*] - + &New deck - + &Load deck... - + Load deck from cl&ipboard... - + &Save deck - + + &Update prices + + + + + Ctrl+U + + + + 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? diff --git a/cockatrice/translations/cockatrice_es.ts b/cockatrice/translations/cockatrice_es.ts index 38b6ee326..cee81068a 100644 --- a/cockatrice/translations/cockatrice_es.ts +++ b/cockatrice/translations/cockatrice_es.ts @@ -37,66 +37,71 @@ 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: - + Card rendering Renderizado de las cartas - + Display card names on cards having a picture Mostrar nombre de las cartas en aquellas que tengan imagen - + 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 + + + Minimum player count for multi-column layout: + + Economical layout Disposición Económica - + Invert vertical coordinate Invertir coordenada vertical @@ -105,30 +110,61 @@ 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 + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Por favor, introduce la duración del ban (en minutos) +Indica 0 para un ban indefinido. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + &Aceptar + + + + &Cancel + &Cancelar + + + + Ban user from server + + + CardDatabaseModel @@ -160,22 +196,42 @@ CardInfoWidget - + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + Name: Nombre: - + Mana cost: Coste de mana: - + Card type: Tipo de carta: - + P / T: F / R: @@ -183,57 +239,57 @@ CardItem - + &Play &Jugar - + &Hide &Ocultar - + &Tap &Girar - + &Untap &Enderezar - + Toggle &normal untapping Alternar enderezamiento &normal - + &Flip &Voltear - + &Clone &Clonar - + Ctrl+H Ctrl+H - + &Attach to card... Ane&xar a una carta... - + Ctrl+A Ctrl+A - + Unattac&h Desane&xar @@ -242,142 +298,147 @@ Establecer &F/R... - + + &Draw arrow... + + + + &Power / toughness &Fuerza / resistencia - + &Increase power &Incrementar fuerza - + Ctrl++ Ctrl++ - + &Decrease power &Decrementar fuerza - + Ctrl+- Ctrl+- - + I&ncrease toughness I&ncrementar resistencia - + Alt++ Alt++ - + D&ecrease toughness D&ecrementar resistencia - + Alt+- Alt+- - + In&crease power and toughness In&crementar fuerza y resistencia - + Ctrl+Alt++ Ctrl+Alt++ - + Dec&rease power and toughness Dec&rementar fuerza y resistencia - + Ctrl+Alt+- Ctrl+Alt+- - + Set &power and toughness... Establecer &fuerza y resistencia... - + Ctrl+P Ctrl+P - + &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 @@ -465,40 +526,34 @@ de la reserva &de %1 - his hand nominative - su mano + su mano - %1's hand nominative - mano de %1 + mano de %1 - of his hand genitive - de su mano + de su mano - of %1's hand genitive - de la mano de %1 + de la mano de %1 - his hand accusative - su mano + su mano - %1's hand accusative - mano de %1 + mano de %1 his hand @@ -511,40 +566,34 @@ mano &de %1 - his library nominative - su biblioteca + su biblioteca - %1's library nominative - biblioteca de %1 + biblioteca de %1 - of his library genitive - de su biblioteca + de su biblioteca - of %1's library genitive - de la biblioteca de %1 + de la biblioteca de %1 - his library accusative - su biblioteca + su biblioteca - %1's library accusative - biblioteca de %1 + biblioteca de %1 his library @@ -557,40 +606,394 @@ biblioteca &de %1 - - his graveyard - nominative - su cementerio + + her hand + nominative, female owner + - - %1's graveyard - nominative - cementerio de %1 + + %1's hand + nominative, female owner + + + + + his hand + nominative, male owner + su mano + + + + %1's hand + nominative, male owner + + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + + + + + of his hand + genitive, male owner + de su mano + + + + of %1's hand + genitive, male owner + + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + + + + + his hand + accusative, male owner + su mano + + + + %1's hand + accusative, male owner + + + + + her library + nominative, female owner + + + + + %1's library + nominative, female owner + + + + + his library + nominative, male owner + su biblioteca + + + + %1's library + nominative, male owner + + + + + of her library + genitive, female owner + + + + + of %1's library + genitive, female owner + + + + + of his library + genitive, male owner + de su biblioteca + + + + of %1's library + genitive, male owner + + + + + her library + accusative, female owner + + + + + %1's library + accusative, female owner + + + + + his library + accusative, male owner + su biblioteca + + + + %1's library + accusative, male owner + + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + + + + + his graveyard + nominative, male owner + su cementerio + + + + %1's graveyard + nominative, male owner + + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + + + + + of his graveyard + genitive, male owner + de su cementerio + + + + of %1's graveyard + genitive, male owner + + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + + + + + his graveyard + accusative, male owner + su cementerio + + + + %1's graveyard + accusative, male owner + + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + el exilio de %1 + + + + his exile + nominative, male owner + su exilio + + + + %1's exile + nominative, male owner + el exilio de %1 + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + del exilio de %1 + + + + of his exile + genitive, male owner + de su exilio + + + + of %1's exile + genitive, male owner + del exilio de %1 + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + el exilio de %1 + + + + his exile + accusative, male owner + su exilio + + + + %1's exile + accusative, male owner + el exilio de %1 + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + la reserva de %1 + + + + his sideboard + nominative, male owner + su reserva + + + + %1's sideboard + nominative, male owner + la reserva de %1 + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + + + + + of his sideboard + genitive, male owner + de su reserva + + + + of %1's sideboard + genitive, male owner + + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + la reserva de %1 + + + + his sideboard + accusative, male owner + su reserva + + + + %1's sideboard + accusative, male owner + la reserva de %1 + + + his graveyard + nominative + su cementerio + + + %1's graveyard + nominative + cementerio de %1 + + of his graveyard genitive - de su cementerio + de su cementerio - of %1's graveyard genitive - del cementerio de %1 + del cementerio de %1 - his graveyard accusative - su cementerio + su cementerio - %1's graveyard accusative - cementerio de %1 + cementerio de %1 his graveyard @@ -603,40 +1006,34 @@ cementerio &de %1 - his exile nominative - su exilio + su exilio - %1's exile nominative - el exilio de %1 + el exilio de %1 - of his exile genitive - de su exilio + de su exilio - of %1's exile genitive - del exilio de %1 + del exilio de %1 - his exile accusative - su exilio + su exilio - %1's exile accusative - el exilio de %1 + el exilio de %1 his exile @@ -649,40 +1046,34 @@ el exilio de %1 - his sideboard nominative - su reserva + su reserva - %1's sideboard nominative - la reserva de %1 + la reserva de %1 - of his sideboard genitive - de su reserva + de su reserva - of %1's sideboard genitive - de la reserva de %1 + de la reserva de %1 - his sideboard accusative - su reserva + su reserva - %1's sideboard accusative - la reserva de %1 + la reserva de %1 his sideboard @@ -745,38 +1136,56 @@ Nuevo valor para el contador '%1': + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + General + + DeckListModel - + Number Número - + Card Carta + + + Price + + DeckViewContainer - + Load &local deck Cargar mazo &local - + Load d&eck from server Cargar mazo del &servidor - + Ready to s&tart Listo para &empezar - + Load deck Cargar mazo @@ -872,82 +1281,82 @@ &Descripción: - + &Password: &Contraseña: - + P&layers: &Jugadores: - + Game type Tipo de partida - + Only &buddies can join Sólo los &amigos pueden participar - + Only &registered users can join Sólo los usuarios &registrados pueden participar - + Joining restrictions Restricciones de participación - + &Spectators allowed Permitir e&spectadores - + Spectators &need a password to join Los espectadores &necesitan contraseña para unirse - + Spectators can &chat Los espectadores pueden &chatear - + Spectators see &everything Los espectadores pueden verlo &todo - + Spectators Espectadores - + &OK &Aceptar - + &Cancel &Cancelar - + Create game Crear partida - + Error Error - + Server error. Error del servidor. @@ -1089,9 +1498,9 @@ DlgSettings - - - + + + Error Error @@ -1108,47 +1517,52 @@ 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 - + + Deck editor + + + + Messages Mensajes - + &Close &Cerrar @@ -1156,87 +1570,98 @@ GameSelector - + C&reate C&rear - + &Join E&ntrar - - - - - - - + + + + + + + + Error Error - + + Please join the appropriate room first. + + + + 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. - + This game is only open to registered users. Esta partida está abierta sólo a usuarios registrados. - + This game is only open to its creator's buddies. Esta partida está abierta sólo a los amigos del creador. - + You are being ignored by the creator of this game. Estas siendo ignorado por el creador de la partida. - + Join game Entrar en la partida - + Password: Contraseña: - + Games Partidas - + Show &full games Ver partidas &sin plazas libres + + + Show &running games + + &Show full games &Ver partidas sin plazas libres - + J&oin as spectator Entrar como e&spectador @@ -1252,67 +1677,72 @@ GamesModel - + yes - + no no - + Creator Creador - + Description Descripción - + yes, free for spectators sí, libre para espectadores - + buddies only solo amigos - + reg. users only solo usuarios registrados - + not allowed no permitido + Room + Sala + + + Game type Tipo de partida - + Password Contraseña - + Restrictions Restricciones - + Players Jugadores - + Spectators Espectadores @@ -1320,50 +1750,50 @@ GeneralSettingsPage - - - + + + Choose path Elija ruta - + Personal settings Preferencias personales - + Language: Idioma: - + Download card pictures on the fly Descargar imagenes de las cartas al vuelo - + Paths Rutas - + Decks directory: Directorio de mazos: - + Pictures directory: Directorio de imagenes: - + Path to card database: Ruta a la base de datos de las cartas: - - + + English Español @@ -1382,128 +1812,158 @@ + Scheduled server shutdown. + + + + Unknown reason. Motivo desconocido. - + Connection closed Conexión cerrada - + The server has terminated your connection. Reason: %1 El servidor ha finalizado tu conexión. Motivo: %1 - + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + 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 - + Version %1 Versión %1 - + Authors: Autores: - + Translators: Traductores: - + Spanish: Español: - + Portugese (Portugal): Portugués (Portugal): - + Portugese (Brazil): Portugués (Brasil): - + French: Francés: - + Japanese: Japonés: - + Russian: Ruso: - - - - - - + + Czech: + + + + + Slovak: + + + + + + + + + Error Error - + Server timeout Tiempo de espera del servidor agotado - + Invalid login data. Datos de conexión invalidos. - + There is already an active session using this user name. Please close that session first and re-login. Ya existe una sesión activa usando ese nombre de usuario. Por favor, cierra esa sesión primero y reintentalo. - + Socket error: %1 Error del Socket: %1 - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. Estás intentando conectar a un servidor obsoleto. Por favor, usa una versión anterior de Cockatrice o conecta a un servidor apropiado. La versión local es %1, la versión remota es %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. Tu cliente de Cockatrice esta obsoleto. Por favor, actualiza tu versión de Cockatrice. @@ -1514,82 +1974,82 @@ La versión local es %1, la versión remota es %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? @@ -1597,213 +2057,1041 @@ La versión local es %1, la versión remota es %2. MessageLogWidget - Connecting to %1... - Conectando a %1... + Conectando a %1... - Disconnected from server. - Desconectado del servidor. + Desconectado del servidor. - Invalid password. - Contraseña incorrecta. + Contraseña incorrecta. - Protocol error. - Error del protocolo. + Error del protocolo. - + The game has been closed. La partida ha sido cerrada. - + %1 is now watching the game. %1 está ahora observando la partida. - + %1 is not watching the game any more. %1 ya no está observado más la partida. - %1 is not ready to start the game any more. - %1 ya no está listo para empezar el juego. + %1 ya no está listo para empezar el juego. - %1 rolls a %2 with a %3-sided die. - %1 sacó un %2 con un dado de %3 caras. + %1 sacó un %2 con un dado de %3 caras. - %1 draws %n card(s). - + %1 roba %n carta. %1 roba %n cartas. - + + You have joined game #%1. + female + Te has unido a la partida #%1. + + + + You have joined game #%1. + male + Te has unido a la partida #%1. + + + + %1 has joined the game. + female + %1 se ha unido a la partida. + + + + %1 has joined the game. + male + %1 se ha unido a la partida. + + + + %1 has left the game. + female + %1 ha dejado la partida. + + + + %1 has left the game. + male + %1 ha dejado la partida. + + + + %1 has loaded a local deck. + female + %1 ha cargado un mazo local. + + + + %1 has loaded a local deck. + male + %1 ha cargado un mazo local. + + + + %1 has loaded deck #%2. + female + %1 ha cargado el mazo #%2. + + + + %1 has loaded deck #%2. + male + %1 ha cargado el mazo #%2. + + + + %1 is ready to start the game. + female + %1 está preparado para empezar la partida. + + + + %1 is ready to start the game. + male + %1 está preparado para empezar la partida. + + + + %1 is not ready to start the game any more. + female + %1 ya no está listo para empezar el juego. + + + + %1 is not ready to start the game any more. + male + %1 ya no está listo para empezar el juego. + + + + %1 has conceded the game. + female + %1 ha concedido la partida. + + + + %1 has conceded the game. + male + %1 ha concedido la partida. + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + + %1 rolls a %2 with a %3-sided die. + female + %1 sacó un %2 con un dado de %3 caras. + + + + %1 rolls a %2 with a %3-sided die. + male + %1 sacó un %2 con un dado de %3 caras. + + + + %1 draws %n card(s). + female + + %1 roba %n carta. + %1 roba %n cartas. + + + + + %1 draws %n card(s). + male + + %1 roba %n carta. + %1 roba %n cartas. + + + + %1 undoes his last draw. %1 deshace su último robo. - + + %1 undoes her last draw. + + + + %1 undoes his last draw (%2). %1 deshace su último robo (%2). - + + %1 undoes her last draw (%2). + + + + from table de la mesa - + from graveyard del cementerio - + from exile del exilio - + from hand de la mano - + the bottom card of his library el fondo de la biblioteca - + + the bottom card of her library + + + + from the bottom of his library del fondo de la biblioteca - + + from the bottom of her library + + + + the top card of his library la parte superior de la biblioteca - + + the top card of her library + + + + from the top of his library de la parte superior de la biblioteca - + + from the top of her library + + + + from library de la biblioteca - + from sideboard de la reserva - + from the stack de la pila - + %1 gives %2 control over %3. %1 entrega a %2 el control sobre %3. - + %1 puts %2 into play tapped%3. %1 pone %2 en juego%3 girado. - + %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 into her library. + + + + %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 bottom of her library. + + + + %1 puts %2%3 on top of his library. %1 pone %2%3 en la parte superior de su biblioteca. - + + %1 puts %2%3 on top of her library. + + + + %1 puts %2%3 into his library at position %4. %1 pone %2%3 en su biblioteca en la posición %4. - + + %1 puts %2%3 into her library at position %4. + + + + %1 moves %2%3 to sideboard. %1 mueve %2%3 a la reserva. - + %1 plays %2%3. %1 juega %2%3. + + + %1 takes a mulligan to %n. + female + + + + + + + + %1 takes a mulligan to %n. + male + + + + + - - + + %1 flips %2 face-down. + female + %1 voltea %2 boca abajo. + + + + %1 flips %2 face-down. + male + %1 voltea %2 boca abajo. + + + + %1 flips %2 face-up. + female + %1 voltea %2 boca arriba. + + + + %1 flips %2 face-up. + male + %1 voltea %2 boca arriba. + + + + %1 destroys %2. + female + %1 destruye %2. + + + + %1 destroys %2. + male + %1 destruye %2. + + + %1 attaches %2 to %3's %4. + female + %1 anexa %2 a el %4 de %3. + + + %1 attaches %2 to %3's %4. + male + %1 anexa %2 a el %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + %1 anexa %2 a el %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + %1 anexa %2 a el %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + %1 anexa %2 a el %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + %1 anexa %2 a el %4 de %3. + + + + %1 unattaches %2. + female + %1 desanexa %2. + + + + %1 unattaches %2. + male + %1 desanexa %2. + + + + %1 creates token: %2%3. + female + %1 crea una ficha: %2%3. + + + + %1 creates token: %2%3. + male + %1 crea una ficha: %2%3. + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + %1 apunta desde el %3 de %2 a %4. + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + %1 apunta desde el %3 de %2 al %5 de %4. + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + %1 pone %n %2 contador en %3 (ahora %4). + %1 pone %n %2 contadores en %3 (ahora %4). + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 pone %n %2 contador en %3 (ahora %4). + %1 pone %n %2 contadores en %3 (ahora %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 remueve %n %2 contador en %3 (ahora %4). + %1 remueve %n %2 contadores en %3 (ahora %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + %1 remueve %n %2 contador en %3 (ahora %4). + %1 remueve %n %2 contadores en %3 (ahora %4). + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + %1 establece los contadores de %2 a %3 (%4%5). + + + + %1 sets counter %2 to %3 (%4%5). + male + %1 establece los contadores de %2 a %3 (%4%5). + + + + %1 sets %2 to not untap normally. + female + %1 establece que %2 no se endereze normalmente. + + + + %1 sets %2 to not untap normally. + male + %1 establece que %2 no se endereze normalmente. + + + + %1 sets %2 to untap normally. + female + %1 establece que %2 se endereze normalmente. + + + + %1 sets %2 to untap normally. + male + %1 establece que %2 se endereze normalmente. + + + + %1 sets PT of %2 to %3. + female + %1 establece F/R de %2 a %3. + + + + %1 sets PT of %2 to %3. + male + %1 establece F/R de %2 a %3. + + + + %1 sets annotation of %2 to %3. + female + %1 establece la anotación de %2 a %3. + + + + %1 sets annotation of %2 to %3. + male + %1 establece la anotación de %2 a %3. + + + + %1 is looking at the top %2 cards %3. + female + %1 esta mirando las primeras %2 cartas de %3. + + + + %1 is looking at the top %2 cards %3. + male + %1 esta mirando las primeras %2 cartas de %3. + + + + %1 is looking at %2. + female + %1 está mirando: %2. + + + + %1 is looking at %2. + male + %1 está mirando: %2. + + + + %1 stops looking at %2. + female + %1 termina de mirar: %2. + + + + %1 stops looking at %2. + male + %1 termina de mirar: %2. + + + + %1 reveals %2 to %3. + p1 female, p2 female + %1 revela %2 a %3. + + + + %1 reveals %2 to %3. + p1 female, p2 male + %1 revela %2 a %3. + + + + %1 reveals %2 to %3. + p1 male, p2 female + %1 revela %2 a %3. + + + + %1 reveals %2 to %3. + p1 male, p2 male + %1 revela %2 a %3. + + + + %1 reveals %2. + female + %1 revela %2. + + + + %1 reveals %2. + male + %1 revela %2. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + %1 revela aleatoriamente %2%3 a %4. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + %1 revela aleatoriamente %2%3 a %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + %1 revela aleatoriamente %2%3 a %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + %1 revela aleatoriamente %2%3 a %4. + + + + %1 randomly reveals %2%3. + female + %1 revela aleatoriamente %2%3. + + + + %1 randomly reveals %2%3. + male + %1 revela aleatoriamente %2%3. + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + %1 revela %2%3 a %4. + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + %1 revela %2%3 a %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + %1 revela %2%3 a %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + %1 revela %2%3 a %4. + + + + %1 reveals %2%3. + female + %1 revela %2%3. + + + + %1 reveals %2%3. + male + %1 revela %2%3. + + + + It is now %1's turn. + female + Es el turno de %1. + + + + It is now %1's turn. + male + Es el turno de %1. + + + + a card una carta - %1 flips %2 face-down. - %1 voltea %2 boca abajo. + %1 voltea %2 boca abajo. - %1 flips %2 face-up. - %1 voltea %2 boca arriba. + %1 voltea %2 boca arriba. - %1 attaches %2 to %3's %4. - %1 anexa %2 a el %4 de %3. + %1 anexa %2 a el %4 de %3. - %1 unattaches %2. - %1 desanexa %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 apunta desde el %3 de %2 al %5 de %4. %1 places %n counter(s) (%2) on %3 (now %4). @@ -1820,7 +3108,7 @@ La versión local es %1, la versión remota es %2. - + red rojo @@ -1828,7 +3116,7 @@ La versión local es %1, la versión remota es %2. - + yellow amarillo @@ -1836,7 +3124,7 @@ La versión local es %1, la versión remota es %2. - + green verde @@ -1844,74 +3132,61 @@ La versión local es %1, la versión remota es %2. - %1 sets counter %2 to %3 (%4%5). - %1 establece los contadores de %2 a %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 establece F/R de %2 a %3. - %1 sets annotation of %2 to %3. - %1 establece la anotación de %2 a %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. + %1 esta mirando las primeras %2 cartas de %3. - + The game has started. La partida ha comenzado. - Connected. - Conectado. + Conectado. - Protocol version mismatch. Client: %1, Server: %2 - La versión del protocolo es diferente. Cliente: %1, Servidor: %2 + La versión del protocolo es diferente. Cliente: %1, Servidor: %2 - You have joined game #%1. - Te has unido a la partida #%1. + Te has unido a la partida #%1. - %1 has joined the game. - %1 se ha unido a la partida. + %1 se ha unido a la partida. - %1 has left the game. - %1 ha dejado la partida. + %1 ha dejado la partida. - %1 has loaded a local deck. - %1 ha cargado un mazo local. + %1 ha cargado un mazo local. - %1 has loaded deck #%2. - %1 ha cargado el mazo #%2. + %1 ha cargado el mazo #%2. - %1 is ready to start the game. - %1 está preparado para empezar la partida. + %1 está preparado para empezar la partida. - %1 has conceded the game. - %1 ha concedido la partida. + %1 ha concedido la partida. %1 draws a card. @@ -1922,196 +3197,185 @@ La versión local es %1, la versión remota es %2. %1 roba %2 cartas. - %1 destroys %2. - %1 destruye %2. + %1 destruye %2. - %1 creates token: %2%3. - %1 crea una ficha: %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 apunta desde el %3 de %2 a %4. - %1 places %n %2 counter(s) on %3 (now %4). - + %1 pone %n %2 contador en %3 (ahora %4). %1 pone %n %2 contadores en %3 (ahora %4). - %1 removes %n %2 counter(s) from %3 (now %4). - + %1 remueve %n %2 contador en %3 (ahora %4). %1 remueve %n %2 contadores en %3 (ahora %4). - %1 %2 %3. - %1 %2 %3. + %1 %2 %3. - %1 is looking at %2. - %1 está mirando: %2. + %1 está mirando: %2. - %1 stops looking at %2. - %1 termina de mirar: %2. + %1 termina de mirar: %2. - %1 reveals %2 to %3. - %1 revela %2 a %3. + %1 revela %2 a %3. - %1 reveals %2. - %1 revela %2. + %1 revela %2. - + ending phase fase de fin de turno - It is now %1's turn. - Es el turno de %1. + Es el turno de %1. - %1 shuffles his library. - %1 baraja su biblioteca. + %1 baraja su biblioteca. + + + + %1 draws his initial hand. + + + + + %1 draws her initial hand. + - %1 randomly reveals %2%3 to %4. - %1 revela aleatoriamente %2%3 a %4. + %1 revela aleatoriamente %2%3 a %4. - %1 randomly reveals %2%3. - %1 revela aleatoriamente %2%3. + %1 revela aleatoriamente %2%3. - %1 reveals %2%3 to %4. - %1 revela %2%3 a %4. + %1 revela %2%3 a %4. - %1 reveals %2%3. - %1 revela %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 + gira - untaps - endereza + endereza - %1 sets %2 to not untap normally. - %1 establece que %2 no se endereze normalmente. + %1 establece que %2 no se endereze normalmente. - %1 sets %2 to untap normally. - %1 establece que %2 se endereze normalmente. + %1 establece que %2 se endereze normalmente. - his permanents - sus permanentes + sus permanentes MessagesSettingsPage - + &Add &Añadir - + &Remove &Quitar - + Add message Añadir mensaje - + Message: Mensaje: @@ -2177,128 +3441,128 @@ La versión local es %1, la versión remota es %2. 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 - + &Undo last draw &Deshacer último robo - + 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 @@ -2307,98 +3571,98 @@ La versión local es %1, la versión remota es %2. 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 @@ -2407,100 +3671,100 @@ La versión local es %1, la versión remota es %2. Mover cartas superiores al ce&menterio... - + Move top cards to &exile... Mover cartas superiores al &exilio... - + Put top card on &bottom Poner carta superior en la parte &inferior - + &Reveal to &Revelar a - + Reveal r&andom card to Revelar carta &aleatoriamente a - + C&ard C&arta - + &All players &Todos los jugadores - + Ctrl+F3 Ctrl+F3 - + Ctrl+Shift+D Ctrl+Shift+D - + 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 @@ -2594,17 +3858,17 @@ La versión local es %1, la versión remota es %2. Reserva - + Cockatrice decks (*.cod) Mazos de Cockatrice (*.cod) - + Plain text decks (*.dec *.mwDeck) Archivos de texto plano (*.dec *.mwDeck) - + All files (*.*) Todos los archivos (*.*) @@ -2680,40 +3944,73 @@ La versión local es %1, la versión remota es %2. Nombre largo + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + &Aceptar + + + + &Cancel + &Cancelar + + + + Shut down server + + + TabAdmin - + Update server &message Actualizar &mensaje del servidor - + + &Shut down server + + + + Server administration functions Funciones de administración del servidor - + &Unlock functions &Desbloquear funciones - + &Lock functions &Bloquear funciones - + Unlock administration functions Desbloquear funciones de administración - + Do you really want to unlock the administration functions? ¿Realmente quieres desbloquear las funciones de administración? - + Administration Administración @@ -2808,127 +4105,132 @@ Por favor, introduzca un nombre: TabGame - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + &Phases &Fases - + &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 - + + Ctrl+Q + Ctrl+Q + + + &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? - + Kicked Expulsado - + You have been kicked out of the game. Has sido expulsado de la partida. @@ -2941,32 +4243,32 @@ Por favor, introduzca un nombre: TabMessage - + Personal &talk &Conversación personal - + &Leave &Cerrar - + This user is ignoring you. Este usuario está ignorandote. - + %1 has left the server. %1 ha abandonado el servidor. - + %1 has joined the server. %1 se ha unido al servidor. - + Talking to %1 Hablando con %1 @@ -2974,27 +4276,27 @@ Por favor, introduzca un nombre: TabRoom - + &Say: &Decir: - + Chat Chat - + &Room &Sala - + &Leave room &Dejar sala - + You are flooding the chat. Please wait a couple of seconds. Estás floodeando el chat. Por favor, espera unos segundos. @@ -3026,42 +4328,51 @@ Por favor, introduzca un nombre: UserInfoBox - + User information Información del usuario - + Real name: Nombre real: - + + Gender: + + + + Location: Localización: - + User level: Nivel de usuario: - + Administrator Administrador - - Judge - Juez + + Moderator + - + Judge + Juez + + + Registered user Usuario registrado - + Unregistered user Usuario no registrado @@ -3069,279 +4380,312 @@ Por favor, introduzca un nombre: 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 + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + Elija ruta + UserList - + Users online: %1 Usuarios online: %1 - + Users in this room: %1 Usuarios en esta sala: %1 - + Buddies online: %1 / %2 Amigos online: %1 / %2 - + Ignored users online: %1 / %2 Usuarios ignorados online: %1 / %2 - + + %1's games + + + + User &details &Detalles del usuario - + Direct &chat &Chat privado - + + Show this user's &games + + + + Add to &buddy list Añadir a la lista de &amigos - + Remove from &buddy list Quitar de la lista de &amigos - + Add to &ignore list Añadir a la lista de &ignorados - + Remove from &ignore list Quitar de la lista de &ignorados - + Ban from &server Banear del &servidor - Duration - Duración + Duración - Please enter the duration of the ban (in minutes). Enter 0 for an indefinite ban. - Por favor, introduce la duración del ban (en minutos) + Por favor, introduce la duración del ban (en minutos) Indica 0 para un ban indefinido. WndDeckEditor - + &Search for: &Buscar por: - + Deck &name: &Nombre del mazo: - + &Comments: &Comentarios: - + Deck editor [*] Editor de mazos [*] - + &New deck &Nuevo mazo - + &Load deck... &Cargar mazo... - + Load deck from cl&ipboard... Cargar mazo del &portapapeles... - + &Save deck &Guardar mazo - + + &Update prices + + + + + Ctrl+U + Ctrl+U + + + Save deck &as... Guardar mazo &como... - + Save deck to clip&board Guardar mazo al p&ortapales - + &Print deck... Im&primir mazo... - + &Close &Cerrar - + Ctrl+Q Ctrl+Q - + &Edit sets... &Editar ediciones... - + &Deck &Mazo - + Load deck Cargar mazo - + Error Error - + The deck could not be saved. Please check that the directory is writable and try again. El mazo no puede guardarse Por favor, compruebe que tiene permisos de escritura en el directorio e intentelo de nuevo. - + Save deck Guardar mazo - + Add card to &maindeck Añadir carta al &mazo principal - + Return Return - + Enter Enter - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter - + Add card to &sideboard Añadir carta a la &reserva - + &Search... &Buscar... - + &Clear search &Limpiar busqueda - + &Card database &Base de datos de cartas - + &Remove row &Eliminar columna - + Del Del - + &Increment number &Incrementar número - + + + - + &Decrement number &Decrementar número - + - - - + Are you sure? ¿Estás seguro? - + The decklist has been modified. Do you want to save the changes? La lista del mazo ha sido modificada diff --git a/cockatrice/translations/cockatrice_fr.ts b/cockatrice/translations/cockatrice_fr.ts index e8ab3fdd0..301f32172 100644 --- a/cockatrice/translations/cockatrice_fr.ts +++ b/cockatrice/translations/cockatrice_fr.ts @@ -37,90 +37,126 @@ AppearanceSettingsPage - + Zone background pictures Zone images de fond - + Path to hand background: Chemin pour les images de fond de main: - + Path to stack background: Chemin pour les images de fond de pile: - + Path to table background: Chemin pour les images d'arrière-plan: - + Path to player info background: Chemin pour les images de fond d'affichage d'informations: - + Path to picture of card back: Chemin pour les images de dos des cartes: - + Card rendering Rendu des cartes - + Display card names on cards having a picture Afficher le nom des cartes ayant une image - + Hand layout Disposition de la main - + Display hand horizontally (wastes space) Montrer la main horizontalement - + Table grid layout Disposition en forme de grille - + Invert vertical coordinate Inverser la disposition du champ de bataille - + + Minimum player count for multi-column layout: + + + + 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 + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Entrez la durée de temps du ban (en minutes). +Entrez 0 pour une durée illimitée du ban. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + &OK + + + + &Cancel + &Annuler + + + + Ban user from server + + + CardDatabaseModel @@ -152,22 +188,42 @@ CardInfoWidget - + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + Name: Nom: - + Mana cost: Cout de mana: - + Card type: Type de carte: - + P / T: F / E: @@ -175,57 +231,57 @@ CardItem - + &Play &Jouer - + &Hide &Cacher - + &Tap &Engager - + &Untap &Dégager - + Toggle &normal untapping Activer/ Désactiver le dégagement &normal - + &Flip &Retourner la carte - + &Clone &Copier une carte - + Ctrl+H - + &Attach to card... &Attacher à la carte... - + Ctrl+A Ctrl+A - + Unattac&h Détac&her @@ -234,142 +290,147 @@ Fixer &F/E... - + + &Draw arrow... + + + + &Power / toughness F&orce / Endurance - + &Increase power &Augmenter force - + Ctrl++ Ctrl++ - + &Decrease power &Diminuer force - + Ctrl+- Ctrl+- - + I&ncrease toughness A&ugmenter endurance - + Alt++ Alt++ - + D&ecrease toughness D&iminuer endurance - + Alt+- Alt+- - + In&crease power and toughness Au&gmenter la force et l'endurance - + Ctrl+Alt++ Ctrl+Alt++ - + Dec&rease power and toughness Di&minuer la force et l'endurance - + Ctrl+Alt+- Ctrl+Alt+- - + Set &power and toughness... Fi&xer la force et l'endurance... - + Ctrl+P Ctrl+P - + &Set annotation... A&jouter note... - + red rouge - + yellow jaune - + green vert - + &Add counter (%1) &Ajouter compteur (%1) - + &Remove counter (%1) &Retirer compteur (%1) - + &Set counters (%1)... &Fixer marqueurs (%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 @@ -377,184 +438,514 @@ CardZone - his hand nominative - sa main + sa main - %1's hand nominative - main de %1 + main de %1 - of his hand genitive - de sa main + 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 + 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 + sa bibliothèque + + + %1's library + accusative + bibliothèque de %1 - of %1's hand - genitive - de la main de %1 + her hand + nominative, female owner + - - his hand - accusative - sa main - - - + %1's hand - accusative - main de %1 + nominative, female owner + main de %1 - - his library - nominative - sa bibliothèque + + his hand + nominative, male owner + sa main - + + %1's hand + nominative, male owner + main de %1 + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + de la main de %1 + + + + of his hand + genitive, male owner + de sa main + + + + of %1's hand + genitive, male owner + de la main de %1 + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + main de %1 + + + + his hand + accusative, male owner + sa main + + + + %1's hand + accusative, male owner + main de %1 + + + + her library + nominative, female owner + + + + %1's library - nominative - bibliothèque de %1 + nominative, female owner + bibliothèque de %1 - of his library - genitive - de sa bibliothèque + his library + nominative, male owner + sa bibliothèque + %1's library + nominative, male owner + bibliothèque de %1 + + + + of her library + genitive, female owner + + + + of %1's library - genitive - de la bibliothèque de %1 + genitive, female owner + de la bibliothèque de %1 - his library - accusative - sa bibliothèque + of his library + genitive, male owner + de sa bibliothèque + of %1's library + genitive, male owner + de la bibliothèque de %1 + + + + her library + accusative, female owner + + + + %1's library - accusative - bibliothèque de %1 + accusative, female owner + bibliothèque de %1 - - his graveyard - nominative - son cimetière + + his library + accusative, male owner + sa bibliothèque - - %1's graveyard - nominative - le cimetière de %1 + + %1's library + accusative, male owner + bibliothèque de %1 + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + le cimetière de %1 + + + + his graveyard + nominative, male owner + son cimetière + + + + %1's graveyard + nominative, male owner + le cimetière de %1 + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + du cimetière de %1 + + + + of his graveyard + genitive, male owner + de son cimetière + + + + of %1's graveyard + genitive, male owner + du cimetière de %1 + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + le cimetière de %1 + + + + his graveyard + accusative, male owner + son cimetière + + + + %1's graveyard + accusative, male owner + le cimetière de %1 + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + la zone exil de %1 + + + + his exile + nominative, male owner + sa zone exil + + + + %1's exile + nominative, male owner + la zone exil de %1 + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + de la zone exil de %1 + + + + of his exile + genitive, male owner + de sa zone exil + + + + of %1's exile + genitive, male owner + de la zone exil de %1 + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + la zone exil de %1 + + + + his exile + accusative, male owner + sa zone exil + + + + %1's exile + accusative, male owner + la zone exil de %1 + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + la réserve de %1 + + + + his sideboard + nominative, male owner + sa réserve + + + + %1's sideboard + nominative, male owner + la réserve de %1 + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + de la réserve de %1 + + + + of his sideboard + genitive, male owner + de sa réserve + + + + of %1's sideboard + genitive, male owner + de la réserve de %1 + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + la réserve de %1 + + + + his sideboard + accusative, male owner + sa réserve + + + + %1's sideboard + accusative, male owner + la réserve 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 + de son cimetière - of %1's graveyard genitive - du cimetière de %1 + du cimetière de %1 - his graveyard accusative - son cimetière + son cimetière - %1's graveyard accusative - le cimetière de %1 + le cimetière de %1 - his exile nominative - sa zone exil + sa zone exil - %1's exile nominative - la zone exil de %1 + la zone exil de %1 - of his exile genitive - de sa zone exil + de sa zone exil - of %1's exile genitive - de la zone exil de %1 + de la zone exil de %1 - his exile accusative - sa zone exil + sa zone exil - %1's exile accusative - la zone exil de %1 + la zone exil de %1 - his sideboard nominative - sa réserve + sa réserve - %1's sideboard nominative - la réserve de %1 + la réserve de %1 - of his sideboard genitive - de sa réserve + de sa réserve - of %1's sideboard genitive - de la réserve de %1 + de la réserve de %1 - his sideboard accusative - sa réserve + sa réserve - %1's sideboard accusative - la réserve de %1 + la réserve de %1 @@ -607,38 +998,56 @@ Nouvelle valeur pour le compteur '%1': + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + Géneral + + DeckListModel - + Number Nombre - + Card Carte + + + Price + + DeckViewContainer - + Load &local deck Charger un deck &local - + Load d&eck from server Charger un d&eck depuis le serveur - + Ready to s&tart P&rêt à démarrer - + Load deck Charger deck @@ -734,82 +1143,82 @@ &Description: - + &Password: Mot de &Passe: - + P&layers: &Joueurs: - + Game type Type de partie - + Only &buddies can join Seuls les &amis peuvent rejoindre - + Only &registered users can join Seules les personnes en&registrées peuvent rejoindre - + Joining restrictions Conditions pour rejoindre - + &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 dis&cuter - + 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. @@ -951,54 +1360,59 @@ 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. Souhaitez-vous redéfinir 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. Souhaitez-vous redéfinir 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. Souhaitez-vous redéfinir le chemin d'accès? - + Settings Paramètres - + General Géneral - + Appearance Apparence - + User interface Interface utilisateur - + + Deck editor + + + + Messages Messages - + &Close &Fermer @@ -1006,88 +1420,99 @@ GameSelector - - - - - - - + + + + + + + + Error Erreur - + + Please join the appropriate room first. + + + + Wrong password. Mot de passe erroné. - + 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. - + This game is only open to registered users. Cette partie n'est accessible qu'aux joueurs enregistrés. - + This game is only open to its creator's buddies. Cette partie n'est accessible qu'aux amis. - + You are being ignored by the creator of this game. Vous avez été ignoré par le créateur de la partie. - + Join game Rejoindre partie - + Password: Mot de passe: - + Games Parties - + Show &full games Montrer &toutes les parties + + + Show &running games + + &Show full games toutes ou complèetes? &Montrer toutes les parties - + C&reate C&réer - + &Join Re&joindre - + J&oin as spectator Rej&oindre en tant que spectateur @@ -1103,67 +1528,72 @@ GamesModel - + yes oui - + yes, free for spectators oui, libre pour les spectateurs - + no non - + buddies only invités uniquement - + reg. users only joueurs enregistrés uniquement - + not allowed non autorisé - + + Room + Salon + + + Description Description - + Creator Créateur - + Game type Type de jeu - + Password Mot de passe - + Restrictions Restrictions - + Players Joueurs - + Spectators Spectateurs @@ -1171,50 +1601,50 @@ GeneralSettingsPage - - + + English Français - - - + + + Choose path Choisir chemin d'accès - + Personal settings Paramètres personnels - + Language: Langue: - + Download card pictures on the fly 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 de cartes: @@ -1222,23 +1652,23 @@ 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 @@ -1247,67 +1677,67 @@ <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 Version %1 - + Authors: Auteurs: - + Translators: Traducteurs: - + Spanish: Espagnol: - + Portugese (Portugal): Portugais (Portugal): - + Portugese (Brazil): Portugais (Brésil): - + French: Français: - + Japanese: Japonais: - - - - - - + + + + + + Error Erreur - + Server timeout Délai de la demande dépassé - + Invalid login data. Information de connexion érronée. - + Socket error: %1 Erreur de socket: %1 @@ -1327,126 +1757,156 @@ + Scheduled server shutdown. + + + + Unknown reason. Raison inconnue. - + Connection closed Connection fermée - + The server has terminated your connection. Reason: %1 Le serveur a coupé votre connexion. Raison: %1 - + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + Russian: putted "France" instead of "Russe" -> meant that I must put the translation laguage country, isn't it? France: - + + Czech: + + + + + Slovak: + + + + There is already an active session using this user name. Please close that session first and re-login. Il y a déjà une session ouvert avec le même pseudo. Fermez cette session puis re-connectez-vous. - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. Vous tentez de vous connecter à un serveur obsolète. Chargez la nouvelle version de Cockatrice ou connectez-vous à un serveur approprié. La version la plus récente est %1, l'ancienne version est %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. Votre client Cockatrice est obsolète. Veuillez charger la nouvelle version. La version la plus récente est %1, l'ancienne version est %2. - + Connecting to %1... Connexion à %1... - + 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 Éditeur de &deck - + &Full screen &Plein écran - + Ctrl+F Ctrl+F - + &Settings... &Paramètres... - + &Exit &Quitter - + &Cockatrice &Cockatrice - + &About Cockatrice À propos de Cock&atrice - + &Help A&ide - + Are you sure? Êtes-vous sûr? - + There are still open games. Are you sure you want to quit? Il y a encore des parties en cours. Êtes-vous sûr de vouloir quitter? @@ -1454,106 +1914,90 @@ La version la plus récente est %1, l'ancienne version est %2. MessageLogWidget - Connecting to %1... - Connexion à %1... + Connexion à %1... - Connected. - Connecté. + Connecté. - Disconnected from server. - Déconnecté du serveur. + Déconnecté du serveur. - Invalid password. - Mot de passe invalide. + 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 rejoint la partie #%1. + + + %1 has joined the game. + %1 a rejoint la partie. + + + %1 has left the game. + %1 a quitté la partie. - 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 rejoint la partie #%1. - - - - %1 has joined the game. - %1 a rejoint 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 a chargé un deck local. - %1 has loaded deck #%2. - %1 a chargé le deck #%2. + %1 a chargé le deck #%2. - %1 is ready to start the game. - %1 est prêt à démarrer la partie. + %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 n'est plus prêt à démarrer la partie. - %1 has conceded the game. partie ou jeu - %1 a concédé la partie. + %1 a concédé la partie. - + The game has started. La partie commence. - %1 shuffles his library. - %1 mélange sa bibliothèque. + %1 mélange sa bibliothèque. - %1 rolls a %2 with a %3-sided die. is it always a dice? - %1 lance un %2 à %3 faces. + %1 lance un %2 à %3 faces. %1 draws a card. @@ -1564,187 +2008,1028 @@ La version la plus récente est %1, l'ancienne version est %2.%1 pioche %2 cartes. - - from table - depuis le champ de bataille + + You have joined game #%1. + female + Vous avez rejoint la partie #%1. - - from graveyard - depuis son cimetière + + You have joined game #%1. + male + Vous avez rejoint la partie #%1. - - from exile - depuis la zone exil + + %1 has joined the game. + female + %1 a rejoint la partie. - - from hand - depuis sa main + + %1 has joined the game. + male + %1 a rejoint la partie. - - the bottom card of his library - la carte du dessous de sa bibliothèque + + %1 has left the game. + female + %1 a quitté la partie. - - from the bottom of his library - du dessous de sa bibliothèque + + %1 has left the game. + male + %1 a quitté la partie. - - the top card of his library - le carte du dessus de sa bibliothèque + + %1 has loaded a local deck. + female + %1 a chargé un deck local. - - from the top of his library - du dessus de sa bibliothèque + + %1 has loaded a local deck. + male + %1 a chargé un deck local. - - from library - depuis sa bibliothèque + + %1 has loaded deck #%2. + female + %1 a chargé le deck #%2. - - from sideboard - depuis sa réserve + + %1 has loaded deck #%2. + male + %1 a chargé le deck #%2. - - from the stack - depuis la pile + + %1 is ready to start the game. + female + %1 est prêt à démarrer la partie. - - %1 puts %2 into play tapped%3. - %1 met %2 en jeu engagé%3. + + %1 is ready to start the game. + male + %1 est prêt à démarrer la partie. - - %1 puts %2 into play%3. - what is %3? plz exemple (resp. by Ranma : XX met island en jeu -depuis sa main-.) - %1 met %2 en jeu %3. + + %1 is not ready to start the game any more. + female + %1 n'est plus prêt à démarrer la partie. - - %1 puts %2%3 into graveyard. - %1 met %2%3 dans son cimetière. + + %1 is not ready to start the game any more. + male + %1 n'est plus prêt à démarrer la partie. - - %1 exiles %2%3. - %1 exile %2%3. + + %1 has conceded the game. + female + %1 a concédé la partie. - - %1 moves %2%3 to hand. - %1 met %2%3 dans sa main. + + %1 has conceded the game. + male + %1 a concédé la partie. - - %1 puts %2%3 into his library. - %1 met %2%3 dans sa bibliothèque. + + %1 has restored connection to the game. + female + - - %1 puts %2%3 on bottom of his library. - %1 met %2%3 en-dessous de sa bibliothèque. + + %1 has restored connection to the game. + male + - - %1 puts %2%3 on top of his library. - %1 met %2%3 au-dessus de sa bibliothèque. + + %1 has lost connection to the game. + female + - - %1 puts %2%3 into his library at position %4. - %1 met %2%3 dans sa bibliothèque à la position n°%4. + + %1 has lost connection to the game. + male + - - %1 moves %2%3 to sideboard. - %1 met %2%3 à sa réserve. + + %1 shuffles %2. + female + - - %1 plays %2%3. - %1 joue %2%3. + + %1 shuffles %2. + male + - - - a card - une carte + + %1 rolls a %2 with a %3-sided die. + female + %1 lance un %2 à %3 faces. + + + + %1 rolls a %2 with a %3-sided die. + male + %1 lance un %2 à %3 faces. - + %1 draws %n card(s). - + female + + %1 pioche %n carte. + %1 pioche %n cartes. + + + + + %1 draws %n card(s). + male + %1 pioche %n carte. %1 pioche %n cartes. - + + from table + depuis le champ de bataille + + + + from graveyard + depuis son cimetière + + + + from exile + depuis la zone exil + + + + from hand + depuis sa main + + + + the bottom card of his library + la carte du dessous de sa bibliothèque + + + + the bottom card of her library + + + + + from the bottom of his library + du dessous de sa bibliothèque + + + + from the bottom of her library + + + + + the top card of his library + le carte du dessus de sa bibliothèque + + + + the top card of her library + + + + + from the top of his library + du dessus de sa bibliothèque + + + + from the top of her library + + + + + from library + depuis sa bibliothèque + + + + from sideboard + depuis sa réserve + + + + from the stack + depuis la pile + + + + %1 puts %2 into play tapped%3. + %1 met %2 en jeu engagé%3. + + + + %1 puts %2 into play%3. + what is %3? plz exemple (resp. by Ranma : XX met island en jeu -depuis sa main-.) + %1 met %2 en jeu %3. + + + + %1 puts %2%3 into graveyard. + %1 met %2%3 dans son cimetière. + + + + %1 exiles %2%3. + %1 exile %2%3. + + + + %1 moves %2%3 to hand. + %1 met %2%3 dans sa main. + + + + %1 puts %2%3 into his library. + %1 met %2%3 dans sa bibliothèque. + + + + %1 puts %2%3 into her library. + + + + + %1 puts %2%3 on bottom of his library. + %1 met %2%3 en-dessous de sa bibliothèque. + + + + %1 puts %2%3 on bottom of her library. + + + + + %1 puts %2%3 on top of his library. + %1 met %2%3 au-dessus de sa bibliothèque. + + + + %1 puts %2%3 on top of her library. + + + + + %1 puts %2%3 into his library at position %4. + %1 met %2%3 dans sa bibliothèque à la position n°%4. + + + + %1 puts %2%3 into her library at position %4. + + + + + %1 moves %2%3 to sideboard. + %1 met %2%3 à sa réserve. + + + + %1 plays %2%3. + %1 joue %2%3. + + + + %1 takes a mulligan to %n. + female + + + + + + + + %1 takes a mulligan to %n. + male + + + + + + + + %1 flips %2 face-down. + female + %1 retourne %2 face cachée. + + + + %1 flips %2 face-down. + male + %1 retourne %2 face cachée. + + + + %1 flips %2 face-up. + female + %1 retourne %2 face visible. + + + + %1 flips %2 face-up. + male + %1 retourne %2 face visible. + + + + %1 destroys %2. + female + %1 détruit %2. + + + + %1 destroys %2. + male + %1 détruit %2. + + + %1 attaches %2 to %3's %4. + female + %1 attache %2 sur %4 de %3. + + + %1 attaches %2 to %3's %4. + male + %1 attache %2 sur %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + %1 attache %2 sur %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + %1 attache %2 sur %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + %1 attache %2 sur %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + %1 attache %2 sur %4 de %3. + + + + %1 unattaches %2. + female + %1 détache %2. + + + + %1 unattaches %2. + male + %1 détache %2. + + + + %1 creates token: %2%3. + female + %1 crée un jeton %2%3. + + + + %1 creates token: %2%3. + male + %1 crée un jeton %2%3. + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + %1 désigne le %3 de %2 à %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + %1 désigne le %3 de %2 à %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + %1 désigne le %3 de %2 à %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + %1 désigne le %3 de %2 à %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + %1 désigne le %3 de %2 à %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + %1 désigne le %3 de %2 à %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + %1 désigne le %3 de %2 à %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + %1 désigne le %3 de %2 à %4. + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + %1 désigne le %3 de %2 à %5 de %4. + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + %1 met %n %2 marqueur sur %3 (maintenant %4). + %1 met %n %2 marqueurs sur %3 (maintenant %4). + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 met %n %2 marqueur sur %3 (maintenant %4). + %1 met %n %2 marqueurs sur %3 (maintenant %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 retire %n %2 marqueur de %3 (maintenant %4). + %1 retire %n %2 marqueurs de %3 (maintenant %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + %1 retire %n %2 marqueur de %3 (maintenant %4). + %1 retire %n %2 marqueurs de %3 (maintenant %4). + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + %1 met les marqueurs %2 à %3 (%4%5). + + + + %1 sets counter %2 to %3 (%4%5). + male + %1 met les marqueurs %2 à %3 (%4%5). + + + + %1 sets %2 to not untap normally. + female + %2 de %1 ne se dégagera pas lors de l'étape de dégagement. + + + + %1 sets %2 to not untap normally. + male + %2 de %1 ne se dégagera pas lors de l'étape de dégagement. + + + + %1 sets %2 to untap normally. + female + %2 de %1 se dégagera lors de l'étape de dégagement. + + + + %1 sets %2 to untap normally. + male + %2 de %1 se dégagera lors de l'étape de dégagement. + + + + %1 sets PT of %2 to %3. + female + %1 change la F/E de %2 à %3. + + + + %1 sets PT of %2 to %3. + male + %1 change la F/E de %2 à %3. + + + + %1 sets annotation of %2 to %3. + female + %1 met l'annotation %3 à %2. + + + + %1 sets annotation of %2 to %3. + male + %1 met l'annotation %3 à %2. + + + + %1 is looking at the top %2 cards %3. + female + %1 regarde les %2 cartes du dessus %3. + + + + %1 is looking at the top %2 cards %3. + male + %1 regarde les %2 cartes du dessus %3. + + + + %1 is looking at %2. + female + %1 regarde %2. + + + + %1 is looking at %2. + male + %1 regarde %2. + + + + %1 stops looking at %2. + female + %1 arrête de regarder %2. + + + + %1 stops looking at %2. + male + %1 arrête de regarder %2. + + + + %1 reveals %2 to %3. + p1 female, p2 female + %1 révèle %2 à %3. + + + + %1 reveals %2 to %3. + p1 female, p2 male + %1 révèle %2 à %3. + + + + %1 reveals %2 to %3. + p1 male, p2 female + %1 révèle %2 à %3. + + + + %1 reveals %2 to %3. + p1 male, p2 male + %1 révèle %2 à %3. + + + + %1 reveals %2. + female + %1 révèle %2. + + + + %1 reveals %2. + male + %1 révèle %2. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + %1 révèle au hasard %2%3 à %4. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + %1 révèle au hasard %2%3 à %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + %1 révèle au hasard %2%3 à %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + %1 révèle au hasard %2%3 à %4. + + + + %1 randomly reveals %2%3. + female + %1 révèle au hasard %2%3. + + + + %1 randomly reveals %2%3. + male + %1 révèle au hasard %2%3. + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + %1 révèle %2%3 à %4. + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + %1 révèle %2%3 à %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + %1 révèle %2%3 à %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + %1 révèle %2%3 à %4. + + + + %1 reveals %2%3. + female + %1 révèle %2%3. + + + + %1 reveals %2%3. + male + %1 révèle %2%3. + + + + It is now %1's turn. + female + C'est maintenant le tour de %1. + + + + It is now %1's turn. + male + C'est maintenant le tour de %1. + + + + + a card + une carte + + + %1 draws %n card(s). + + %1 pioche %n carte. + %1 pioche %n cartes. + + + + %1 undoes his last draw. %1 annule sa dernière pioche. - + + %1 undoes her last draw. + + + + %1 undoes his last draw (%2). %1 annule sa dernière pioche (%2). - + + %1 undoes her last draw (%2). + + + + %1 gives %2 control over %3. %1 donne le contrôle de %2 à %3. - + + %1 draws his initial hand. + + + + + %1 draws her initial hand. + + + %1 flips %2 face-down. - %1 retourne %2 face cachée. + %1 retourne %2 face cachée. - %1 flips %2 face-up. - %1 retourne %2 face visible. + %1 retourne %2 face visible. - %1 destroys %2. - %1 détruit %2. + %1 détruit %2. - %1 attaches %2 to %3's %4. need exemple (Resp'.by Ranma: JoueurA attache Adventuring Gear sur -Plated Geopede- de -JoueurB-.) - %1 attache %2 sur %4 de %3. + %1 attache %2 sur %4 de %3. - %1 unattaches %2. - %1 détache %2. + %1 détache %2. - %1 creates token: %2%3. - %1 crée un jeton %2%3. + %1 crée un jeton %2%3. - %1 points from %2's %3 to %4. need exemple - %1 désigne le %3 de %2 à %4. + %1 désigne le %3 de %2 à %4. - %1 points from %2's %3 to %4's %5. need exemple - %1 désigne le %3 de %2 à %5 de %4. + %1 désigne le %3 de %2 à %5 de %4. %1 places %n counter(s) (%2) on %3 (now %4). @@ -1763,23 +3048,21 @@ La version la plus récente est %1, l'ancienne version est %2. - %1 places %n %2 counter(s) on %3 (now %4). - + %1 met %n %2 marqueur sur %3 (maintenant %4). %1 met %n %2 marqueurs sur %3 (maintenant %4). - %1 removes %n %2 counter(s) from %3 (now %4). - + %1 retire %n %2 marqueur de %3 (maintenant %4). %1 retire %n %2 marqueurs de %3 (maintenant %4). - + red rouge @@ -1787,7 +3070,7 @@ La version la plus récente est %1, l'ancienne version est %2. - + yellow jaune @@ -1795,7 +3078,7 @@ La version la plus récente est %1, l'ancienne version est %2. - + green vert @@ -1803,164 +3086,145 @@ La version la plus récente est %1, l'ancienne version est %2. - his permanents - ses permanents + ses permanents - %1 %2 %3. wtf ? - %1 %2 %3. + %1 %2 %3. - taps - engage + engage - untaps - dégage + dégage - %1 sets counter %2 to %3 (%4%5). need exemple - %1 met les marqueurs %2 à %3 (%4%5). + %1 met les marqueurs %2 à %3 (%4%5). - %1 sets %2 to not untap normally. need exemple - %2 de %1 ne se dégagera pas lors de l'étape de dégagement. + %2 de %1 ne se dégagera pas lors de l'étape de dégagement. - %1 sets %2 to untap normally. - %2 de %1 se dégagera lors de l'étape de dégagement. + %2 de %1 se dégagera lors de l'étape de dégagement. - %1 sets PT of %2 to %3. exemple plz - %1 change la F/E de %2 à %3. + %1 change la F/E de %2 à %3. - %1 sets annotation of %2 to %3. - %1 met l'annotation %3 à %2. + %1 met l'annotation %3 à %2. - %1 is looking at the top %2 cards %3. exemple plz - %1 regarde les %2 cartes du dessus %3. + %1 regarde les %2 cartes du dessus %3. - %1 is looking at %2. exemple plz - %1 regarde %2. + %1 regarde %2. - %1 stops looking at %2. need exemple to be sure - %1 arrête de regarder %2. + %1 arrête de regarder %2. - %1 reveals %2 to %3. - %1 révèle %2 à %3. + %1 révèle %2 à %3. - %1 reveals %2. - %1 révèle %2. + %1 révèle %2. - %1 randomly reveals %2%3 to %4. - %1 révèle au hasard %2%3 à %4. + %1 révèle au hasard %2%3 à %4. - %1 randomly reveals %2%3. - %1 révèle au hasard %2%3. + %1 révèle au hasard %2%3. - %1 reveals %2%3 to %4. - %1 révèle %2%3 à %4. + %1 révèle %2%3 à %4. - %1 reveals %2%3. - %1 révèle %2%3. + %1 révèle %2%3. - It is now %1's turn. - C'est maintenant le tour de %1. + C'est maintenant le tour de %1. - + 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 bloqueurs - + combat damage step étape de répartition et de résolution des blessures - + end of combat step étape de fin de combat - + second main phase seconde phase principale - + ending phase phase de fin de tour - + It is now the %1. need exemple C'est maintenant %1. @@ -1969,22 +3233,22 @@ La version la plus récente est %1, l'ancienne version est %2. MessagesSettingsPage - + Add message Ajouter message - + Message: Message: - + &Add &Ajouter - + &Remove &Enlever @@ -2050,323 +3314,323 @@ La version la plus récente est %1, l'ancienne version est %2. Player - + &View graveyard &Voir le cimetière - + &View exile &Voir la zone exil - + Player "%1" Joueur "%1" - + &Graveyard &Cimetière - + &Exile &Exil - - - + + + Move to &top of library Mettre au-dess&us de sa bibliothèque - - - + + + Move to &bottom of library Mettre en-dess&ous de sa bibliothèque - - + + Move to &graveyard Mettre dans son cime&tière - - + + Move to &exile Déplacer dans la zone &exil - - + + Move to &hand Mettre dans sa &main - + &View library &Voir la bibliothèque - + View &top cards of library... Voir les cartes du &dessus de la bibliothèque... - + Reveal &library to Révéler la &bibliothèque à - + Reveal t&op card to Révéler la carte du &dessus à - + &View sideboard &Voir la réserve - + &Draw card &Piocher une carte - + D&raw cards... P&iocher plusieurs cartes... - + &Undo last draw Annu&ler dernière pioche - + Take &mulligan &Mulliganer - + &Shuffle Mél&anger - + Move top cards to &graveyard... Déplacer les cartes du dessus vers le &cimetière... - + Move top cards to &exile... Déplacer les cartes du dessus vers la zone &exil... - + Put top card on &bottom Mettre la carte du dessus en &dessous - + &Hand &Main - + &Reveal to &Révéler à - + Reveal r&andom card to Révéler une carte au &hasard à - + &Sideboard Ré&serve - + &Library &Bibliothèque - + &Counters Mar&queurs - + &Untap all permanents Dé&gager tous les permanents - + R&oll die... Lancer un &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 &Tous les joueurs - + Ctrl+F3 Ctrl+F3 - + F3 F3 - + Ctrl+W Ctrl+W - + F4 F4 - + Ctrl+D Ctrl+D - + Ctrl+E Ctrl+E - + Ctrl+Shift+D Ctrl+Shift+D - + 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 plusieurs cartes - - - - + + + + Number: Nombre: - + Move top cards to grave Mettre les cartes du dessus dans le cimetière - + Move top cards to exile Mettre les cartes du dessus dans la zone exil - + Roll die Lancer un 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 une note - + Please enter the new annotation: Entrez la nouvelle note: - + Set counters Mettre des marqueurs @@ -2452,17 +3716,17 @@ La version la plus récente est %1, l'ancienne version est %2.Réserve - + Cockatrice decks (*.cod) Decks format Cockatrice (*.cod) - + Plain text decks (*.dec *.mwDeck) Decks au format texte (*.dec *.mwDeck) - + All files (*.*) Tous les fichiers (*.*) @@ -2539,40 +3803,73 @@ La version la plus récente est %1, l'ancienne version est %2.Nom complet + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + &OK + + + + &Cancel + &Annuler + + + + Shut down server + + + TabAdmin - + Update server &message Mettre à jour le &message du serveur - + + &Shut down server + + + + Server administration functions Fonctions d'administration du serveur - + &Unlock functions &Débloquer fonctions - + &Lock functions &Bloquer fonctions - + Unlock administration functions Débloquer fonctions d'administration - + Do you really want to unlock the administration functions? Êtes-vous sûr de vouloir débloquer les fonctions d'administration? - + Administration Administration @@ -2667,127 +3964,132 @@ Entrez un nom s'il vous plaît: TabGame - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + &Phases - + &Game &Partie - + Next &phase &Prochaine phase - + Ctrl+Space Ctrl+Space - + Next &turn Prochain &Tour - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter - + &Remove all local arrows &Retirer toutes les flèches locales - + Ctrl+R Ctrl+R - + &Concede &Concéder - + F2 F2 - + &Leave game &Quitter la partie - + + Ctrl+Q + Ctrl+Q + + + &Say: &Dire: - + Concede Concéder - + Are you sure you want to concede this game? Êtes-vous sûr de vouloir concéder la partie? - + Leave game Quitter la partie - + Are you sure you want to leave this game? Êtes-vous sûr de vouloir quitter la partie? - + Kicked Exclu - + You have been kicked out of the game. Vous avez été exclu de la partie. @@ -2800,33 +4102,33 @@ Entrez un nom s'il vous plaît: TabMessage - + Personal &talk need exemple &Discussion privée - + &Leave &Quitter - + This user is ignoring you. Cet utilisateur vous a ignoré. - + %1 has left the server. %1 a quitté le serveur. - + %1 has joined the server. %1 a rejoint le serveur. - + Talking to %1 Vous parlez à %1 @@ -2834,27 +4136,27 @@ Entrez un nom s'il vous plaît: TabRoom - + &Say: &Dire: - + Chat Chat - + &Room &Salon - + &Leave room &Quitter le salon - + You are flooding the chat. Please wait a couple of seconds. Vous floodez le chat. Veuillez patienter quelques secondes. @@ -2886,43 +4188,52 @@ Entrez un nom s'il vous plaît: UserInfoBox - + User information Informations utilisateur - + Real name: Vrai nom: - + + Gender: + + + + Location: Localisation: - + User level: Rang utilisateur: - + Administrator Administrateur - - Judge - arbitre ? - Juge + + Moderator + - + Judge + arbitre ? + Juge + + + Registered user Utilisateur enregistré - + Unregistered user Utilisateur non enregistré @@ -2930,283 +4241,316 @@ Entrez un nom s'il vous plaît: 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églage des animations - + &Tap/untap animation &Animation d'engagement et de dégagement + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + + UserList - + Users online: %1 Utilisateurs en ligne:%1 - + Users in this room: %1 Utilisateurs dans ce salon: %1 - + Buddies online: %1 / %2 Amis connectés; %1 / %2 - + Ignored users online: %1 / %2 Personnes sur liste noire connectés: %1 / %2 - + + %1's games + + + + User &details &Détails utilisateur - + Direct &chat &Chat direct - + + Show this user's &games + + + + Add to &buddy list Ajouter à la liste d'&amis - + Remove from &buddy list Retirer de la liste d'&amis - + Add to &ignore list Ajouter à la liste &noire - + Remove from &ignore list Retirer de la liste &noire - + Ban from &server Bannir du &serveur - Duration - Durée + Durée - Please enter the duration of the ban (in minutes). Enter 0 for an indefinite ban. - Entrez la durée de temps du ban (en minutes). + Entrez la durée de temps du ban (en minutes). Entrez 0 pour une durée illimitée du ban. WndDeckEditor - + &Search... &Chercher... - + &Clear search &Effacer la recherche - + &Search for: &Rechercher: - + Deck &name: &Nom du deck: - + &Comments: &Commentaires: - + + &Update prices + + + + + Ctrl+U + Ctrl+U + + + Deck editor [*] Editeur de deck [*] - + &New deck &Nouveau deck - + &Load deck... Char&ger deck... - + &Save deck &Sauvegarder le deck - + Save deck &as... S&auvegarder le deck sous... - + Load deck from cl&ipboard... Charger deck depuis le presse-pap&ier... - + Save deck to clip&board Sauve&garder 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 de &cartes - + Add card to &maindeck Ajouter carte au &deck - + Return Retour - + Enter Entrer - + Add card to &sideboard Ajouter carte à la ré&serve - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter - + &Remove row &Retirer la ligne - + Del Supprimer - + &Increment number to check &Augmenter quantité - + + + - + &Decrement number to check &Diminuer quantité - + - - - + Are you sure? Êtes-vous sûr? - + 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. Le deck n'a pas pu être enregistré. Vérifiez que le répertoire ne soit pas en lecture seule et réessayez. - + Save deck Sauvegarder le deck diff --git a/cockatrice/translations/cockatrice_ja.ts b/cockatrice/translations/cockatrice_ja.ts index 6ad1942ae..5470b7724 100644 --- a/cockatrice/translations/cockatrice_ja.ts +++ b/cockatrice/translations/cockatrice_ja.ts @@ -37,58 +37,58 @@ 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: カード背面画像へのパス: - + Card rendering カードレンダリング - + Display card names on cards having a picture やや不明 画像持ちカードのカードネームを表示する - + Hand layout 手札のレイアウト - + Display hand horizontally (wastes space) 手札を横に並べる(スペースを消費します) - + Table grid layout テーブルグリッドのレイアウト @@ -97,35 +97,70 @@ 省スペースレイアウト(カード間間隔を細かくできます) - + Invert vertical coordinate 垂直反転調整 - + + Minimum player count for multi-column layout: + + + + Zone view layout ゾーンビューレイアウト - + Sort by name 名前で整列 - + Sort by type タイプで整列 - - - - - + + + + + Choose path 画像の指定 + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + バンする期間を入力してください(分単位).0でバンを解除します. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + + + + + &Cancel + + + + + Ban user from server + + + CardDatabaseModel @@ -157,22 +192,42 @@ CardInfoWidget - + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + Name: カード名: - + Mana cost: マナコスト: - + Card type: カードタイプ: - + P / T: @@ -180,58 +235,58 @@ CardItem - + &Play プレイ - + &Hide テスト版のため確認取れず再度チェック 裏にしてプレイ - + &Tap タップ - + &Untap アンタップ - + Toggle &normal untapping 通常のアンタップをしない - + &Flip 裏にする - + &Clone 複製する - + Ctrl+H - + &Attach to card... カードに付ける... - + Ctrl+A - + Unattac&h 取り外す @@ -240,142 +295,147 @@ P/Tを決める... - + + &Draw arrow... + + + + &Power / toughness パワー / タフネス - + &Increase power パワーを上げる - + Ctrl++ - + &Decrease power パワーを下げる - + Ctrl+- - + I&ncrease toughness タフネスを上げる - + Alt++ - + D&ecrease toughness タフネスを下げる - + Alt+- - + In&crease power and toughness パワーとタフネスを上げる - + Ctrl+Alt++ - + Dec&rease power and toughness パワーとタフネスを下げる - + Ctrl+Alt+- - + Set &power and toughness... パワーとタフネスを設定する... - + Ctrl+P - + &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 移動させる @@ -383,184 +443,364 @@ CardZone - - his hand - nominative - + + her hand + nominative, female owner + - + %1's hand - nominative - + nominative, female owner + - of his hand - genitive - + his hand + nominative, male owner + + %1's hand + nominative, male owner + + + + + of her hand + genitive, female owner + + + + of %1's hand - genitive - + genitive, female owner + - his hand - accusative - + of his hand + genitive, male owner + + of %1's hand + genitive, male owner + + + + + her hand + accusative, female owner + + + + %1's hand - accusative - + accusative, female owner + - - his library - nominative - + + his hand + accusative, male owner + - + + %1's hand + accusative, male owner + + + + + her library + nominative, female owner + + + + %1's library - nominative - + nominative, female owner + - of his library - genitive - + his library + nominative, male owner + + %1's library + nominative, male owner + + + + + of her library + genitive, female owner + + + + of %1's library - genitive - + genitive, female owner + - his library - accusative - + of his library + genitive, male owner + + of %1's library + genitive, male owner + + + + + her library + accusative, female owner + + + + %1's library - accusative - + accusative, female owner + - - his graveyard - nominative - + + his library + accusative, male owner + - + + %1's library + accusative, male owner + + + + + her graveyard + nominative, female owner + + + + %1's graveyard - nominative - + nominative, female owner + - of his graveyard - genitive - + his graveyard + nominative, male owner + + %1's graveyard + nominative, male owner + + + + + of her graveyard + genitive, female owner + + + + of %1's graveyard - genitive - + genitive, female owner + - his graveyard - accusative - + of his graveyard + genitive, male owner + + of %1's graveyard + genitive, male owner + + + + + her graveyard + accusative, female owner + + + + %1's graveyard - accusative - + accusative, female owner + - - his exile - nominative - + + his graveyard + accusative, male owner + - + + %1's graveyard + accusative, male owner + + + + + her exile + nominative, female owner + + + + %1's exile - nominative - + nominative, female owner + - of his exile - genitive - + his exile + nominative, male owner + + %1's exile + nominative, male owner + + + + + of her exile + genitive, female owner + + + + of %1's exile - genitive - + genitive, female owner + - his exile - accusative - + of his exile + genitive, male owner + + of %1's exile + genitive, male owner + + + + + her exile + accusative, female owner + + + + %1's exile - accusative - + accusative, female owner + - - his sideboard - nominative - + + his exile + accusative, male owner + - + + %1's exile + accusative, male owner + + + + + her sideboard + nominative, female owner + + + + %1's sideboard - nominative - + nominative, female owner + - of his sideboard - genitive - + his sideboard + nominative, male owner + + %1's sideboard + nominative, male owner + + + + + of her sideboard + genitive, female owner + + + + of %1's sideboard - genitive - + genitive, female owner + - his sideboard - accusative - + of his sideboard + genitive, male owner + + of %1's sideboard + genitive, male owner + + + + + her sideboard + accusative, female owner + + + + %1's sideboard - accusative - + accusative, female owner + + + + + his sideboard + accusative, male owner + + + + + %1's sideboard + accusative, male owner + @@ -601,38 +841,56 @@ カウンター '%1'の新しい値を設定する: + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + 全般 + + DeckListModel - + Number カード枚数 - + Card カード名 + + + Price + + DeckViewContainer - + Load &local deck ローカルからデッキをロード - + Load d&eck from server サーバーからデッキをロード - + Ready to s&tart 開始準備完了 - + Load deck デッキをロード @@ -721,82 +979,82 @@ 説明: - + &Password: パスワード: - + P&layers: プレイヤー人数: - + Game type ゲームタイプ - + Only &buddies can join フレンドのみ参加可能 - + Only &registered users can join 登録済みプレイヤーのみ参加可能 - + Joining restrictions 参加制限 - + &Spectators allowed 観戦者を許可する - + Spectators &need a password to join 観戦者は参加にパスワードが必要 - + Spectators can &chat 観戦者はチャットに参加できる - + Spectators see &everything 観戦者は全て見れる - + Spectators 観戦者 - + &OK - + &Cancel - + Create game 部屋を作る - + Error エラー - + Server error. サーバーエラー. @@ -938,54 +1196,59 @@ 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 ユーザーインターフェース - + + Deck editor + + + + Messages メッセージ - + &Close @@ -993,87 +1256,98 @@ GameSelector - + C&reate 部屋を作る - + &Join 参加する - - - - - - - + + + + + + + + Error エラー - + + Please join the appropriate room first. + + + + Wrong password. パスワードが間違っています. - + Spectators are not allowed in this game. この試合は観戦者は許可されていません. - + The game is already full. このゲームはすでに満員です. - + The game does not exist any more. このゲームはもう存在しません. - + This game is only open to registered users. このゲームは登録済みプレイヤーにのみ公開されています. - + This game is only open to its creator's buddies. このゲームは作成者のフレンドのみに公開されています. - + You are being ignored by the creator of this game. あなたはこのゲームの作成者によって拒否されています. - + Join game 参加 - + Password: パスワード: - + Games ゲーム - + Show &full games 全てのゲームを見る + + + Show &running games + + &Show full games 全てのゲームを見る - + J&oin as spectator 観戦者として参加 @@ -1089,67 +1363,72 @@ GamesModel - + yes あり - + no なし - + Creator 作成者 - + Description 説明 - + yes, free for spectators あり,観戦は自由 - + buddies only フレンドのみ - + reg. users only 登録済みユーザーのみ - + not allowed 不許可 + Room + 部屋 + + + Game type ゲームタイプ - + Password パスワード - + Restrictions 制限 - + Players プレイヤー - + Spectators 観戦者 @@ -1157,50 +1436,50 @@ GeneralSettingsPage - - - + + + Choose path パスを選択 - + Personal settings 個人設定 - + Language: 言語: - + Download card pictures on the fly - + Paths パス - + Decks directory: デッキディレクトリ: - + Pictures directory: カード画像のディレクトリ: - + Path to card database: カードデータベースのパス: - - + + English Japanese @@ -1220,210 +1499,239 @@ + Scheduled server shutdown. + + + + Unknown reason. 不明な理由. - + Connection closed 通信切断 - + The server has terminated your connection. Reason: %1 サーバーはあなたの接続を切断しました. 理由: %1 - + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + 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: 日本語: - + Russian: ロシア語: - - - - - - + + Czech: + + + + + Slovak: + + + + + + + + + Error エラー - + Server timeout サーバータイムアウト - + Invalid login data. 無効なログインデータです. - + There is already an active session using this user name. Please close that session first and re-login. これはすでにこのユーザー名で使われているアクティブなセッションです. まずこのセッションを閉じてログインしなおしてください. - + Socket error: %1 ソケットエラー: %1 - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. あなたは古いVerのサーバーに接続しようとしています.CockatriceのVerをダウングレードするか適正なサーバーに接続してください. ローカルVer %1,リモートVer %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. あなたのCockatriceのVerが古いです.Cockatriceをアップデートしてください. ローカルVer %1,リモートVer %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? ゲームがまだ開いています.本当に退出しますか? @@ -1431,211 +1739,947 @@ Local version is %1, remote version is %2. 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. - + + You have joined game #%1. + female + - + + You have joined game #%1. + male + + + + + %1 has joined the game. + female + + + + + %1 has joined the game. + male + + + + + %1 has left the game. + female + + + + + %1 has left the game. + male + + + + + %1 has loaded a local deck. + female + + + + + %1 has loaded a local deck. + male + + + + + %1 has loaded deck #%2. + female + + + + + %1 has loaded deck #%2. + male + + + + + %1 is ready to start the game. + female + + + + + %1 is ready to start the game. + male + + + + + %1 is not ready to start the game any more. + female + + + + + %1 is not ready to start the game any more. + male + + + + + %1 has conceded the game. + female + + + + + %1 has conceded the game. + male + + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + %1 rolls a %2 with a %3-sided die. - + female + + + + + %1 rolls a %2 with a %3-sided die. + male + - + %1 draws %n card(s). - + female + + + + + + + %1 draws %n card(s). + male + - + %1 undoes his last draw. - + + %1 undoes her last draw. + + + + %1 undoes his last draw (%2). - + + %1 undoes her last draw (%2). + + + + from table - + from graveyard - + from exile - + from hand - + the bottom card of his library - + + the bottom card of her library + + + + from the bottom of his library - + + from the bottom of her library + + + + the top card of his library - + + the top card of her library + + + + from the top of his library - + + from the top of her library + + + + from library - + from sideboard - + from the stack - + %1 gives %2 control over %3. - + %1 puts %2 into play tapped%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 into her library. + + + + %1 puts %2%3 on bottom of his library. - + + %1 puts %2%3 on bottom of her library. + + + + %1 puts %2%3 on top of his library. - + + %1 puts %2%3 on top of her library. + + + + %1 puts %2%3 into his library at position %4. - + + %1 puts %2%3 into her library at position %4. + + + + %1 moves %2%3 to sideboard. - + %1 plays %2%3. - - - - a card - + + + %1 takes a mulligan to %n. + female + + + + + + + %1 takes a mulligan to %n. + male + + + - + %1 flips %2 face-down. - + female + - + + %1 flips %2 face-down. + male + + + + %1 flips %2 face-up. - + female + - - %1 attaches %2 to %3's %4. - + + %1 flips %2 face-up. + male + - + + %1 destroys %2. + female + + + + + %1 destroys %2. + male + + + + %1 unattaches %2. - + female + - + + %1 unattaches %2. + male + + + + + %1 creates token: %2%3. + female + + + + + %1 creates token: %2%3. + male + + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + + + + + %1 sets counter %2 to %3 (%4%5). + male + + + + + %1 sets %2 to not untap normally. + female + + + + + %1 sets %2 to not untap normally. + male + + + + + %1 sets %2 to untap normally. + female + + + + + %1 sets %2 to untap normally. + male + + + + + %1 sets PT of %2 to %3. + female + + + + + %1 sets PT of %2 to %3. + male + + + + + %1 sets annotation of %2 to %3. + female + + + + + %1 sets annotation of %2 to %3. + male + + + + + %1 is looking at the top %2 cards %3. + female + + + + + %1 is looking at the top %2 cards %3. + male + + + + + %1 is looking at %2. + female + + + + + %1 is looking at %2. + male + + + + + %1 stops looking at %2. + female + + + + + %1 stops looking at %2. + male + + + + + %1 reveals %2 to %3. + p1 female, p2 female + + + + + %1 reveals %2 to %3. + p1 female, p2 male + + + + + %1 reveals %2 to %3. + p1 male, p2 female + + + + + %1 reveals %2 to %3. + p1 male, p2 male + + + + + %1 reveals %2. + female + + + + + %1 reveals %2. + male + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 randomly reveals %2%3. + female + + + + + %1 randomly reveals %2%3. + male + + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 reveals %2%3. + female + + + + + %1 reveals %2%3. + male + + + + + It is now %1's turn. + female + + + + + It is now %1's turn. + male + + + + + + a card @@ -1651,285 +2695,145 @@ Local version is %1, remote version is %2. - + 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. - + + %1 draws his initial hand. + - - Protocol version mismatch. Client: %1, Server: %2 - + + %1 draws her initial hand. + - - 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 destroys %2. - - - - - %1 creates token: %2%3. - - - - - %1 points from %2's %3 to %4. - - - - - %1 places %n %2 counter(s) on %3 (now %4). - - - - - - - %1 removes %n %2 counter(s) from %3 (now %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 - + + %1 attaches %2 to %3's %4. + p1 female, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + + + + 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: メッセージ: @@ -1995,322 +2899,322 @@ Local version is %1, remote version is %2. 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 発言する - + &Undo last draw 最後のドローを取り消す - + Move top cards to &exile... ライブラリーの一番上からX枚追放する - + Put top card on &bottom 一番上のカードを一番下に置く - + &Reveal to 公開する - + Reveal r&andom card to ランダムに公開する - + C&ard カード - + &All players 全てのプレイヤー - + Ctrl+F3 - + Ctrl+Shift+D - + 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 カウンターを設定する @@ -2388,17 +3292,17 @@ Local version is %1, remote version is %2. サイドボード - + Cockatrice decks (*.cod) - + Plain text decks (*.dec *.mwDeck) - + All files (*.*) 全てのファイル (*.*) @@ -2474,40 +3378,73 @@ Local version is %1, remote version is %2. 正式名称 + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + + + + + &Cancel + + + + + Shut down server + + + TabAdmin - + Update server &message サーバー更新&メッセージ - + + &Shut down server + + + + Server administration functions サーバー管理機能 - + &Unlock functions 機能をアンロックする - + &Lock functions 機能をロックする - + Unlock administration functions 管理機能をアンロックする - + Do you really want to unlock the administration functions? 本当に管理機能をアンロックしますか? - + Administration 管理者 @@ -2601,127 +3538,132 @@ Please enter a name: TabGame - + F5 - + F6 - + F7 - + F8 - + F9 - + F10 - + &Phases フェイズ - + &Game ゲーム - + Next &phase 次のフェイズ - + Ctrl+Space - + Next &turn 次のターン - + Ctrl+Return - + Ctrl+Enter - + &Remove all local arrows 全ての矢印を消す - + Ctrl+R - + &Concede 投了する - + F2 - + &Leave game ゲームを退出する - + + Ctrl+Q + + + + &Say: 発言する - + Concede 投了する - + Are you sure you want to concede this game? 本当にこのゲームに投了しますか? - + Leave game ゲームから退出する - + Are you sure you want to leave this game? 本当にこのゲームから退出しますか? - + Kicked キック - + You have been kicked out of the game. あなたはこのゲームからキックされました. @@ -2734,32 +3676,32 @@ Please enter a name: TabMessage - + Personal &talk 個人会話 - + &Leave 退出する - + This user is ignoring you. このユーザーはあなたを無視しています. - + %1 has left the server. %1はサーバーから退出しました. - + %1 has joined the server. %1がサーバーに参加しました. - + Talking to %1 %1と会話 @@ -2767,27 +3709,27 @@ Please enter a name: TabRoom - + &Say: 発言する - + Chat チャット - + &Room 部屋 - + &Leave room 部屋から出る - + You are flooding the chat. Please wait a couple of seconds. あなたはチャットルームから弾かれました.少々お待ちください. @@ -2819,42 +3761,51 @@ Please enter a name: UserInfoBox - + User information ユーザー情報 - + Real name: 本名: - + + Gender: + + + + Location: 現在地: - + User level: ユーザーレベル: - + Administrator 管理者 - - Judge - ジャッジ + + Moderator + - + Judge + ジャッジ + + + Registered user 登録ユーザー - + Unregistered user 未登録ユーザー @@ -2862,278 +3813,311 @@ Please enter a name: UserInterfaceSettingsPage - + General interface settings インターフェース総合設定 - + &Double-click cards to play them (instead of single-click) ダブルクリックでカードをプレイする(シングルクリックの代わり) - + Animation settings アニメーション設定 - + &Tap/untap animation タップ/アンタップアニメーション + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + + UserList - + Users online: %1 ユーザー オンライン: %1 - + Users in this room: %1 部屋のユーザー数: %1 - + Buddies online: %1 / %2 フレンドオンライン: %1 / %2 - + Ignored users online: %1 / %2 無視ユーザーオンライン: %1 / %2 - + + %1's games + + + + User &details ユーザー補足 - + Direct &chat 個人チャット - + + Show this user's &games + + + + Add to &buddy list フレンドリストに追加 - + Remove from &buddy list フレンドリストから削除 - + Add to &ignore list 無視リストに追加 - + Remove from &ignore list 無視リストから削除 - + Ban from &server サーバーからバンする - Duration - 期間 + 期間 - Please enter the duration of the ban (in minutes). Enter 0 for an indefinite ban. - バンする期間を入力してください(分単位).0でバンを解除します. + バンする期間を入力してください(分単位).0でバンを解除します. WndDeckEditor - + &Search for: 検索: - + Deck &name: デッキ名: - + &Comments: コメント: - + Deck editor [*] デッキエディター [*] - + &New deck 新しいデッキ - + &Load deck... デッキをロード... - + Load deck from cl&ipboard... クリップボードからデッキをロード... - + &Save deck デッキを保存 - + + &Update prices + + + + + Ctrl+U + + + + 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? このデッキリストは変更されています.変更を保存しますか? diff --git a/cockatrice/translations/cockatrice_pl.ts b/cockatrice/translations/cockatrice_pl.ts new file mode 100644 index 000000000..f13d9e828 --- /dev/null +++ b/cockatrice/translations/cockatrice_pl.ts @@ -0,0 +1,4047 @@ + + + + + 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: + + + + + Card rendering + + + + + Display card names on cards having a picture + + + + + Hand layout + + + + + Display hand horizontally (wastes space) + + + + + Table grid layout + + + + + Invert vertical coordinate + + + + + Minimum player count for multi-column layout: + + + + + Zone view layout + + + + + Sort by name + + + + + Sort by type + + + + + + + + + Choose path + + + + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + + + + + &Cancel + + + + + Ban user from server + + + + + CardDatabaseModel + + + Name + + + + + Sets + + + + + Mana cost + + + + + Card type + + + + + P/T + + + + + CardInfoWidget + + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + + Name: + + + + + Mana cost: + + + + + Card type: + + + + + P / T: + + + + + CardItem + + + &Play + + + + + &Hide + + + + + &Tap + + + + + &Untap + + + + + Toggle &normal untapping + + + + + &Flip + + + + + &Clone + + + + + Ctrl+H + + + + + &Attach to card... + + + + + Ctrl+A + + + + + Unattac&h + + + + + &Draw arrow... + + + + + &Power / toughness + + + + + &Increase power + + + + + Ctrl++ + + + + + &Decrease power + + + + + Ctrl+- + + + + + I&ncrease toughness + + + + + Alt++ + + + + + D&ecrease toughness + + + + + Alt+- + + + + + In&crease power and toughness + + + + + Ctrl+Alt++ + + + + + Dec&rease power and toughness + + + + + Ctrl+Alt+- + + + + + Set &power and toughness... + + + + + Ctrl+P + + + + + &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 + + + + + CardZone + + + her hand + nominative, female owner + + + + + %1's hand + nominative, female owner + + + + + his hand + nominative, male owner + + + + + %1's hand + nominative, male owner + + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + + + + + of his hand + genitive, male owner + + + + + of %1's hand + genitive, male owner + + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + + + + + his hand + accusative, male owner + + + + + %1's hand + accusative, male owner + + + + + her library + nominative, female owner + + + + + %1's library + nominative, female owner + + + + + his library + nominative, male owner + + + + + %1's library + nominative, male owner + + + + + of her library + genitive, female owner + + + + + of %1's library + genitive, female owner + + + + + of his library + genitive, male owner + + + + + of %1's library + genitive, male owner + + + + + her library + accusative, female owner + + + + + %1's library + accusative, female owner + + + + + his library + accusative, male owner + + + + + %1's library + accusative, male owner + + + + + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + + + + + his graveyard + nominative, male owner + + + + + %1's graveyard + nominative, male owner + + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + + + + + of his graveyard + genitive, male owner + + + + + of %1's graveyard + genitive, male owner + + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + + + + + his graveyard + accusative, male owner + + + + + %1's graveyard + accusative, male owner + + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + + + + + his exile + nominative, male owner + + + + + %1's exile + nominative, male owner + + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + + + + + of his exile + genitive, male owner + + + + + of %1's exile + genitive, male owner + + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + + + + + his exile + accusative, male owner + + + + + %1's exile + accusative, male owner + + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + + + + + his sideboard + nominative, male owner + + + + + %1's sideboard + nominative, male owner + + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + + + + + of his sideboard + genitive, male owner + + + + + of %1's sideboard + genitive, male owner + + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + + + + + his sideboard + accusative, male owner + + + + + %1's sideboard + accusative, male owner + + + + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + + + + + DeckListModel + + + Number + + + + + Card + + + + + Price + + + + + DeckViewContainer + + + Load &local deck + + + + + Load d&eck from server + + + + + Ready to s&tart + + + + + Load deck + + + + + DlgCardSearch + + + Card name: + + + + + Card text: + + + + + Card type (OR): + + + + + Color (OR): + + + + + O&K + + + + + &Cancel + + + + + Card search + + + + + DlgConnect + + + &Host: + + + + + &Port: + + + + + Player &name: + + + + + P&assword: + + + + + &OK + + + + + &Cancel + + + + + Connect to server + + + + + DlgCreateGame + + + &Description: + + + + + P&layers: + + + + + Game type + + + + + &Password: + + + + + Only &buddies can join + + + + + Only &registered users can join + + + + + Joining restrictions + + + + + &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 + + + + + Deck editor + + + + + Messages + + + + + &Close + + + + + GameSelector + + + + + + + + + + Error + + + + + Please join the appropriate room first. + + + + + Wrong password. + + + + + Spectators are not allowed in this game. + + + + + The game is already full. + + + + + The game does not exist any more. + + + + + This game is only open to registered users. + + + + + This game is only open to its creator's buddies. + + + + + You are being ignored by the creator of this game. + + + + + Join game + + + + + Password: + + + + + Games + + + + + Show &full games + + + + + Show &running games + + + + + C&reate + + + + + &Join + + + + + J&oin as spectator + + + + + GameView + + + Esc + + + + + GamesModel + + + yes + + + + + yes, free for spectators + + + + + no + + + + + buddies only + + + + + reg. users only + + + + + not allowed + + + + + Room + + + + + Description + + + + + Creator + + + + + Game type + + + + + Password + + + + + Restrictions + + + + + Players + + + + + Spectators + + + + + GeneralSettingsPage + + + + English + + + + + + + Choose path + + + + + Personal settings + + + + + Language: + + + + + Download card pictures on the fly + + + + + Paths + + + + + Decks directory: + + + + + Pictures directory: + + + + + Path to card database: + + + + + MainWindow + + + There are too many concurrent connections from your address. + + + + + Banned by moderator. + + + + + Scheduled server shutdown. + + + + + Unknown reason. + + + + + Connection closed + + + + + The server has terminated your connection. +Reason: %1 + + + + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + + + Number of players + + + + + Please enter the number of players. + + + + + + Player %1 + + + + + About Cockatrice + + + + + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + + French: + + + + + Japanese: + + + + + Russian: + + + + + Czech: + + + + + Slovak: + + + + + + + + + + Error + + + + + Server timeout + + + + + Invalid login data. + + + + + There is already an active session using this user name. +Please close that session first and re-login. + + + + + Socket error: %1 + + + + + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. +Local version is %1, remote version is %2. + + + + + Your Cockatrice client is obsolete. Please update your Cockatrice version. +Local version is %1, remote version is %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? + + + + + MessageLogWidget + + + The game has been closed. + + + + + %1 is now watching the game. + + + + + %1 is not watching the game any more. + + + + + The game has started. + + + + + You have joined game #%1. + female + + + + + You have joined game #%1. + male + + + + + %1 has joined the game. + female + + + + + %1 has joined the game. + male + + + + + %1 has left the game. + female + + + + + %1 has left the game. + male + + + + + %1 has loaded a local deck. + female + + + + + %1 has loaded a local deck. + male + + + + + %1 has loaded deck #%2. + female + + + + + %1 has loaded deck #%2. + male + + + + + %1 is ready to start the game. + female + + + + + %1 is ready to start the game. + male + + + + + %1 is not ready to start the game any more. + female + + + + + %1 is not ready to start the game any more. + male + + + + + %1 has conceded the game. + female + + + + + %1 has conceded the game. + male + + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + + %1 rolls a %2 with a %3-sided die. + female + + + + + %1 rolls a %2 with a %3-sided die. + male + + + + + %1 draws %n card(s). + female + + + + + + + + + %1 draws %n card(s). + male + + + + + + + + + %1 undoes his last draw. + + + + + %1 undoes her last draw. + + + + + %1 undoes his last draw (%2). + + + + + %1 undoes her last draw (%2). + + + + + from table + + + + + from graveyard + + + + + from exile + + + + + from hand + + + + + the bottom card of his library + + + + + the bottom card of her library + + + + + from the bottom of his library + + + + + from the bottom of her library + + + + + the top card of his library + + + + + the top card of her library + + + + + from the top of his library + + + + + from the top of her library + + + + + from library + + + + + from sideboard + + + + + from the stack + + + + + + a card + + + + + %1 gives %2 control over %3. + + + + + %1 puts %2 into play tapped%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 into her library. + + + + + %1 puts %2%3 on bottom of his library. + + + + + %1 puts %2%3 on bottom of her library. + + + + + %1 puts %2%3 on top of his library. + + + + + %1 puts %2%3 on top of her library. + + + + + %1 puts %2%3 into his library at position %4. + + + + + %1 puts %2%3 into her library at position %4. + + + + + %1 moves %2%3 to sideboard. + + + + + %1 plays %2%3. + + + + + %1 takes a mulligan to %n. + female + + + + + + + + + %1 takes a mulligan to %n. + male + + + + + + + + + %1 flips %2 face-down. + female + + + + + %1 flips %2 face-down. + male + + + + + %1 flips %2 face-up. + female + + + + + %1 flips %2 face-up. + male + + + + + %1 destroys %2. + female + + + + + %1 destroys %2. + male + + + + + %1 unattaches %2. + female + + + + + %1 unattaches %2. + male + + + + + %1 creates token: %2%3. + female + + + + + %1 creates token: %2%3. + male + + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + + + + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + + + + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + + + + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + + + + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + + + + + %1 sets counter %2 to %3 (%4%5). + male + + + + + %1 sets %2 to not untap normally. + female + + + + + %1 sets %2 to not untap normally. + male + + + + + %1 sets %2 to untap normally. + female + + + + + %1 sets %2 to untap normally. + male + + + + + %1 sets PT of %2 to %3. + female + + + + + %1 sets PT of %2 to %3. + male + + + + + %1 sets annotation of %2 to %3. + female + + + + + %1 sets annotation of %2 to %3. + male + + + + + %1 is looking at the top %2 cards %3. + female + + + + + %1 is looking at the top %2 cards %3. + male + + + + + %1 is looking at %2. + female + + + + + %1 is looking at %2. + male + + + + + %1 stops looking at %2. + female + + + + + %1 stops looking at %2. + male + + + + + %1 reveals %2 to %3. + p1 female, p2 female + + + + + %1 reveals %2 to %3. + p1 female, p2 male + + + + + %1 reveals %2 to %3. + p1 male, p2 female + + + + + %1 reveals %2 to %3. + p1 male, p2 male + + + + + %1 reveals %2. + female + + + + + %1 reveals %2. + male + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 randomly reveals %2%3. + female + + + + + %1 randomly reveals %2%3. + male + + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 reveals %2%3. + female + + + + + %1 reveals %2%3. + male + + + + + It is now %1's turn. + female + + + + + It is now %1's turn. + male + + + + + %1 draws his initial hand. + + + + + %1 draws her initial hand. + + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + + + + + red + + + + + + + + + yellow + + + + + + + + + green + + + + + + + + + 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 + + + + + ending phase + + + + + It is now the %1. + + + + + MessagesSettingsPage + + + Add message + + + + + Message: + + + + + &Add + + + + + &Remove + + + + + 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 + + + + + Player + + + &View graveyard + + + + + &View exile + + + + + Player "%1" + + + + + &Graveyard + + + + + &Exile + + + + + + + Move to &top of library + + + + + + + Move to &bottom of library + + + + + + Move to &graveyard + + + + + + Move to &exile + + + + + + Move to &hand + + + + + &View library + + + + + View &top cards of library... + + + + + Reveal &library to + + + + + Reveal t&op card to + + + + + &View sideboard + + + + + &Draw card + + + + + D&raw cards... + + + + + &Undo last draw + + + + + Take &mulligan + + + + + &Shuffle + + + + + Move top cards to &graveyard... + + + + + Move top cards to &exile... + + + + + Put top card on &bottom + + + + + &Hand + + + + + &Reveal to + + + + + Reveal r&andom card to + + + + + &Sideboard + + + + + &Library + + + + + &Counters + + + + + &Untap all permanents + + + + + R&oll die... + + + + + &Create token... + + + + + C&reate another token + + + + + S&ay + + + + + C&ard + + + + + &All players + + + + + Ctrl+F3 + + + + + F3 + + + + + Ctrl+W + + + + + F4 + + + + + Ctrl+D + + + + + Ctrl+E + + + + + Ctrl+Shift+D + + + + + Ctrl+M + + + + + Ctrl+S + + + + + Ctrl+U + + + + + Ctrl+I + + + + + Ctrl+T + + + + + Ctrl+G + + + + + View top cards of library + + + + + Number of cards: + + + + + 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 + + + + + PlayerListWidget + + + local deck + + + + + deck #%1 + + + + + User &details + + + + + Direct &chat + + + + + Add to &buddy list + + + + + Remove from &buddy list + + + + + Add to &ignore list + + + + + Remove from &ignore list + + + + + Kick from &game + + + + + 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 + + + + + SetsModel + + + Short name + + + + + Long name + + + + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + + + + + &Cancel + + + + + Shut down server + + + + + TabAdmin + + + Update server &message + + + + + &Shut down server + + + + + Server administration functions + + + + + &Unlock functions + + + + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration + + + + + 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 + + + F5 + + + + + F6 + + + + + F7 + + + + + F8 + + + + + F9 + + + + + F10 + + + + + &Phases + + + + + &Game + + + + + Next &phase + + + + + Ctrl+Space + + + + + Next &turn + + + + + Ctrl+Return + + + + + Ctrl+Enter + + + + + &Remove all local arrows + + + + + Ctrl+R + + + + + &Concede + + + + + F2 + + + + + &Leave game + + + + + Ctrl+Q + + + + + &Say: + + + + + Concede + + + + + Are you sure you want to concede this game? + + + + + Leave game + + + + + Are you sure you want to leave this game? + + + + + Kicked + + + + + You have been kicked out of the game. + + + + + Game %1: %2 + + + + + TabMessage + + + Personal &talk + + + + + &Leave + + + + + This user is ignoring you. + + + + + %1 has left the server. + + + + + %1 has joined the server. + + + + + Talking to %1 + + + + + TabRoom + + + &Say: + + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + You are flooding the chat. Please wait a couple of seconds. + + + + + TabServer + + + Server + + + + + TabUserLists + + + User lists + + + + + UserInfoBox + + + User information + + + + + Real name: + + + + + Gender: + + + + + Location: + + + + + User level: + + + + + Administrator + + + + + Moderator + + + + + Registered user + + + + + Unregistered user + + + + + UserInterfaceSettingsPage + + + General interface settings + + + + + &Double-click cards to play them (instead of single-click) + + + + + Animation settings + + + + + &Tap/untap animation + + + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + + + + + UserList + + + Users online: %1 + + + + + Users in this room: %1 + + + + + Buddies online: %1 / %2 + + + + + Ignored users online: %1 / %2 + + + + + %1's games + + + + + User &details + + + + + Direct &chat + + + + + Show this user's &games + + + + + Add to &buddy list + + + + + Remove from &buddy list + + + + + Add to &ignore list + + + + + Remove from &ignore list + + + + + Ban from &server + + + + + WndDeckEditor + + + &Search... + + + + + &Clear search + + + + + &Search for: + + + + + Deck &name: + + + + + &Comments: + + + + + &Update prices + + + + + Ctrl+U + + + + + Deck editor [*] + + + + + &New deck + + + + + &Load deck... + + + + + &Save deck + + + + + Save deck &as... + + + + + Load deck from cl&ipboard... + + + + + Save deck to clip&board + + + + + &Print deck... + + + + + &Close + + + + + Ctrl+Q + + + + + &Edit sets... + + + + + &Deck + + + + + &Card database + + + + + Add card to &maindeck + + + + + Return + + + + + Enter + + + + + Add card to &sideboard + + + + + Ctrl+Return + + + + + Ctrl+Enter + + + + + &Remove row + + + + + Del + + + + + &Increment number + + + + + + + + + + + &Decrement number + + + + + - + + + + + Are you sure? + + + + + The decklist has been modified. +Do you want to save the changes? + + + + + Load deck + + + + + + Error + + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + + Save deck + + + + + 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 index c7d3bb81c..9c018f044 100644 --- a/cockatrice/translations/cockatrice_pt-br.ts +++ b/cockatrice/translations/cockatrice_pt-br.ts @@ -37,57 +37,57 @@ 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: - + Card rendering Renderização do card - + Display card names on cards having a picture Mostrar o nome dos cards nos cards que tem imagem - + 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 @@ -96,35 +96,71 @@ Layout econômico - + Invert vertical coordinate Inverter a coordenada vertical - + + Minimum player count for multi-column layout: + + + + Zone view layout Layout de vista da zona - + Sort by name Ordenar por nome - + Sort by type Ordenar por tipo - - - - - + + + + + Choose path Escolher caminho + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Por favor, digite a duração do banimento (em minutos). +Digite 0 para banir indefinidamente. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + Ban user from server + + + CardDatabaseModel @@ -156,22 +192,42 @@ CardInfoWidget - + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + Name: Nome: - + Mana cost: Custo de mana: - + Card type: Tipo de card: - + P / T: P / R: @@ -179,57 +235,57 @@ CardItem - + &Play &Jogar - + &Hide &Ocultar - + &Tap &Virar - + &Untap &Desvirar - + Toggle &normal untapping &Trocar o modo de desvirar - + &Flip Virar a &face - + &Clone Clo&nar - + Ctrl+H Ctrl+H - + &Attach to card... Ane&xar ao card... - + Ctrl+A Ctrl+A - + Unattac&h De&sanexar @@ -238,142 +294,147 @@ Alterar &P/R... - + + &Draw arrow... + + + + &Power / toughness Po&der / resistência - + &Increase power Au&mentar poder - + Ctrl++ Ctrl++ - + &Decrease power Dimi&nuir poder - + Ctrl+- Ctrl+- - + I&ncrease toughness A&umentar resistência - + Alt++ Alt++ - + D&ecrease toughness D&iminuir resistência - + Alt+- Alt+- - + In&crease power and toughness Aumen&tar poder e resistência - + Ctrl+Alt++ Ctrl+Alt++ - + Dec&rease power and toughness Diminuir p&oder e resistência - + Ctrl+Alt+- Ctrl+Alt+- - + Set &power and toughness... Alterar poder e resis&tência... - + Ctrl+P Ctrl+P - + &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 @@ -381,184 +442,514 @@ CardZone - his hand nominative - sua mão + sua mão - %1's hand nominative - mão de %1 + mão de %1 - of his hand genitive - da sua mão + 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 - of %1's hand - genitive - da mão de %1 + her hand + nominative, female owner + - - his hand - accusative - sua mão - - - + %1's hand - accusative - mão de %1 + nominative, female owner + mão de %1 - - his library - nominative - seu grimório + + his hand + nominative, male owner + sua mão - + + %1's hand + nominative, male owner + mão de %1 + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + da mão de %1 + + + + of his hand + genitive, male owner + da sua mão + + + + of %1's hand + genitive, male owner + da mão de %1 + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + mão de %1 + + + + his hand + accusative, male owner + sua mão + + + + %1's hand + accusative, male owner + mão de %1 + + + + her library + nominative, female owner + + + + %1's library - nominative - grimório de %1 + nominative, female owner + grimório de %1 - of his library - genitive - do seu grimório + his library + nominative, male owner + seu grimório + %1's library + nominative, male owner + grimório de %1 + + + + of her library + genitive, female owner + + + + of %1's library - genitive - do grimório de %1 + genitive, female owner + do grimório de %1 - his library - accusative - seu grimório + of his library + genitive, male owner + do seu grimório + of %1's library + genitive, male owner + do grimório de %1 + + + + her library + accusative, female owner + + + + %1's library - accusative - grimório de %1 + accusative, female owner + grimório de %1 - - his graveyard - nominative - seu cemitério + + his library + accusative, male owner + seu grimório - - %1's graveyard - nominative - cemitério de %1 + + %1's library + accusative, male owner + grimório de %1 + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + cemitério de %1 + + + + his graveyard + nominative, male owner + seu cemitério + + + + %1's graveyard + nominative, male owner + cemitério de %1 + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + do cemitério de %1 + + + + of his graveyard + genitive, male owner + do seu cemitério + + + + of %1's graveyard + genitive, male owner + do cemitério de %1 + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + cemitério de %1 + + + + his graveyard + accusative, male owner + seu cemitério + + + + %1's graveyard + accusative, male owner + cemitério de %1 + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + exílio de %1 + + + + his exile + nominative, male owner + seu exílio + + + + %1's exile + nominative, male owner + exílio de %1 + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + do exílio de %1 + + + + of his exile + genitive, male owner + do seu exílio + + + + of %1's exile + genitive, male owner + do exílio de %1 + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + exílio de %1 + + + + his exile + accusative, male owner + seu exílio + + + + %1's exile + accusative, male owner + exílio de %1 + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + sideboard de %1 + + + + his sideboard + nominative, male owner + seu sideboard + + + + %1's sideboard + nominative, male owner + sideboard de %1 + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + do sideboard de %1 + + + + of his sideboard + genitive, male owner + do seu sideboard + + + + of %1's sideboard + genitive, male owner + do sideboard de %1 + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + sideboard de %1 + + + + his sideboard + accusative, male owner + seu sideboard + + + + %1's sideboard + accusative, male owner + sideboard de %1 + + + his graveyard + nominative + seu cemitério + + + %1's graveyard + nominative + cemitério de %1 + + of his graveyard genitive - do seu cemitério + do seu cemitério - of %1's graveyard genitive - do cemitério de %1 + do cemitério de %1 - his graveyard accusative - seu cemitério + seu cemitério - %1's graveyard accusative - cemitério de %1 + cemitério de %1 - his exile nominative - seu exílio + seu exílio - %1's exile nominative - exílio de %1 + exílio de %1 - of his exile genitive - do seu exílio + do seu exílio - of %1's exile genitive - do exílio de %1 + do exílio de %1 - his exile accusative - seu exílio + seu exílio - %1's exile accusative - exílio de %1 + exílio de %1 - his sideboard nominative - seu sideboard + seu sideboard - %1's sideboard nominative - sideboard de %1 + sideboard de %1 - of his sideboard genitive - do seu sideboard + do seu sideboard - of %1's sideboard genitive - do sideboard de %1 + do sideboard de %1 - his sideboard accusative - seu sideboard + seu sideboard - %1's sideboard accusative - sideboard de %1 + sideboard de %1 @@ -611,38 +1002,56 @@ Novo valor para o marcador '%1': + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + Geral + + DeckListModel - + Number Número - + Card Card + + + Price + + 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 @@ -738,82 +1147,82 @@ &Descrição: - + &Password: S&enha: - + P&layers: &Jogadores: - + Game type Tipo de jogo - + Only &buddies can join Apenas ami&gos podem entrar - + Only &registered users can join Apenas usuários re&gistrados podem entrar - + Joining restrictions Restrições para entrar - + &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. @@ -955,54 +1364,59 @@ 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 - + + Deck editor + + + + Messages Mensagens - + &Close &Fechar @@ -1010,87 +1424,98 @@ GameSelector - + C&reate &Criar - + &Join &Entrar - - - - - - - + + + + + + + + Error Erro - + + Please join the appropriate room first. + + + + 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. - + This game is only open to registered users. Este jogo é aberto apenas para usuários registrados. - + This game is only open to its creator's buddies. Este jogo é aberto apenas para os amigos de quem criou o jogo. - + You are being ignored by the creator of this game. Você está sendo ignorado pelo criador deste jogo. - + Join game Entrar no jogo - + Password: Senha: - + Games Jogos - + Show &full games &Mostrar os jogos cheios + + + Show &running games + + &Show full games &Mostrar os jogos cheios - + J&oin as spectator E&ntrar como visitante @@ -1106,67 +1531,72 @@ GamesModel - + yes sim - + no não - + Creator Criador - + Description Descrição - + yes, free for spectators sim, livre para visitantes - + buddies only apenas amigos - + reg. users only usuários reg. apenas - + not allowed não permitidos + Room + Sala + + + Game type Tipo de jogo - + Password Senha - + Restrictions Restrições - + Players Jogadores - + Spectators Visitantes @@ -1174,50 +1604,50 @@ 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 @@ -1225,23 +1655,23 @@ 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 @@ -1250,72 +1680,72 @@ <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 Versão %1 - + Authors: Autores: - + Translators: Tradutores: - + Spanish: Espanhol: - + Portugese (Portugal): Português (Portugal): - + Portugese (Brazil): Português (Brasil): - + French: Francês: - + Japanese: Japonês: - + Russian: Russo: - - - - - - + + + + + + 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 @@ -1335,119 +1765,149 @@ + Scheduled server shutdown. + + + + Unknown reason. Razão desconhecida. - + Connection closed Conexão fechada - + The server has terminated your connection. Reason: %1 O servidor terminou sua conexão. Razão: %1 - + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + + Czech: + + + + + Slovak: + + + + There is already an active session using this user name. Please close that session first and re-login. Já existe uma sessão ativa usando este nome de usuário. Por favor, feche a sessão primeiro e logue novamente. - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. Você está tentando conectar a um servidor obsoleto. Por favor, faça um downgrade na versão do seu Cockatrice ou conecte-se ao servidor correto. A versão local é %1 e a versão remota é %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. A versão do seu Cockatrice é obsoleta. Por favor, atualize a sua versão. A versão local é %1 e a 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? @@ -1455,213 +1915,1041 @@ A versão local é %1 e a versão remota é %2. MessageLogWidget - Connecting to %1... - Conectando a %1... + Conectando a %1... - Disconnected from server. - Desconectado do servidor. + Desconectado do servidor. - Invalid password. - Senha incorreta. + Senha incorreta. - Protocol error. - Erro de protocolo. + 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 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. + %1 tirou um %2 com um dado de %3 lados. - %1 draws %n card(s). - + %1 compra %n card. %1 compra %n cards. - + + You have joined game #%1. + female + Você entrou no jogo nº %1. + + + + You have joined game #%1. + male + Você entrou no jogo nº %1. + + + + %1 has joined the game. + female + %1 entrou no jogo. + + + + %1 has joined the game. + male + %1 entrou no jogo. + + + + %1 has left the game. + female + %1 saiu do jogo. + + + + %1 has left the game. + male + %1 saiu do jogo. + + + + %1 has loaded a local deck. + female + %1 carregou um deck local. + + + + %1 has loaded a local deck. + male + %1 carregou um deck local. + + + + %1 has loaded deck #%2. + female + %1 carregou o deck nº %2. + + + + %1 has loaded deck #%2. + male + %1 carregou o deck nº %2. + + + + %1 is ready to start the game. + female + %1 está pronto para começar o jogo. + + + + %1 is ready to start the game. + male + %1 está pronto para começar o jogo. + + + + %1 is not ready to start the game any more. + female + %1 não está mais pronto para começar o jogo. + + + + %1 is not ready to start the game any more. + male + %1 não está mais pronto para começar o jogo. + + + + %1 has conceded the game. + female + %1 concedeu o jogo. + + + + %1 has conceded the game. + male + %1 concedeu o jogo. + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + + %1 rolls a %2 with a %3-sided die. + female + %1 tirou um %2 com um dado de %3 lados. + + + + %1 rolls a %2 with a %3-sided die. + male + %1 tirou um %2 com um dado de %3 lados. + + + + %1 draws %n card(s). + female + + %1 compra %n card. + %1 compra %n cards. + + + + + %1 draws %n card(s). + male + + %1 compra %n card. + %1 compra %n cards. + + + + %1 undoes his last draw. %1 desfaz sua última compra. - + + %1 undoes her last draw. + + + + %1 undoes his last draw (%2). %1 desfaz sua última compra (%2). - + + %1 undoes her last draw (%2). + + + + 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 - + + the bottom card of her library + + + + from the bottom of his library vindo do fundo do seu grimório - + + from the bottom of her library + + + + the top card of his library o card do topo do seu grimório - + + the top card of her library + + + + from the top of his library vindo do topo do seu grimório - + + from the top of her library + + + + from library vindo do grimório - + from sideboard vindo do sideboard - + from the stack vindo da pilha - + %1 gives %2 control over %3. %1 dá controle para %2 sobre %3. - + %1 puts %2 into play tapped%3. %1 põe %2 em jogo virado%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 into her library. + + + + %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 bottom of her library. + + + + %1 puts %2%3 on top of his library. %1 põe %2 no topo do seu grimório%3. - + + %1 puts %2%3 on top of her library. + + + + %1 puts %2%3 into his library at position %4. %1 põe %2 no seu grimório na posição %4%3. - + + %1 puts %2%3 into her library at position %4. + + + + %1 moves %2%3 to sideboard. %1 move %2 para o sideboard%3. - + %1 plays %2%3. %1 põe %2 na pilha%3. + + + %1 takes a mulligan to %n. + female + + + + + + + + %1 takes a mulligan to %n. + male + + + + + - - + + %1 flips %2 face-down. + female + %1 vira %2 para baixo. + + + + %1 flips %2 face-down. + male + %1 vira %2 para baixo. + + + + %1 flips %2 face-up. + female + %1 vira %2 para cima. + + + + %1 flips %2 face-up. + male + %1 vira %2 para cima. + + + + %1 destroys %2. + female + %1 destrói %2. + + + + %1 destroys %2. + male + %1 destrói %2. + + + %1 attaches %2 to %3's %4. + female + %1 anexa %2 a %4 de %3. + + + %1 attaches %2 to %3's %4. + male + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + %1 anexa %2 a %4 de %3. + + + + %1 unattaches %2. + female + %1 desanexa %2. + + + + %1 unattaches %2. + male + %1 desanexa %2. + + + + %1 creates token: %2%3. + female + %1 cria a ficha: %2%3. + + + + %1 creates token: %2%3. + male + %1 cria a ficha: %2%3. + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + %1 aponta para %4 com %3 de %2 . + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + %1 aponta para %4 com %3 de %2 . + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + %1 aponta para %4 com %3 de %2 . + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + %1 aponta para %4 com %3 de %2 . + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + %1 aponta para %4 com %3 de %2 . + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + %1 aponta para %4 com %3 de %2 . + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + %1 aponta para %4 com %3 de %2 . + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + %1 aponta para %4 com %3 de %2 . + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + %1 aponta para %5 de %4 com %3 de %2. + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + %1 põe %n marcador %2 em %3 (agora %4). + %1 põe %n marcadores %2 em %3 (agora %4). + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 põe %n marcador %2 em %3 (agora %4). + %1 põe %n marcadores %2 em %3 (agora %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 tira %n marcador %2 em %3 (agora %4). + %1 tira %n marcadores %2 em %3 (agora %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + %1 tira %n marcador %2 em %3 (agora %4). + %1 tira %n marcadores %2 em %3 (agora %4). + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + %1 altera o marcador %2 para %3 (%4%5). + + + + %1 sets counter %2 to %3 (%4%5). + male + %1 altera o marcador %2 para %3 (%4%5). + + + + %1 sets %2 to not untap normally. + female + %1 define que %2 não desvira normalmente. + + + + %1 sets %2 to not untap normally. + male + %1 define que %2 não desvira normalmente. + + + + %1 sets %2 to untap normally. + female + %1 define que %2 desvira normalmente. + + + + %1 sets %2 to untap normally. + male + %1 define que %2 desvira normalmente. + + + + %1 sets PT of %2 to %3. + female + %1 altera o P/R de %2 para %3. + + + + %1 sets PT of %2 to %3. + male + %1 altera o P/R de %2 para %3. + + + + %1 sets annotation of %2 to %3. + female + %1 altera a nota de %2 para%3. + + + + %1 sets annotation of %2 to %3. + male + %1 altera a nota de %2 para%3. + + + + %1 is looking at the top %2 cards %3. + female + %1 está olhando para os %2 cards do topo %3. + + + + %1 is looking at the top %2 cards %3. + male + %1 está olhando para os %2 cards do topo %3. + + + + %1 is looking at %2. + female + %1 está olhando para %2. + + + + %1 is looking at %2. + male + %1 está olhando para %2. + + + + %1 stops looking at %2. + female + %1 para de olhar para %2. + + + + %1 stops looking at %2. + male + %1 para de olhar para %2. + + + + %1 reveals %2 to %3. + p1 female, p2 female + %1 revela %2 para %3. + + + + %1 reveals %2 to %3. + p1 female, p2 male + %1 revela %2 para %3. + + + + %1 reveals %2 to %3. + p1 male, p2 female + %1 revela %2 para %3. + + + + %1 reveals %2 to %3. + p1 male, p2 male + %1 revela %2 para %3. + + + + %1 reveals %2. + female + %1 revela %2. + + + + %1 reveals %2. + male + %1 revela %2. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + %1 revela aleatoriamente %2%3. para %4. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + %1 revela aleatoriamente %2%3. para %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + %1 revela aleatoriamente %2%3. para %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + %1 revela aleatoriamente %2%3. para %4. + + + + %1 randomly reveals %2%3. + female + %1 revela aleatoriamente %2%3. + + + + %1 randomly reveals %2%3. + male + %1 revela aleatoriamente %2%3. + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + %1 revela %2%3 para %4. + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + %1 revela %2%3 para %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + %1 revela %2%3 para %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + %1 revela %2%3 para %4. + + + + %1 reveals %2%3. + female + %1 revela %2%3. + + + + %1 reveals %2%3. + male + %1 revela %2%3. + + + + It is now %1's turn. + female + Agora é o turno de %1. + + + + It is now %1's turn. + male + Agora é o turno de %1. + + + + a card um card - %1 flips %2 face-down. - %1 vira %2 para baixo. + %1 vira %2 para baixo. - %1 flips %2 face-up. - %1 vira %2 para cima. + %1 vira %2 para cima. - %1 attaches %2 to %3's %4. - %1 anexa %2 a %4 de %3. + %1 anexa %2 a %4 de %3. - %1 unattaches %2. - %1 desanexa %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 aponta para %5 de %4 com %3 de %2. %1 places %n counter(s) (%2) on %3 (now %4). @@ -1678,7 +2966,7 @@ A versão local é %1 e a versão remota é %2. - + red vermelho @@ -1686,7 +2974,7 @@ A versão local é %1 e a versão remota é %2. - + yellow amarelo @@ -1694,7 +2982,7 @@ A versão local é %1 e a versão remota é %2. - + green verde @@ -1702,74 +2990,61 @@ A versão local é %1 e a versão remota é %2. - %1 sets counter %2 to %3 (%4%5). - %1 altera o marcador %2 para %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 altera o P/R de %2 para %3. - %1 sets annotation of %2 to %3. - %1 altera a nota de %2 para%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. + %1 está olhando para os %2 cards do topo %3. - + The game has started. O jogo começou. - Connected. - Conectado. + Conectado. - Protocol version mismatch. Client: %1, Server: %2 - Versão dos protocolos incompatível. Versão do utilizador:%1, versão do servidor:%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. + Você entrou no jogo nº %1. - %1 has joined the game. - %1 entrou no jogo. + %1 entrou no jogo. - %1 has left the game. - %1 saiu do jogo. + %1 saiu do jogo. - %1 has loaded a local deck. - %1 carregou um deck local. + %1 carregou um deck local. - %1 has loaded deck #%2. - %1 carregou o deck nº %2. + %1 carregou o deck nº %2. - %1 is ready to start the game. - %1 está pronto para começar o jogo. + %1 está pronto para começar o jogo. - %1 has conceded the game. - %1 concedeu o jogo. + %1 concedeu o jogo. %1 draws a card. @@ -1780,196 +3055,185 @@ A versão local é %1 e a versão remota é %2. %1 compra %2 cards. - %1 destroys %2. - %1 destrói %2. + %1 destrói %2. - %1 creates token: %2%3. - %1 cria a ficha: %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 aponta para %4 com %3 de %2 . - %1 places %n %2 counter(s) on %3 (now %4). - + %1 põe %n marcador %2 em %3 (agora %4). %1 põe %n marcadores %2 em %3 (agora %4). - %1 removes %n %2 counter(s) from %3 (now %4). - + %1 tira %n marcador %2 em %3 (agora %4). %1 tira %n marcadores %2 em %3 (agora %4). - %1 %2 %3. - %1 %2 %3. + %1 %2 %3. - %1 is looking at %2. - %1 está olhando para %2. + %1 está olhando para %2. - %1 stops looking at %2. - %1 para de olhar para %2. + %1 para de olhar para %2. - %1 reveals %2 to %3. - %1 revela %2 para %3. + %1 revela %2 para %3. - %1 reveals %2. - %1 revela %2. + %1 revela %2. - + ending phase fase final - It is now %1's turn. - Agora é o turno de %1. + Agora é o turno de %1. - %1 shuffles his library. - %1 embaralha o seu grimório. + %1 embaralha o seu grimório. + + + + %1 draws his initial hand. + + + + + %1 draws her initial hand. + - %1 randomly reveals %2%3 to %4. - %1 revela aleatoriamente %2%3. para %4. + %1 revela aleatoriamente %2%3. para %4. - %1 randomly reveals %2%3. - %1 revela aleatoriamente %2%3. + %1 revela aleatoriamente %2%3. - %1 reveals %2%3 to %4. - %1 revela %2%3 para %4. + %1 revela %2%3 para %4. - %1 reveals %2%3. - %1 revela %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 + vira - untaps - desvira + desvira - %1 sets %2 to not untap normally. - %1 define que %2 não desvira normalmente. + %1 define que %2 não desvira normalmente. - %1 sets %2 to untap normally. - %1 define que %2 desvira normalmente. + %1 define que %2 desvira normalmente. - his permanents - as suas permanentes + as suas permanentes MessagesSettingsPage - + &Add &Adicionar - + &Remove &Remover - + Add message Adicionar mensagem - + Message: Mensagem: @@ -2035,322 +3299,322 @@ A versão local é %1 e a versão remota é %2. 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 - + &Undo last draw Desfa&zer última compra - + Move top cards to &exile... Mover os cards do topo para o e&xílio... - + Put top card on &bottom Colocar o card do topo no &fundo - + &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 - + Ctrl+F3 Ctrl+F3 - + Ctrl+Shift+D Ctrl+Shift+D - + 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 @@ -2436,17 +3700,17 @@ A versão local é %1 e a versão remota é %2. Sideboard - + Cockatrice decks (*.cod) Decks Cockatrice (*.cod) - + Plain text decks (*.dec *.mwDeck) Decks de texto simples (*.dec *.mwDeck) - + All files (*.*) Todos os arquivos (*.*) @@ -2522,40 +3786,73 @@ A versão local é %1 e a versão remota é %2. Nome longo + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + &OK + + + + &Cancel + &Cancelar + + + + Shut down server + + + TabAdmin - + Update server &message &Atualizar mensagem do servidor - + + &Shut down server + + + + Server administration functions Funções do administrador do servidor - + &Unlock functions &Desbloquear funções - + &Lock functions &Bloquear funções - + Unlock administration functions Desbloquear funções do administrador - + Do you really want to unlock the administration functions? Você quer mesmo desbloquear as funções do administrador? - + Administration Administração @@ -2650,127 +3947,132 @@ Por favor, entre um nome: TabGame - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + &Phases &Etapas - + &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 - + + Ctrl+Q + Ctrl+Q + + + &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? - + Kicked Chutado - + You have been kicked out of the game. Você foi chutado do jogo. @@ -2783,32 +4085,32 @@ Por favor, entre um nome: TabMessage - + Personal &talk Chat &privado - + &Leave &Sair - + This user is ignoring you. Este usuário está ignorando você. - + %1 has left the server. %1 saiu do servidor. - + %1 has joined the server. %1 entrou no servidor. - + Talking to %1 Falando com %1 @@ -2816,27 +4118,27 @@ Por favor, entre um nome: TabRoom - + &Say: &Falar: - + Chat Chat - + &Room &Sala - + &Leave room S&air da sala - + You are flooding the chat. Please wait a couple of seconds. Você está flodando o chat. Por favor, espere alguns segundos. @@ -2868,42 +4170,51 @@ Por favor, entre um nome: UserInfoBox - + User information Informação do usuário - + Real name: Nome real: - + + Gender: + + + + Location: Localização: - + User level: Nível do usuário: - + Administrator Administrador - - Judge - Juiz + + Moderator + - + Judge + Juiz + + + Registered user Usuário registrado - + Unregistered user Usuário não registrado @@ -2911,279 +4222,312 @@ Por favor, entre um nome: 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 + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + Escolher caminho + UserList - + Users online: %1 Usuários online: %1 - + Users in this room: %1 Usuários nesta sala: %1 - + Buddies online: %1 / %2 Amigos online: %1 / %2 - + Ignored users online: %1 / %2 Usuários ignorados online: %1 / %2 - + + %1's games + + + + User &details &Detalhes do usuário - + Direct &chat &Chat direto - + + Show this user's &games + + + + Add to &buddy list Adicionar à &lista de amigos - + Remove from &buddy list Remover da li&sta de amigos - + Add to &ignore list Adicionar à li&sta dos ignorados - + Remove from &ignore list Remover da lista dos i&gnorados - + Ban from &server Ban&ir do servidor - Duration - Duração + Duração - Please enter the duration of the ban (in minutes). Enter 0 for an indefinite ban. - Por favor, digite a duração do banimento (em minutos). + Por favor, digite a duração do banimento (em minutos). Digite 0 para banir indefinidamente. 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 - + + &Update prices + + + + + Ctrl+U + Ctrl+U + + + 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. O deck não pôde ser salvo. Por favor, verifique se o diretório não é somente leitura e tente novamente. - + 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. diff --git a/cockatrice/translations/cockatrice_pt.ts b/cockatrice/translations/cockatrice_pt.ts index e9d026b0c..db115aa25 100644 --- a/cockatrice/translations/cockatrice_pt.ts +++ b/cockatrice/translations/cockatrice_pt.ts @@ -37,57 +37,57 @@ AppearanceSettingsPage - + Zone background pictures Zona das imagens de fundo - + Path to hand background: 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: - + Card rendering Rendering da carta - + Display card names on cards having a picture Mostrar o nome em cartas com imagem - + 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 @@ -96,35 +96,71 @@ Esquema económico - + Invert vertical coordinate Inverter coordenada vertical - + + Minimum player count for multi-column layout: + + + + 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 + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Por favor introduza a duração do banimento (em minutos). +Introduza 0 para um banimento indefinido. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + + + + + &Cancel + &Cancelar + + + + Ban user from server + + + CardDatabaseModel @@ -156,22 +192,42 @@ CardInfoWidget - + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + Name: Nome: - + Mana cost: Custo de Mana: - + Card type: Tipo de carta: - + P / T: P / R: @@ -179,57 +235,57 @@ CardItem - + &Play &Jogar - + &Hide Esco&nder - + &Tap &Virar - + &Untap Desv&irar - + Toggle &normal untapping A&lterar desvirar normalmente - + &Flip Vol&tar - + &Clone Copi&ar - + Ctrl+H Ctrl+H - + &Attach to card... Ane&xar a carta... - + Ctrl+A Ctrl+A - + Unattac&h De&sanexar @@ -238,142 +294,147 @@ Definir &P/R... - + + &Draw arrow... + + + + &Power / toughness &Poder / resistência - + &Increase power &Aumentar poder - + Ctrl++ Ctrl++ - + &Decrease power &Diminuir poder - + Ctrl+- Ctrl+- - + I&ncrease toughness A&umentar resistência - + Alt++ Alt++ - + D&ecrease toughness Di&minuir resistência - + Alt+- Alt+- - + In&crease power and toughness Aumen&tar poder e resistência - + Ctrl+Alt++ Ctrl+Alt++ - + Dec&rease power and toughness Dimin&uir poder e resistência - + Ctrl+Alt+- Ctrl+Alt+- - + Set &power and toughness... Definir &poder e resistência... - + Ctrl+P Ctrl+P - + &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 @@ -381,184 +442,514 @@ CardZone - his hand nominative - sua mão + sua mão - %1's hand nominative - mão de %1 + mão de %1 - of his hand genitive - da sua mão + 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 - of %1's hand - genitive - da mão de %1 + her hand + nominative, female owner + - - his hand - accusative - sua mão - - - + %1's hand - accusative - mão de %1 + nominative, female owner + mão de %1 - - his library - nominative - seu grimório + + his hand + nominative, male owner + sua mão - + + %1's hand + nominative, male owner + mão de %1 + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + da mão de %1 + + + + of his hand + genitive, male owner + da sua mão + + + + of %1's hand + genitive, male owner + da mão de %1 + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + mão de %1 + + + + his hand + accusative, male owner + sua mão + + + + %1's hand + accusative, male owner + mão de %1 + + + + her library + nominative, female owner + + + + %1's library - nominative - grimório de %1 + nominative, female owner + grimório de %1 - of his library - genitive - do seu grimório + his library + nominative, male owner + seu grimório + %1's library + nominative, male owner + grimório de %1 + + + + of her library + genitive, female owner + + + + of %1's library - genitive - do grimório de %1 + genitive, female owner + do grimório de %1 - his library - accusative - seu grimório + of his library + genitive, male owner + do seu grimório + of %1's library + genitive, male owner + do grimório de %1 + + + + her library + accusative, female owner + + + + %1's library - accusative - grimório de %1 + accusative, female owner + grimório de %1 - - his graveyard - nominative - seu cemitério + + his library + accusative, male owner + seu grimório - - %1's graveyard - nominative - cemitério de %1 + + %1's library + accusative, male owner + grimório de %1 + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + + + + + his graveyard + nominative, male owner + seu cemitério + + + + %1's graveyard + nominative, male owner + + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + do cemitério de %1 + + + + of his graveyard + genitive, male owner + do seu cemitério + + + + of %1's graveyard + genitive, male owner + do cemitério de %1 + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + + + + + his graveyard + accusative, male owner + seu cemitério + + + + %1's graveyard + accusative, male owner + + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + exílio de %1 + + + + his exile + nominative, male owner + seu exílio + + + + %1's exile + nominative, male owner + exílio de %1 + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + do exílio de %1 + + + + of his exile + genitive, male owner + do seu exílio + + + + of %1's exile + genitive, male owner + do exílio de %1 + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + exílio de %1 + + + + his exile + accusative, male owner + seu exílio + + + + %1's exile + accusative, male owner + exílio de %1 + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + sideboard de %1 + + + + his sideboard + nominative, male owner + seu sideboard + + + + %1's sideboard + nominative, male owner + sideboard de %1 + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + do sideboard de %1 + + + + of his sideboard + genitive, male owner + do seu sideboard + + + + of %1's sideboard + genitive, male owner + do sideboard de %1 + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + sideboard de %1 + + + + his sideboard + accusative, male owner + seu sideboard + + + + %1's sideboard + accusative, male owner + sideboard de %1 + + + his graveyard + nominative + seu cemitério + + + %1's graveyard + nominative + cemitério de %1 + + of his graveyard genitive - do seu cemitério + do seu cemitério - of %1's graveyard genitive - do cemitério de %1 + do cemitério de %1 - his graveyard accusative - seu cemitério + seu cemitério - %1's graveyard accusative - cemitéro de %1 + cemitéro de %1 - his exile nominative - seu exílio + seu exílio - %1's exile nominative - exílio de %1 + exílio de %1 - of his exile genitive - do seu exílio + do seu exílio - of %1's exile genitive - do exílio de %1 + do exílio de %1 - his exile accusative - seu exílio + seu exílio - %1's exile accusative - exílio de %1 + exílio de %1 - his sideboard nominative - seu sideboard + seu sideboard - %1's sideboard nominative - sideboard de %1 + sideboard de %1 - of his sideboard genitive - do seu sideboard + do seu sideboard - of %1's sideboard genitive - do sideboard de %1 + do sideboard de %1 - his sideboard accusative - seu sideboard + seu sideboard - %1's sideboard accusative - sideboard de %1 + sideboard de %1 @@ -611,38 +1002,56 @@ Novo valor para o marcador '%1': + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + Geral + + DeckListModel - + Number Número - + Card Carta + + + Price + + DeckViewContainer - + Load &local deck Carregar deck l&ocal - + Load d&eck from server Carregar deck do &servidor - + Ready to s&tart &Pronto para começar - + Load deck Carregar deck @@ -738,82 +1147,82 @@ &Descrição: - + &Password: &Password: - + P&layers: &Jogadores: - + Game type Tipo de jogo - + Only &buddies can join Apenas &amigos podem entrar - + Only &registered users can join Apenas utilizadores &registados podem entrar - + Joining restrictions Restrições para ligar - + &Spectators allowed &Espectadores permitidos - + Spectators &need a password to join Espectadores &necessitam de password para aceder - + Spectators can &chat Espectadores podem c&onversar - + Spectators see &everything Espectadores podem ver &tudo - + Spectators Espectadores - + &OK O&K - + &Cancel &Cancelar - + Create game Criar jogo - + Error Erro - + Server error. Erro do servidor. @@ -955,54 +1364,59 @@ 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 - + + Deck editor + + + + Messages Mensagens - + &Close &Fechar @@ -1010,87 +1424,98 @@ GameSelector - - - - - - - + + + + + + + + Error Erro - + + Please join the appropriate room first. + + + + 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. - + This game is only open to registered users. Este jogo só está aberto a utilizadores registados. - + This game is only open to its creator's buddies. Este jogo só está aberto aos amigos do seu criador. - + You are being ignored by the creator of this game. Você está a ser ignorado pelo criador deste jogo. - + Join game Entrar no jogo - + Password: Password: - + Games Jogos - + Show &full games &Mostrar jogos cheios + + + Show &running games + + &Show full games &Mostrar jogos cheios - + C&reate &Criar - + &Join &Entrar - + J&oin as spectator Entrar como &espectador @@ -1106,67 +1531,72 @@ GamesModel - + yes sim - + yes, free for spectators sim, livre para espectadores - + no não - + buddies only amigos apenas - + reg. users only utilizadores registados apenas - + not allowed não permitidos - + + Room + Sala + + + Description Descrição - + Creator Criador - + Game type Tipo de jogo - + Password Password - + Restrictions Restrições - + Players Jogadores - + Spectators Espectadores @@ -1174,50 +1604,50 @@ GeneralSettingsPage - - + + English Português - - - + + + Choose path Escolher directório - + Personal settings Defenições pessoais - + Language: Língua: - + Download card pictures on the fly Baixar a imagem das cartas ao passar - + Paths Directórios - + Decks directory: Directório dos decks: - + Pictures directory: Directório das imagens: - + Path to card database: Directório da base de dados de cartas: @@ -1225,23 +1655,23 @@ 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 @@ -1250,22 +1680,22 @@ <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: @@ -1274,52 +1704,52 @@ Português: - + Portugese (Portugal): Português (Portugal): - + Portugese (Brazil): Português (Brasil): - + French: Francês: - + Japanese: Japonês: - + Russian: Russo: - - - - - - + + + + + + Error Erro - + Server timeout Tempo do servidor esgotado - + Invalid login data. Informação de login incorrecta. - + Socket error: %1 Erro de ligação:%1 @@ -1339,119 +1769,149 @@ + Scheduled server shutdown. + + + + Unknown reason. Razão desconhecida. - + Connection closed Ligação terminada - + The server has terminated your connection. Reason: %1 O servidor terminou a sua ligação. Motivo: %1 - + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + + Czech: + + + + + Slovak: + + + + There is already an active session using this user name. Please close that session first and re-login. Já existe uma sessão activa com este nome de utilizador. Por favor termine essa sessão e volte a ligar-se. - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. Está a tentar ligar-se a um servidor obsoleto. Por favor faça downgrade à sua versão do Cockatrice ou ligue-se a servidor adequado. Versão local é %1, versão remota é %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. A sua versão do Cockatrice é obsoleta. Por favor actualize-a. 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? @@ -1459,104 +1919,88 @@ Versão local é %1, versão remota é %2. MessageLogWidget - Connecting to %1... - Ligando a %1... + Ligando a %1... - Connected. - Ligado. + Ligado. - Disconnected from server. - Desligado do servidor. + Desligado do servidor. - Invalid password. - Password incorrecto. + Password incorrecto. + + + Protocol version mismatch. Client: %1, Server: %2 + Versão dos protocolos incompatível. Versão do utilizador:%1, versão do servidor:%2 + + + Protocol error. + Erro de protocolo. + + + You have joined game #%1. + Você entrou no jogo #%1. + + + %1 has joined the game. + %1 entrou no jogo. + + + %1 has left the game. + %1 abandonou o jogo. - Protocol version mismatch. Client: %1, Server: %2 - Versão dos protocolos incompatível. Versão do utilizador:%1, versão do servidor:%2 - - - - Protocol error. - Erro de protocolo. - - - - You have joined game #%1. - Você entrou no jogo #%1. - - - - %1 has joined the game. - %1 entrou no jogo. - - - - %1 has left the game. - %1 abandonou o jogo. - - - The game has been closed. Este jogo foi encerrado. - + %1 is now watching the game. %1 está agora a ver o jogo. - + %1 is not watching the game any more. %1 já não está a ver o jogo. - %1 has loaded a local deck. - %1 carregou um deck local. + %1 carregou um deck local. - %1 has loaded deck #%2. - %1 carregou o deck #%2. + %1 carregou o deck #%2. - %1 is ready to start the game. - %1 está pronto a começar o jogo. + %1 está pronto a começar o jogo. - %1 is not ready to start the game any more. - %1 já não está pronto a começar o jogo. + %1 já não está pronto a começar o jogo. - %1 has conceded the game. - %1 concedeu o jogo. + %1 concedeu o jogo. - + The game has started. O jogo começou. - %1 shuffles his library. - %1 baralha o grimório. + %1 baralha o grimório. - %1 rolls a %2 with a %3-sided die. - %1 obteve %2 com um dado de %3 faces. + %1 obteve %2 com um dado de %3 faces. %1 draws a card. @@ -1567,199 +2011,1038 @@ Versão local é %1, versão remota é %2. %1 compra %2 cartas. - - from table - vindo da mesa + + You have joined game #%1. + female + Você entrou no jogo #%1. + + You have joined game #%1. + male + Você entrou no jogo #%1. + + + + %1 has joined the game. + female + %1 entrou no jogo. + + + + %1 has joined the game. + male + %1 entrou no jogo. + + + + %1 has left the game. + female + %1 abandonou o jogo. + + + + %1 has left the game. + male + %1 abandonou o jogo. + + + + %1 has loaded a local deck. + female + %1 carregou um deck local. + + + + %1 has loaded a local deck. + male + %1 carregou um deck local. + + + + %1 has loaded deck #%2. + female + %1 carregou o deck #%2. + + + + %1 has loaded deck #%2. + male + %1 carregou o deck #%2. + + + + %1 is ready to start the game. + female + %1 está pronto a começar o jogo. + + + + %1 is ready to start the game. + male + %1 está pronto a começar o jogo. + + + + %1 is not ready to start the game any more. + female + %1 já não está pronto a começar o jogo. + + + + %1 is not ready to start the game any more. + male + %1 já não está pronto a começar o jogo. + + + + %1 has conceded the game. + female + %1 concedeu o jogo. + + + + %1 has conceded the game. + male + %1 concedeu o jogo. + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + + %1 rolls a %2 with a %3-sided die. + female + %1 obteve %2 com um dado de %3 faces. + + + + %1 rolls a %2 with a %3-sided die. + male + %1 obteve %2 com um dado de %3 faces. + + - from graveyard - vindo do cemitério - - - - from exile - vindo do exílio - - - - from hand - vindo da mão - - - - the bottom card of his library - a carta do fundo do seu grimório - - - - from the bottom of his library - do fundo do seu grimório - - - - the top card of his library - a carta do topo do seu grimório - - - - from the top of his library - do topo do seu grimório - - - - from library - do grimório - - - - from sideboard - do sideboard - - - - from the stack - da pilha - - - - %1 puts %2 into play tapped%3. - %1 coloca %2 em jogo virado(a)%3. - - - - %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 fundo 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. - - - - %1 places %n %2 counter(s) on %3 (now %4). - - %1 coloca %n %2 marcador em %3 (agora com %4). - %1 coloca %n %2 marcadores em %3 (agora com %4). - - - - - %1 removes %n %2 counter(s) from %3 (now %4). - - %1 remove %n %2 marcador de %3 (agora com %4). - %1 remove %n %2 marcadores de %3 (agora com %4). - - - - - - a card - uma carta - - - %1 draws %n card(s). - + female + + %1 compra %n carta. + %1 compra %n cartas. + + + + + %1 draws %n card(s). + male + %1 compra %n carta. %1 compra %n cartas. - + + from table + vindo da mesa + + + + from graveyard + vindo do cemitério + + + + from exile + vindo do exílio + + + + from hand + vindo da mão + + + + the bottom card of his library + a carta do fundo do seu grimório + + + + the bottom card of her library + + + + + from the bottom of his library + do fundo do seu grimório + + + + from the bottom of her library + + + + + the top card of his library + a carta do topo do seu grimório + + + + the top card of her library + + + + + from the top of his library + do topo do seu grimório + + + + from the top of her library + + + + + from library + do grimório + + + + from sideboard + do sideboard + + + + from the stack + da pilha + + + + %1 puts %2 into play tapped%3. + %1 coloca %2 em jogo virado(a)%3. + + + + %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 into her library. + + + + + %1 puts %2%3 on bottom of his library. + %1 coloca %2%3 no fundo do seu grimório. + + + + %1 puts %2%3 on bottom of her library. + + + + + %1 puts %2%3 on top of his library. + %1 coloca %2%3 no topo do seu grimório. + + + + %1 puts %2%3 on top of her library. + + + + + %1 puts %2%3 into his library at position %4. + %1 coloca %2%3 no seu grimório na posição %4. + + + + %1 puts %2%3 into her library at position %4. + + + + + %1 moves %2%3 to sideboard. + %1 move %2%3 para o sideboard. + + + + %1 plays %2%3. + %1 joga %2%3. + + + + %1 takes a mulligan to %n. + female + + + + + + + + %1 takes a mulligan to %n. + male + + + + + + + + %1 flips %2 face-down. + female + %1 volta a face de %2 para baixo. + + + + %1 flips %2 face-down. + male + %1 volta a face de %2 para baixo. + + + + %1 flips %2 face-up. + female + %1 volta a face de %2 para cima. + + + + %1 flips %2 face-up. + male + %1 volta a face de %2 para cima. + + + + %1 destroys %2. + female + %1 destrói %2. + + + + %1 destroys %2. + male + %1 destrói %2. + + + %1 attaches %2 to %3's %4. + female + %1 anexa %2 a %4 de %3. + + + %1 attaches %2 to %3's %4. + male + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + %1 anexa %2 a %4 de %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + %1 anexa %2 a %4 de %3. + + + + %1 unattaches %2. + female + %1 desanexa %2. + + + + %1 unattaches %2. + male + %1 desanexa %2. + + + + %1 creates token: %2%3. + female + %1 cria ficha: %2%3. + + + + %1 creates token: %2%3. + male + %1 cria ficha: %2%3. + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + %1 aponta de %3 de %2 para %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + %1 aponta de %3 de %2 para %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + %1 aponta de %3 de %2 para %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + %1 aponta de %3 de %2 para %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + %1 aponta de %3 de %2 para %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + %1 aponta de %3 de %2 para %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + %1 aponta de %3 de %2 para %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + %1 aponta de %3 de %2 para %4. + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + %1 aponta de %3 de %2 para %5 de %4. + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + %1 coloca %n %2 marcador em %3 (agora com %4). + %1 coloca %n %2 marcadores em %3 (agora com %4). + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 coloca %n %2 marcador em %3 (agora com %4). + %1 coloca %n %2 marcadores em %3 (agora com %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 remove %n %2 marcador de %3 (agora com %4). + %1 remove %n %2 marcadores de %3 (agora com %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + %1 remove %n %2 marcador de %3 (agora com %4). + %1 remove %n %2 marcadores de %3 (agora com %4). + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + %1 altera o número de marcadores %2 para %3(%4%5). + + + + %1 sets counter %2 to %3 (%4%5). + male + %1 altera o número de marcadores %2 para %3(%4%5). + + + + %1 sets %2 to not untap normally. + female + %1 define %2 para não desvirar normalmente. + + + + %1 sets %2 to not untap normally. + male + %1 define %2 para não desvirar normalmente. + + + + %1 sets %2 to untap normally. + female + %1 define %2 para desvirar normalmente. + + + + %1 sets %2 to untap normally. + male + %1 define %2 para desvirar normalmente. + + + + %1 sets PT of %2 to %3. + female + %1 define o P/R de %2 como %3. + + + + %1 sets PT of %2 to %3. + male + %1 define o P/R de %2 como %3. + + + + %1 sets annotation of %2 to %3. + female + %1 coloca uma nota de %2 em%3. + + + + %1 sets annotation of %2 to %3. + male + %1 coloca uma nota de %2 em%3. + + + + %1 is looking at the top %2 cards %3. + female + %1 está a olhar para as %2 cartas do topo %3. + + + + %1 is looking at the top %2 cards %3. + male + %1 está a olhar para as %2 cartas do topo %3. + + + + %1 is looking at %2. + female + %1 está a olhar para %2. + + + + %1 is looking at %2. + male + %1 está a olhar para %2. + + + + %1 stops looking at %2. + female + %1 para de olhar para %2. + + + + %1 stops looking at %2. + male + %1 para de olhar para %2. + + + + %1 reveals %2 to %3. + p1 female, p2 female + %1 revela %2 a %3. + + + + %1 reveals %2 to %3. + p1 female, p2 male + %1 revela %2 a %3. + + + + %1 reveals %2 to %3. + p1 male, p2 female + %1 revela %2 a %3. + + + + %1 reveals %2 to %3. + p1 male, p2 male + %1 revela %2 a %3. + + + + %1 reveals %2. + female + %1 revela %2. + + + + %1 reveals %2. + male + %1 revela %2. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + %1 revela aleatoreamente %2%3. a %4. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + %1 revela aleatoreamente %2%3. a %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + %1 revela aleatoreamente %2%3. a %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + %1 revela aleatoreamente %2%3. a %4. + + + + %1 randomly reveals %2%3. + female + %1 revela aleatoreamente %2%3. + + + + %1 randomly reveals %2%3. + male + %1 revela aleatoreamente %2%3. + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + %1 revela %2%3 a %4. + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + %1 revela %2%3 a %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + %1 revela %2%3 a %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + %1 revela %2%3 a %4. + + + + %1 reveals %2%3. + female + %1 revela %2%3. + + + + %1 reveals %2%3. + male + %1 revela %2%3. + + + + It is now %1's turn. + female + É agora o turno de %1. + + + + It is now %1's turn. + male + É agora o turno de %1. + + + + %1 draws his initial hand. + + + + + %1 draws her initial hand. + + + + %1 places %n %2 counter(s) on %3 (now %4). + + %1 coloca %n %2 marcador em %3 (agora com %4). + %1 coloca %n %2 marcadores em %3 (agora com %4). + + + + %1 removes %n %2 counter(s) from %3 (now %4). + + %1 remove %n %2 marcador de %3 (agora com %4). + %1 remove %n %2 marcadores de %3 (agora com %4). + + + + + + a card + uma carta + + + %1 draws %n card(s). + + %1 compra %n carta. + %1 compra %n cartas. + + + + %1 undoes his last draw. %1 desfaz a sua última compra. - + + %1 undoes her last draw. + + + + %1 undoes his last draw (%2). %1 desfaz a sua última compra (%2). - + + %1 undoes her last draw (%2). + + + + %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 volta a face de %2 para baixo. - %1 flips %2 face-up. - %1 volta a face de %2 para cima. + %1 volta a face de %2 para cima. - %1 destroys %2. - %1 destrói %2. + %1 destrói %2. - %1 attaches %2 to %3's %4. - %1 anexa %2 a %4 de %3. + %1 anexa %2 a %4 de %3. - %1 unattaches %2. - %1 desanexa %2. + %1 desanexa %2. - %1 creates token: %2%3. - %1 cria ficha: %2%3. + %1 cria ficha: %2%3. - %1 points from %2's %3 to %4. - %1 aponta de %3 de %2 para %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 aponta de %3 de %2 para %5 de %4. %1 places %n counter(s) (%2) on %3 (now %4). @@ -1776,7 +3059,7 @@ Versão local é %1, versão remota é %2. - + red vermelho @@ -1784,7 +3067,7 @@ Versão local é %1, versão remota é %2. - + yellow amarelo @@ -1792,7 +3075,7 @@ Versão local é %1, versão remota é %2. - + green verde @@ -1800,157 +3083,138 @@ Versão local é %1, versão remota é %2. - his permanents - as suas permanentes + as suas permanentes - %1 %2 %3. - %1 %2 %3. + %1 %2 %3. - taps - vira + vira - untaps - desvira + desvira - %1 sets counter %2 to %3 (%4%5). - %1 altera o número de marcadores %2 para %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 define %2 para não desvirar normalmente. - %1 sets %2 to untap normally. - %1 define %2 para desvirar normalmente. + %1 define %2 para desvirar normalmente. - %1 sets PT of %2 to %3. - %1 define o P/R de %2 como %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 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 está a olhar para as %2 cartas do topo %3. - %1 is looking at %2. - %1 está a olhar para %2. + %1 está a olhar para %2. - %1 stops looking at %2. - %1 para de olhar para %2. + %1 para de olhar para %2. - %1 reveals %2 to %3. - %1 revela %2 a %3. + %1 revela %2 a %3. - %1 reveals %2. - %1 revela %2. + %1 revela %2. - %1 randomly reveals %2%3 to %4. - %1 revela aleatoreamente %2%3. a %4. + %1 revela aleatoreamente %2%3. a %4. - %1 randomly reveals %2%3. - %1 revela aleatoreamente %2%3. + %1 revela aleatoreamente %2%3. - %1 reveals %2%3 to %4. - %1 revela %2%3 a %4. + %1 revela %2%3 a %4. - %1 reveals %2%3. - %1 revela %2%3. + %1 revela %2%3. - It is now %1's turn. - É agora o turno de %1. + É 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. @@ -1958,22 +3222,22 @@ Versão local é %1, versão remota é %2. MessagesSettingsPage - + Add message Adicionar mensagem - + Message: Mensagem: - + &Add &Adicionar - + &Remove &Remover @@ -2039,322 +3303,322 @@ Versão local é %1, versão remota é %2. 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... - + &Undo last draw Desfa&zer a última compra - + 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 - + Ctrl+F3 Ctrl+F3 - + F3 F3 - + Ctrl+W Ctrl+W - + F4 F4 - + Ctrl+D Ctrl+D - + Ctrl+E Ctrl+E - + Ctrl+Shift+D Ctrl+Shift+D - + 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 @@ -2440,17 +3704,17 @@ Versão local é %1, versão remota é %2. 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 (*.*) @@ -2526,40 +3790,73 @@ Versão local é %1, versão remota é %2. Nome longo + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + + + + + &Cancel + &Cancelar + + + + Shut down server + + + TabAdmin - + Update server &message &Actualizar mensagem do servidor - + + &Shut down server + + + + Server administration functions Funções do administrador do servidor - + &Unlock functions &Desbloquear funções - + &Lock functions &Bloquear funções - + Unlock administration functions Desbloquear funções de administração - + Do you really want to unlock the administration functions? Quer mesmo desbloquear as funçõesde administração? - + Administration Administração @@ -2654,127 +3951,132 @@ Por favor introduza um nome: TabGame - + F5 F5 - + F6 F6 - + F7 F7 - + F8 F8 - + F9 F9 - + F10 F10 - + &Phases Fa&ses - + &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 - + + Ctrl+Q + Ctrl+Q + + + &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? - + Kicked Expulso - + You have been kicked out of the game. Você foi expulso do jogo. @@ -2787,32 +4089,32 @@ Por favor introduza um nome: TabMessage - + Personal &talk Conversação &privada - + &Leave &Abandonar - + This user is ignoring you. Este utilizador esta a ignorar-te. - + %1 has left the server. %1 abandonou o servidor. - + %1 has joined the server. %1 entrou no servidor. - + Talking to %1 Falar para %1 @@ -2820,27 +4122,27 @@ Por favor introduza um nome: TabRoom - + &Say: &Dizer: - + Chat - + &Room &Sala - + &Leave room &Abandonar a sala - + You are flooding the chat. Please wait a couple of seconds. Estás a inundar o chat .Por favor aguarde alguns segundos. @@ -2872,42 +4174,51 @@ Por favor introduza um nome: UserInfoBox - + User information Informação do utilizador - + Real name: Nome real: - + + Gender: + + + + Location: Localização: - + User level: Nível de utilizador: - + Administrator Administrador - - Judge - Juiz + + Moderator + - + Judge + Juiz + + + Registered user Utilizador registado - + Unregistered user Utilizador não registado @@ -2915,281 +4226,314 @@ Por favor introduza um nome: 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 + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + Escolher directório + UserList - + Users online: %1 Utilizadores online: %1 - + Users in this room: %1 Utilizadores nesta sala:%1 - + Buddies online: %1 / %2 Amigos online: %1 / %2 - + Ignored users online: %1 / %2 Utilizadores ignorados online %1 / %2 - + + %1's games + + + + User &details Detalhes do &utilizador - + Direct &chat Conversação &directa - + + Show this user's &games + + + + Add to &buddy list Adicionar a lista de &amigos - + Remove from &buddy list Remover da lista de &amigos - + Add to &ignore list Adicionar a lista a &ignorar - + Remove from &ignore list Remover da lista a &ignorar - + Ban from &server Banir do &servidor - Duration - Duração + Duração - Please enter the duration of the ban (in minutes). Enter 0 for an indefinite ban. - Por favor introduza a duração do banimento (em minutos). + Por favor introduza a duração do banimento (em minutos). Introduza 0 para um banimento indefinido. WndDeckEditor - + &Search... &Procurar... - + &Clear search &Limpar pesquisa - + &Search for: &Procurar por: - + Deck &name: &Nome do deck: - + &Comments: &Comentários: - + + &Update prices + + + + + Ctrl+U + Ctrl+U + + + Deck editor [*] Editor de decks [*] - + &New deck &Novo deck - + &Load deck... &Carregar deck... - + &Save deck &Guardar deck - + Save deck &as... G&uardar deck como... - + Load deck from cl&ipboard... Carregar dec&k da memória... - + Save deck to clip&board Guardar deck na &memória - + &Print deck... &Imprimir deck... - + &Close &Fechar - + Ctrl+Q Ctrl+Q - + &Edit sets... &Editar expansões... - + &Deck &Deck - + &Card database &Base de dados das cartas - + Add card to &maindeck Adicionar carta ao &maindeck - + Return Return - + Enter Enter - + Add card to &sideboard Adicionar carta ao &sideboard - + Ctrl+Return Ctrl+Return - + Ctrl+Enter Ctrl+Enter - + &Remove row &Remover linha - + Del Del - + &Increment number &Aumentar o número - + + + - + &Decrement number &Diminuir o número - + - - - + Are you sure? Tem a certeza? - + The decklist has been modified. Do you want to save the changes? A lista foi modificada. Gostaria de guardar as alterações? - + Load deck 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/cockatrice/translations/cockatrice_ru.ts b/cockatrice/translations/cockatrice_ru.ts index 288d096d7..a32a425d0 100644 --- a/cockatrice/translations/cockatrice_ru.ts +++ b/cockatrice/translations/cockatrice_ru.ts @@ -37,90 +37,126 @@ 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: Рубашки карт: - + Card rendering Отрисовка карт - + Display card names on cards having a picture Отображать название карты поверх изображения - + Hand layout Расположение руки - + Display hand horizontally (wastes space) Отбражать руку горизонтально - + Table grid layout Сетка - + Invert vertical coordinate Инвертировать вертикальные координату - + + Minimum player count for multi-column layout: + + + + Zone view layout Сортировка карт - + Sort by name Сортировать по имени - + Sort by type Сортировать по типу - - - - - + + + + + Choose path Выберите путь + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + Введите продолжительность бана (в минутах). +Введите 0 чтобы забанить пожизненно. + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + &Ок + + + + &Cancel + &Отмена + + + + Ban user from server + + + CardDatabaseModel @@ -152,22 +188,42 @@ CardInfoWidget - + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + Name: Название: - + Mana cost: Манакост: - + Card type: Тип: - + P / T: Сила/Защита: @@ -175,57 +231,57 @@ CardItem - + &Play &Разыграть - + &Hide &Cкрыть - + &Tap &Повернуть - + &Untap &Развернуть - + Toggle &normal untapping (Не) &Разворачивать как обычно - + &Flip &Рубашкой вверх (вниз) - + &Clone &Клонировать - + Ctrl+H Ctrl+H - + &Attach to card... &Прикрепить к... - + Ctrl+A - + Unattac&h &Открепить @@ -234,142 +290,147 @@ Установить &Силу/Защиту... - + + &Draw arrow... + + + + &Power / toughness &Сила / защита - + &Increase power &Увеличить силу - + Ctrl++ - + &Decrease power У&меньшить силу - + Ctrl+- - + I&ncrease toughness У&величить защиту - + Alt++ - + D&ecrease toughness Уменьшить &защиту - + Alt+- - + In&crease power and toughness Увеличить силу &и защиту - + Ctrl+Alt++ - + Dec&rease power and toughness Уменьшить силу и за&щиту - + Ctrl+Alt+- - + Set &power and toughness... Уст&ановить силу / защиту... - + Ctrl+P - + &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 &Переместить... @@ -377,218 +438,566 @@ CardZone - his hand nominative - его рука + его рука - %1's hand nominative - рука %1-го игрока + рука %1-го игрока - of his hand genitive - его руки + его руки + + + of %1's hand + genitive + руки %1-го игрока + + + his hand + accusative + его руку + + + %1's hand + accusative + руку %1-го игрока + + + his library + nominative + его библиотека + + + %1's library + nominative + библиотека %1-го игрока + + + of his library + genitive + его библиотеки + + + of %1's library + genitive + библиотеки %1-го игрока + + + his library + accusative + его библиотеку + + + %1's library + accusative + библиотеку %1-го игрока - of %1's hand - genitive - руки %1-го игрока + her hand + nominative, female owner + - - his hand - accusative - его руку - - - + %1's hand - accusative - руку %1-го игрока + nominative, female owner + - - his library - nominative - его библиотека + + his hand + nominative, male owner + - + + %1's hand + nominative, male owner + + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + руки %1-го игрока + + + + of his hand + genitive, male owner + его руки + + + + of %1's hand + genitive, male owner + руки %1-го игрока + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + + + + + his hand + accusative, male owner + + + + + %1's hand + accusative, male owner + + + + + her library + nominative, female owner + + + + %1's library - nominative - библиотека %1-го игрока + nominative, female owner + - of his library - genitive - его библиотеки + his library + nominative, male owner + + %1's library + nominative, male owner + + + + + of her library + genitive, female owner + + + + of %1's library - genitive - библиотеки %1-го игрока + genitive, female owner + библиотеки %1-го игрока - his library - accusative - его библиотеку + of his library + genitive, male owner + его библиотеки + of %1's library + genitive, male owner + библиотеки %1-го игрока + + + + her library + accusative, female owner + + + + %1's library - accusative - библиотеку %1-го игрока + accusative, female owner + - - his graveyard - nominative - его кладбище + + his library + accusative, male owner + - - %1's graveyard - nominative - кладбище %1-го игрока + + %1's library + accusative, male owner + + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + кладбище %1-го игрока + + + + his graveyard + nominative, male owner + его кладбище + + + + %1's graveyard + nominative, male owner + кладбище %1-го игрока + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + кладбища %1-го игрока + + + + of his graveyard + genitive, male owner + его кладбища + + + + of %1's graveyard + genitive, male owner + кладбища %1-го игрока + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + кладбище %1-го игрока + + + + his graveyard + accusative, male owner + его кладбище + + + + %1's graveyard + accusative, male owner + кладбище %1-го игрока + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + изгнание %1-го игрока + + + + his exile + nominative, male owner + его изгнание + + + + %1's exile + nominative, male owner + изгнание %1-го игрока + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + изгнания %1-го игрока + + + + of his exile + genitive, male owner + его изгнания + + + + of %1's exile + genitive, male owner + изгнания %1-го игрока + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + изгнание %1-го игрока + + + + his exile + accusative, male owner + его изгнание + + + + %1's exile + accusative, male owner + изгнание %1-го игрока + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + сайд %1-го игрока + + + + his sideboard + nominative, male owner + его сайд + + + + %1's sideboard + nominative, male owner + сайд %1-го игрока + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + сайда %1-го игрока + + + + of his sideboard + genitive, male owner + его сайда + + + + of %1's sideboard + genitive, male owner + сайда %1-го игрока + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + сайд %1-го игрока + + + + his sideboard + accusative, male owner + его сайд + + + + %1's sideboard + accusative, male owner + сайд %1-го игрока + + + his graveyard + nominative + его кладбище + + + %1's graveyard + nominative + кладбище %1-го игрока + + of his graveyard genitive - его кладбища + его кладбища - of %1's graveyard genitive - кладбища %1-го игрока + кладбища %1-го игрока - his graveyard accusative - его кладбище + его кладбище - %1's graveyard accusative - кладбище %1-го игрока + кладбище %1-го игрока - his exile nominative - его изгнание + его изгнание - %1's exile nominative - изгнание %1-го игрока + изгнание %1-го игрока - of his exile genitive - его изгнания + его изгнания - of %1's exile genitive - изгнания %1-го игрока + изгнания %1-го игрока - his exile accusative - его изгнание + его изгнание - %1's exile accusative - изгнание %1-го игрока + изгнание %1-го игрока - his sideboard nominative - его сайд + его сайд - %1's sideboard nominative - сайд %1-го игрока + сайд %1-го игрока - of his sideboard genitive - его сайда + его сайда - of %1's sideboard genitive - сайда %1-го игрока + сайда %1-го игрока - his sideboard accusative - его сайд + его сайд - %1's sideboard accusative - сайд %1-го игрока + сайд %1-го игрока + + + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + Основные DeckListModel - + Number Номер - + Card Название + + + Price + + DeckViewContainer - + Load &local deck Загрузить &колоду с диска - + Load d&eck from server Загрузить к&олоду с сервера - + Ready to s&tart &Готов - + Load deck Загрузить колоду @@ -677,82 +1086,82 @@ &Подпись: - + &Password: &Пароль: - + P&layers: &Количество игроков: - + Game type Формат игры - + Only &buddies can join Только для &своих - + Only &registered users can join Только для &зарег. пользователей - + Joining restrictions Ограничения - + &Spectators allowed &Разрешить зрителей - + Spectators &need a password to join Требовать &пароль у зрителей - + Spectators can &chat Позволить зрителям &комментировать - + Spectators see &everything Показывать зрителям &все - + Spectators Зрители - + &OK &Ок - + &Cancel &Отмена - + Create game Создать игру - + Error Ошибка - + Server error. Ошибка сервера. @@ -894,54 +1303,59 @@ 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 Интерфейс - + + Deck editor + + + + Messages Сообщения - + &Close &Закрыть @@ -949,83 +1363,94 @@ GameSelector - - - - - - - + + + + + + + + Error Ошибка - + + Please join the appropriate room first. + + + + Wrong password. Неверный пароль. - + Spectators are not allowed in this game. В эту игру не пускают зрителей. - + The game is already full. Все места заняты! =Ь - + The game does not exist any more. Эта игра была удалена. - + This game is only open to registered users. Доступно только для зарегистрированных. - + This game is only open to its creator's buddies. Доступно только для друзей. - + You are being ignored by the creator of this game. Вы добавлены в игнор-лист данного игрока. - + Join game Присоединиться - + Password: Пароль: - + Games Игры - + Show &full games Показывать &текущие - + + Show &running games + + + + C&reate С&оздать - + &Join &Присоединиться - + J&oin as spectator П&рисоединиться как зритель @@ -1041,67 +1466,72 @@ GamesModel - + yes да - + yes, free for spectators да, свободно для зрителей - + no нет - + buddies only только свои - + reg. users only только зарег. - + not allowed Не допускаются - + + Room + Комната + + + Description Подпись - + Creator Создал - + Game type Формат игры - + Password Пароль - + Restrictions Ограничения - + Players Количество игроков - + Spectators Зрители @@ -1109,50 +1539,50 @@ GeneralSettingsPage - - + + English Русский - - - + + + Choose path Путь - + Personal settings Личные настройки - + Language: Язык: - + Download card pictures on the fly Загружать изображения карт на лету - + Paths Расположение - + Decks directory: Колоды: - + Pictures directory: Изображения карт: - + Path to card database: Путь к базе карт: @@ -1171,210 +1601,241 @@ + Scheduled server shutdown. + + + + Unknown reason. Неизвестная причина. - + Connection closed Соединение прервано - + The server has terminated your connection. Reason: %1 Ваше подключение было прервано сервером. Причина: %1 - + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + + Number of players Количество игроков - + Please enter the number of players. Введите количество игроков. - - + + Player %1 Игрок %1 - + About Cockatrice О программе - + Version %1 Версия %1 - + Authors: Разработчики: - + Translators: Переводчики: - + Spanish: Испанский: - + Portugese (Portugal): Португальский: - + Portugese (Brazil): Португальский (Brazil): - + French: Французский: - + Japanese: Японский: - + Russian: Русский: - - - - - - + + Czech: + + + + + Slovak: + + + + + + + + + Error Ошибка - + Server timeout Временная ошибка - + Invalid login data. Неверный логин/пароль. - + There is already an active session using this user name. Please close that session first and re-login. Пользователь с таким именем уже подключен. Пожалуйста, закройте это подключение и войдите заново. - + Socket error: %1 Ошибка сокета: %1 - + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. Local version is %1, remote version is %2. Вы пытаетесь подключиться к несуществующему серверу. Пожалуйста, обновите Cockatrice или выберите другой сервер. Локальная версия %1, удаленная версия %2. - + Your Cockatrice client is obsolete. Please update your Cockatrice version. Local version is %1, remote version is %2. Ваш клиент Cockatrice устарел. Пожалуйста, обновите Cockatrice. Локальная версия %1, удаленная версия %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? Вы подключены к игре. Выйти? @@ -1382,104 +1843,88 @@ Local version is %1, remote version is %2. MessageLogWidget - Connecting to %1... - Подключение к %1... + Подключение к %1... - Connected. - Подключено. + Подключено. - Disconnected from server. - Нет соединения с сервером. + Нет соединения с сервером. - Invalid password. - Неверный пароль. + Неверный пароль. + + + Protocol version mismatch. Client: %1, Server: %2 + Несовпадение версий. Клиент: %1, Сервер: %2 + + + Protocol error. + Ошибка протокола. + + + You have joined game #%1. + Вы присоединились к игре #%1. + + + %1 has joined the game. + %1 присоединился к игре. + + + %1 has left the game. + %1 покиул игру. - Protocol version mismatch. Client: %1, Server: %2 - Несовпадение версий. Клиент: %1, Сервер: %2 - - - - Protocol error. - Ошибка протокола. - - - - You have joined game #%1. - Вы присоединились к игре #%1. - - - - %1 has joined the game. - %1 присоединился к игре. - - - - %1 has left the game. - %1 покиул игру. - - - The game has been closed. Игра закрыта. - + %1 is now watching the game. %1 вошел как зритель. - + %1 is not watching the game any more. %1 покинул зрительскую ложу. - %1 has loaded a local deck. - %1 загрузил колоду с диска. + %1 загрузил колоду с диска. - %1 has loaded deck #%2. - %1 загрузил колоду #%2. + %1 загрузил колоду #%2. - %1 is ready to start the game. - %1 готов начать игру. + %1 готов начать игру. - %1 is not ready to start the game any more. - %1 все еще не готов. + %1 все еще не готов. - %1 has conceded the game. - %1 решил сдаться. + %1 решил сдаться. - + The game has started. Игра началась. - %1 shuffles his library. - %1 размешивает библиотеку. + %1 размешивает библиотеку. - %1 rolls a %2 with a %3-sided die. - %1 выкинул %2 / %3. + %1 выкинул %2 / %3. %1 draws a card. @@ -1490,170 +1935,960 @@ Local version is %1, remote version is %2. %1 взял %2 карт. - + + You have joined game #%1. + female + Вы присоединились к игре #%1. + + + + You have joined game #%1. + male + Вы присоединились к игре #%1. + + + + %1 has joined the game. + female + %1 присоединился к игре. + + + + %1 has joined the game. + male + %1 присоединился к игре. + + + + %1 has left the game. + female + %1 покиул игру. + + + + %1 has left the game. + male + %1 покиул игру. + + + + %1 has loaded a local deck. + female + %1 загрузил колоду с диска. + + + + %1 has loaded a local deck. + male + %1 загрузил колоду с диска. + + + + %1 has loaded deck #%2. + female + %1 загрузил колоду #%2. + + + + %1 has loaded deck #%2. + male + %1 загрузил колоду #%2. + + + + %1 is ready to start the game. + female + %1 готов начать игру. + + + + %1 is ready to start the game. + male + %1 готов начать игру. + + + + %1 is not ready to start the game any more. + female + %1 все еще не готов. + + + + %1 is not ready to start the game any more. + male + %1 все еще не готов. + + + + %1 has conceded the game. + female + %1 решил сдаться. + + + + %1 has conceded the game. + male + %1 решил сдаться. + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + + %1 rolls a %2 with a %3-sided die. + female + %1 выкинул %2 / %3. + + + + %1 rolls a %2 with a %3-sided die. + male + %1 выкинул %2 / %3. + + + + %1 draws %n card(s). + female + + %1 взял %n карту. + %1 взял %n карты. + %1 взял %n карт(ы). + + + + + %1 draws %n card(s). + male + + %1 взял %n карту. + %1 взял %n карты. + %1 взял %n карт(ы). + + + + %1 undoes his last draw. %1 отменил последнее взятие. - + %1 undoes his last draw (%2). %1 отменил %2 последних взятий. - + 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 из стека - - + + a card карту - + %1 gives %2 control over %3. %1 передает %2 контроль над %3. - + %1 puts %2 into play%3. %1 поместил %2 на поле битвы %3. - + %1 puts %2%3 into graveyard. %1 поместил %2%3 на кладбище. - + %1 exiles %2%3. %1 изгоняет %2%3. - + %1 moves %2%3 to hand. %1 поместил %2%3 в руку. - + %1 puts %2%3 into his library. %1 поместил %2%3 в свою библиотеку. - + %1 puts %2%3 on bottom of his library. %1 поместил %2%3 на дно своей библиотеки. - + %1 puts %2%3 on top of his library. %1 поместил %2%3 на верх своей библиотеки. - + %1 puts %2%3 into his library at position %4. %1 поместил %2%3 в свою библиотеку %4 сверху. - + %1 moves %2%3 to sideboard. %1 поместил %2%3 в сайд. - + %1 plays %2%3. %1 разыгрывает %2%3. + + + %1 takes a mulligan to %n. + female + + + + + + + + + %1 takes a mulligan to %n. + male + + + + + + - + %1 flips %2 face-down. - %1 перевернул %2 лицом вниз. + female + %1 перевернул %2 лицом вниз. - + + %1 flips %2 face-down. + male + %1 перевернул %2 лицом вниз. + + + %1 flips %2 face-up. - %1 перевернул %2 лицом вверх. + female + %1 перевернул %2 лицом вверх. - + + %1 flips %2 face-up. + male + %1 перевернул %2 лицом вверх. + + + %1 destroys %2. - %1 уничтожил %2. + female + %1 уничтожил %2. + + + + %1 destroys %2. + male + %1 уничтожил %2. - %1 attaches %2 to %3's %4. - %1 присоединил %2 к %4 игрока %3. + female + %1 присоединил %2 к %4 игрока %3. - + %1 attaches %2 to %3's %4. + male + %1 присоединил %2 к %4 игрока %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + %1 присоединил %2 к %4 игрока %3. + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + %1 присоединил %2 к %4 игрока %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + %1 присоединил %2 к %4 игрока %3. + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + %1 присоединил %2 к %4 игрока %3. + + + %1 unattaches %2. - %1 отсоединил %2. + female + %1 отсоединил %2. - + + %1 unattaches %2. + male + %1 отсоединил %2. + + + %1 creates token: %2%3. - %1 создал фишку: %2%3. + female + %1 создал фишку: %2%3. - + + %1 creates token: %2%3. + male + %1 создал фишку: %2%3. + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + %1 points from %2's %3 to %4. - %1 указывает с %3 контролируемого %2 на %4. + p1 female, p2 female, p3 female + %1 указывает с %3 контролируемого %2 на %4. - + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + %1 указывает с %3 контролируемого %2 на %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + %1 указывает с %3 контролируемого %2 на %4. + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + %1 указывает с %3 контролируемого %2 на %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + %1 указывает с %3 контролируемого %2 на %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + %1 указывает с %3 контролируемого %2 на %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + %1 указывает с %3 контролируемого %2 на %4. + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + %1 указывает с %3 контролируемого %2 на %4. + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + %1 points from %2's %3 to %4's %5. - %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + p1 female, p2 female, p3 female + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + %1 поместил %n %2 жетон на %3 (теперь %4). + %1 поместил %n %2 жетона на %3 (теперь %4). + %1 поместил %n %2 жетонов на %3 (теперь %4). + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + %1 поместил %n %2 жетон на %3 (теперь %4). + %1 поместил %n %2 жетона на %3 (теперь %4). + %1 поместил %n %2 жетонов на %3 (теперь %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + %1 снял %n %2 жетон с %3 (теперь %4). + %1 снял %n %2 жетона с %3 (теперь %4). + %1 снял %n %2 жетонов с %3 (теперь %4). + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + %1 снял %n %2 жетон с %3 (теперь %4). + %1 снял %n %2 жетона с %3 (теперь %4). + %1 снял %n %2 жетонов с %3 (теперь %4). + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + %1 установил жетон %2 на %3 (%4%5). + + + + %1 sets counter %2 to %3 (%4%5). + male + %1 установил жетон %2 на %3 (%4%5). + + + + %1 sets %2 to not untap normally. + female + %2 теперь не разворачивается как обычно (%1). + + + + %1 sets %2 to not untap normally. + male + %2 теперь не разворачивается как обычно (%1). + + + + %1 sets %2 to untap normally. + female + %2 теперь разворачивается как обычно (%1). + + + + %1 sets %2 to untap normally. + male + %2 теперь разворачивается как обычно (%1). + + + + %1 sets PT of %2 to %3. + female + %1 установил Силу/Защиту %2 %3. + + + + %1 sets PT of %2 to %3. + male + %1 установил Силу/Защиту %2 %3. + + + + %1 sets annotation of %2 to %3. + female + %1 сделал пометку на %2 "%3". + + + + %1 sets annotation of %2 to %3. + male + %1 сделал пометку на %2 "%3". + + + + %1 is looking at the top %2 cards %3. + female + %1 смотрит верхние %2 карт библиотеки %3. + + + + %1 is looking at the top %2 cards %3. + male + %1 смотрит верхние %2 карт библиотеки %3. + + + + %1 is looking at %2. + female + %1 просматривает %2. + + + + %1 is looking at %2. + male + %1 просматривает %2. + + + + %1 stops looking at %2. + female + %1 закончил просматривать %2. + + + + %1 stops looking at %2. + male + %1 закончил просматривать %2. + + + + %1 reveals %2 to %3. + p1 female, p2 female + %1 показывает его %2 %3. + + + + %1 reveals %2 to %3. + p1 female, p2 male + %1 показывает его %2 %3. + + + + %1 reveals %2 to %3. + p1 male, p2 female + %1 показывает его %2 %3. + + + + %1 reveals %2 to %3. + p1 male, p2 male + %1 показывает его %2 %3. + + + + %1 reveals %2. + female + %1 открыл его %2. + + + + %1 reveals %2. + male + %1 открыл его %2. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + %1 показывает случайно выбранную%3 карту (%2) %4. + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + %1 показывает случайно выбранную%3 карту (%2) %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + %1 показывает случайно выбранную%3 карту (%2) %4. + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + %1 показывает случайно выбранную%3 карту (%2) %4. + + + + %1 randomly reveals %2%3. + female + %1 открывает случайно выбранную%3 карту (%2). + + + + %1 randomly reveals %2%3. + male + %1 открывает случайно выбранную%3 карту (%2). + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + %1 показывает%2%3 %4. + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + %1 показывает%2%3 %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + %1 показывает%2%3 %4. + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + %1 показывает%2%3 %4. + + + + %1 reveals %2%3. + female + %1 открывает%2%3. + + + + %1 reveals %2%3. + male + %1 открывает%2%3. + + + + It is now %1's turn. + female + Ход игрока %1. + + + + It is now %1's turn. + male + Ход игрока %1. + + + %1 flips %2 face-down. + %1 перевернул %2 лицом вниз. + + + %1 flips %2 face-up. + %1 перевернул %2 лицом вверх. + + + %1 destroys %2. + %1 уничтожил %2. + + + %1 attaches %2 to %3's %4. + %1 присоединил %2 к %4 игрока %3. + + + %1 unattaches %2. + %1 отсоединил %2. + + + %1 creates token: %2%3. + %1 создал фишку: %2%3. + + + %1 points from %2's %3 to %4. + %1 указывает с %3 контролируемого %2 на %4. + + + %1 points from %2's %3 to %4's %5. + %1 указывает с %3 контролируемого %2 на %5 контролируемого %4. %1 places %n counter(s) (%2) on %3 (now %4). @@ -1672,39 +2907,96 @@ Local version is %1, remote version is %2. - %1 draws %n card(s). - + %1 взял %n карту. %1 взял %n карты. %1 взял %n карт(ы). - + + %1 undoes her last draw. + + + + + %1 undoes her last draw (%2). + + + + + the bottom card of her library + + + + + from the bottom of her library + + + + + the top card of her library + + + + + from the top of her library + + + + %1 puts %2 into play tapped%3. %1 положил %2 повернутым на поле битвы%3. + + + %1 puts %2%3 into her library. + + + + + %1 puts %2%3 on bottom of her library. + + + + + %1 puts %2%3 on top of her library. + + + + + %1 puts %2%3 into her library at position %4. + + + + + %1 draws his initial hand. + + + + + %1 draws her initial hand. + + - %1 places %n %2 counter(s) on %3 (now %4). - + %1 поместил %n %2 жетон на %3 (теперь %4). %1 поместил %n %2 жетона на %3 (теперь %4). %1 поместил %n %2 жетонов на %3 (теперь %4). - %1 removes %n %2 counter(s) from %3 (now %4). - + %1 снял %n %2 жетон с %3 (теперь %4). %1 снял %n %2 жетона с %3 (теперь %4). %1 снял %n %2 жетонов с %3 (теперь %4). - + red красный @@ -1713,7 +3005,7 @@ Local version is %1, remote version is %2. - + yellow желтый @@ -1722,7 +3014,7 @@ Local version is %1, remote version is %2. - + green зеленый @@ -1731,157 +3023,138 @@ Local version is %1, remote version is %2. - his permanents - свои перманенты + свои перманенты - %1 %2 %3. - %1 %2 %3. + %1 %2 %3. - taps - повернул + повернул - untaps - развернул + развернул - %1 sets counter %2 to %3 (%4%5). - %1 установил жетон %2 на %3 (%4%5). + %1 установил жетон %2 на %3 (%4%5). - %1 sets %2 to not untap normally. - %2 теперь не разворачивается как обычно (%1). + %2 теперь не разворачивается как обычно (%1). - %1 sets %2 to untap normally. - %2 теперь разворачивается как обычно (%1). + %2 теперь разворачивается как обычно (%1). - %1 sets PT of %2 to %3. - %1 установил Силу/Защиту %2 %3. + %1 установил Силу/Защиту %2 %3. - %1 sets annotation of %2 to %3. - %1 сделал пометку на %2 "%3". + %1 сделал пометку на %2 "%3". - %1 is looking at the top %2 cards %3. - %1 смотрит верхние %2 карт библиотеки %3. + %1 смотрит верхние %2 карт библиотеки %3. - %1 is looking at %2. - %1 просматривает %2. + %1 просматривает %2. - %1 stops looking at %2. - %1 закончил просматривать %2. + %1 закончил просматривать %2. - %1 reveals %2 to %3. - %1 показывает его %2 %3. + %1 показывает его %2 %3. - %1 reveals %2. - %1 открыл его %2. + %1 открыл его %2. - %1 randomly reveals %2%3 to %4. - %1 показывает случайно выбранную%3 карту (%2) %4. + %1 показывает случайно выбранную%3 карту (%2) %4. - %1 randomly reveals %2%3. - %1 открывает случайно выбранную%3 карту (%2). + %1 открывает случайно выбранную%3 карту (%2). - %1 reveals %2%3 to %4. - %1 показывает%2%3 %4. + %1 показывает%2%3 %4. - %1 reveals %2%3. - %1 открывает%2%3. + %1 открывает%2%3. - It is now %1's turn. - Ход игрока %1. + Ход игрока %1. - + 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 вторая главная фаза - + ending phase заключительный шаг - + It is now the %1. Сейчас %1. @@ -1889,22 +3162,22 @@ Local version is %1, remote version is %2. MessagesSettingsPage - + Add message Добавить сообщение - + Message: Сообщение: - + &Add &Добавить - + &Remove &Удалить @@ -1970,322 +3243,322 @@ Local version is %1, remote version is %2. Player - + &View graveyard &Посмотреть кладбище - + &View exile П&осмотреть изгнанные карты - + Player "%1" Игрок "%1" - + &Graveyard &Кладбище - + &Exile &Изгнание - - - + + + Move to &top of library Поместить &наверх библиотеки - - - + + + Move to &bottom of library Поместить на &дно библиотеки - - + + Move to &graveyard поместить на клад&бище - - + + Move to &exile Поместить в изгнани&е - - + + Move to &hand Поместить в &руку - + &View library Просмортеть &библиотеку - + View &top cards of library... Посмтореть верхние карт&ы... - + Reveal &library to Показать б&иблиотеку... - + Reveal t&op card to Показать верхние карты... - + &View sideboard Просмотреть &сайд - + &Draw card В&зять карту - + D&raw cards... Вз&ять карты... - + &Undo last draw &Отменить последнее взятие - + Take &mulligan Взять стра&ховку - + &Shuffle Переме&шать - + Move top cards to &graveyard... Поместить верхние карты на кладби&ще... - + Move top cards to &exile... Поместить верхние карты в и&згнание... - + Put top card on &bottom Поместить верхн&юю карту на дно - + &Hand Р&ука - + &Reveal to &Показать... - + Reveal r&andom card to Показать &случайную карту... - + &Sideboard &Сайд - + &Library &Библиотека - + &Counters &Жетоны - + &Untap all permanents &Развернуть все перманенты - + R&oll die... Бросить &кубик... - + &Create token... Создать &фишку... - + C&reate another token Создать &еще одну фишку - + S&ay Ска&зать - + C&ard Ка&рта - + &All players &Все игроки - + Ctrl+F3 - + F3 - + Ctrl+W - + F4 - + Ctrl+D - + Ctrl+E - + Ctrl+Shift+D - + Ctrl+M - + Ctrl+S - + Ctrl+U - + Ctrl+I - + Ctrl+T - + Ctrl+G - + View top cards of library Просмотр верхних карт - + Number of cards: Количество: - + 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 Установить жетоны @@ -2363,17 +3636,17 @@ Local version is %1, remote version is %2. Сайд - + Cockatrice decks (*.cod) Cockatrice-деклисты (*.cod) - + Plain text decks (*.dec *.mwDeck) Текстовые деклисты (*.dec *.mwDeck) - + All files (*.*) Все файлы (*.*) @@ -2442,40 +3715,73 @@ Local version is %1, remote version is %2. Полное название + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + &Ок + + + + &Cancel + &Отмена + + + + Shut down server + + + TabAdmin - + Update server &message Обновить сооб&щения сервера - + + &Shut down server + + + + Server administration functions Функции администрирования сервера - + &Unlock functions &Разблокировать функции - + &Lock functions &Заблокировать функции - + Unlock administration functions Разблокировать административные права - + Do you really want to unlock the administration functions? Вы действительно хотите разблокировать административные права? - + Administration Администрирование @@ -2551,127 +3857,132 @@ Please enter a name: TabGame - + F5 - + F6 - + F7 - + F8 - + F9 - + F10 - + &Phases &Фазы - + &Game &Игра - + Next &phase Следующая &фаза - + Ctrl+Space - + Next &turn Следующий &ход - + Ctrl+Return - + Ctrl+Enter - + &Remove all local arrows &Удалить все указатели - + Ctrl+R - + &Concede Сда&юсь! - + F2 - + &Leave game Покинуть и&гру - + + Ctrl+Q + + + + &Say: Ска&зать: - + Concede Сдаться - + Are you sure you want to concede this game? Испугался? - + Leave game Покинуть игру - + Are you sure you want to leave this game? Вы уверены, что хотите уйти? - + Kicked Выкинут - + You have been kicked out of the game. Вас выкинули из игры. @@ -2684,32 +3995,32 @@ Please enter a name: TabMessage - + Personal &talk Личная &беседа - + &Leave &Покинуть - + This user is ignoring you. Этот пользователь добавил вас в игнор-лист. - + %1 has left the server. %1 отключился. - + %1 has joined the server. %1 зашел на сервер. - + Talking to %1 Беседует с %1 @@ -2717,27 +4028,27 @@ Please enter a name: TabRoom - + &Say: &Сказать: - + Chat Чат - + &Room &Комната - + &Leave room &Покинуть комнату - + You are flooding the chat. Please wait a couple of seconds. Кажется, Вы нафлудили. Пожалуйста, подождите пару секунд. @@ -2761,42 +4072,51 @@ Please enter a name: UserInfoBox - + User information Информация о пользователе - + Real name: Настоящее имя: - + + Gender: + + + + Location: Местонахождение: - + User level: Уровень: - + Administrator Администратор - - Judge - Судья + + Moderator + - + Judge + Судья + + + Registered user Зарегистрированный пользователь - + Unregistered user Рандом @@ -2804,281 +4124,314 @@ Please enter a name: UserInterfaceSettingsPage - + General interface settings Основные настройки интерфейса - + &Double-click cards to play them (instead of single-click) &Двойной клик чтобы разыграть карту (вместо одинарного) - + Animation settings Настройки анимации - + &Tap/untap animation &Анимировать поворот/разворот карты + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + + UserList - + Users online: %1 Пользователей онлайн: %1 - + Users in this room: %1 Пользователей в этой комнате: %1 - + Buddies online: %1 / %2 Друзей онлайн: %1 / %2 - + Ignored users online: %1 / %2 Игнорируемых пользователей онлайн: %1 / %2 - + + %1's games + + + + User &details Данные о &пользователе - + Direct &chat Обратиться &лично - + + Show this user's &games + + + + Add to &buddy list Добавить в список &друзей - + Remove from &buddy list &Удалить из друзей - + Add to &ignore list Добавить в &игнор-лист - + Remove from &ignore list Удалить и&з игнор-листа - + Ban from &server За&банить на сервере - Duration - Продолжительность + Продолжительность - Please enter the duration of the ban (in minutes). Enter 0 for an indefinite ban. - Введите продолжительность бана (в минутах). + Введите продолжительность бана (в минутах). Введите 0 чтобы забанить пожизненно. WndDeckEditor - + &Search... &Поиск... - + &Clear search &Очистить строку поиска - + &Search for: &Искать: - + Deck &name: &Название колоды: - + &Comments: Ко&мментарии: - + + &Update prices + + + + + Ctrl+U + + + + Deck editor [*] Редактор колод [*] - + &New deck Новая коло&да - + &Load deck... &Загрузить колоду... - + &Save deck Со&хранить колоду - + Save deck &as... Сохранить колоду к&ак... - + Load deck from cl&ipboard... Взять колоду из &буфера... - + Save deck to clip&board Копировать колоду в бу&фер - + &Print deck... Пе&чать колоды... - + &Close &Закрыть - + Ctrl+Q - + &Edit sets... Редактировать издани&я... - + &Deck Ко&лода - + &Card database База кар&т - + Add card to &maindeck Добавить ме&йном - + Return - + Enter - + Add card to &sideboard Добавить в са&йд - + Ctrl+Return - + Ctrl+Enter - + &Remove row &Удалить строку - + Del - + &Increment number У&величить количество - + + - + &Decrement number У&меньшить количество - + - - + Are you sure? Вы уверены? - + The decklist has been modified. Do you want to save the changes? Деклист был отредактирован. Сохранить изменения? - + Load deck Загрузить колоду - + 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_sk.ts b/cockatrice/translations/cockatrice_sk.ts new file mode 100644 index 000000000..a5155a2fc --- /dev/null +++ b/cockatrice/translations/cockatrice_sk.ts @@ -0,0 +1,4047 @@ + + + + + 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: + + + + + Card rendering + + + + + Display card names on cards having a picture + + + + + Hand layout + + + + + Display hand horizontally (wastes space) + + + + + Table grid layout + + + + + Invert vertical coordinate + + + + + Minimum player count for multi-column layout: + + + + + Zone view layout + + + + + Sort by name + + + + + Sort by type + + + + + + + + + Choose path + + + + + BanDialog + + + Please enter the duration of the ban (in minutes). +Enter 0 for an indefinite ban. + + + + + Please enter the reason for the ban. +This is only saved for moderators and cannot be seen by the banned person. + + + + + &OK + + + + + &Cancel + + + + + Ban user from server + + + + + CardDatabaseModel + + + Name + + + + + Sets + + + + + Mana cost + + + + + Card type + + + + + P/T + + + + + CardInfoWidget + + + Hide card info + + + + + Show card only + + + + + Show text only + + + + + Show full info + + + + + Name: + + + + + Mana cost: + + + + + Card type: + + + + + P / T: + + + + + CardItem + + + &Play + + + + + &Hide + + + + + &Tap + + + + + &Untap + + + + + Toggle &normal untapping + + + + + &Flip + + + + + &Clone + + + + + Ctrl+H + + + + + &Attach to card... + + + + + Ctrl+A + + + + + Unattac&h + + + + + &Draw arrow... + + + + + &Power / toughness + + + + + &Increase power + + + + + Ctrl++ + + + + + &Decrease power + + + + + Ctrl+- + + + + + I&ncrease toughness + + + + + Alt++ + + + + + D&ecrease toughness + + + + + Alt+- + + + + + In&crease power and toughness + + + + + Ctrl+Alt++ + + + + + Dec&rease power and toughness + + + + + Ctrl+Alt+- + + + + + Set &power and toughness... + + + + + Ctrl+P + + + + + &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 + + + + + CardZone + + + her hand + nominative, female owner + + + + + %1's hand + nominative, female owner + + + + + his hand + nominative, male owner + + + + + %1's hand + nominative, male owner + + + + + of her hand + genitive, female owner + + + + + of %1's hand + genitive, female owner + + + + + of his hand + genitive, male owner + + + + + of %1's hand + genitive, male owner + + + + + her hand + accusative, female owner + + + + + %1's hand + accusative, female owner + + + + + his hand + accusative, male owner + + + + + %1's hand + accusative, male owner + + + + + her library + nominative, female owner + + + + + %1's library + nominative, female owner + + + + + his library + nominative, male owner + + + + + %1's library + nominative, male owner + + + + + of her library + genitive, female owner + + + + + of %1's library + genitive, female owner + + + + + of his library + genitive, male owner + + + + + of %1's library + genitive, male owner + + + + + her library + accusative, female owner + + + + + %1's library + accusative, female owner + + + + + his library + accusative, male owner + + + + + %1's library + accusative, male owner + + + + + her graveyard + nominative, female owner + + + + + %1's graveyard + nominative, female owner + + + + + his graveyard + nominative, male owner + + + + + %1's graveyard + nominative, male owner + + + + + of her graveyard + genitive, female owner + + + + + of %1's graveyard + genitive, female owner + + + + + of his graveyard + genitive, male owner + + + + + of %1's graveyard + genitive, male owner + + + + + her graveyard + accusative, female owner + + + + + %1's graveyard + accusative, female owner + + + + + his graveyard + accusative, male owner + + + + + %1's graveyard + accusative, male owner + + + + + her exile + nominative, female owner + + + + + %1's exile + nominative, female owner + + + + + his exile + nominative, male owner + + + + + %1's exile + nominative, male owner + + + + + of her exile + genitive, female owner + + + + + of %1's exile + genitive, female owner + + + + + of his exile + genitive, male owner + + + + + of %1's exile + genitive, male owner + + + + + her exile + accusative, female owner + + + + + %1's exile + accusative, female owner + + + + + his exile + accusative, male owner + + + + + %1's exile + accusative, male owner + + + + + her sideboard + nominative, female owner + + + + + %1's sideboard + nominative, female owner + + + + + his sideboard + nominative, male owner + + + + + %1's sideboard + nominative, male owner + + + + + of her sideboard + genitive, female owner + + + + + of %1's sideboard + genitive, female owner + + + + + of his sideboard + genitive, male owner + + + + + of %1's sideboard + genitive, male owner + + + + + her sideboard + accusative, female owner + + + + + %1's sideboard + accusative, female owner + + + + + his sideboard + accusative, male owner + + + + + %1's sideboard + accusative, male owner + + + + + DeckEditorSettingsPage + + + Enable &price tag feature (using data from blacklotusproject.com) + + + + + General + + + + + DeckListModel + + + Number + + + + + Card + + + + + Price + + + + + DeckViewContainer + + + Load &local deck + + + + + Load d&eck from server + + + + + Ready to s&tart + + + + + Load deck + + + + + DlgCardSearch + + + Card name: + + + + + Card text: + + + + + Card type (OR): + + + + + Color (OR): + + + + + O&K + + + + + &Cancel + + + + + Card search + + + + + DlgConnect + + + &Host: + + + + + &Port: + + + + + Player &name: + + + + + P&assword: + + + + + &OK + + + + + &Cancel + + + + + Connect to server + + + + + DlgCreateGame + + + &Description: + + + + + P&layers: + + + + + Game type + + + + + &Password: + + + + + Only &buddies can join + + + + + Only &registered users can join + + + + + Joining restrictions + + + + + &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 + + + + + Deck editor + + + + + Messages + + + + + &Close + + + + + GameSelector + + + + + + + + + + Error + + + + + Please join the appropriate room first. + + + + + Wrong password. + + + + + Spectators are not allowed in this game. + + + + + The game is already full. + + + + + The game does not exist any more. + + + + + This game is only open to registered users. + + + + + This game is only open to its creator's buddies. + + + + + You are being ignored by the creator of this game. + + + + + Join game + + + + + Password: + + + + + Games + + + + + Show &full games + + + + + Show &running games + + + + + C&reate + + + + + &Join + + + + + J&oin as spectator + + + + + GameView + + + Esc + + + + + GamesModel + + + yes + + + + + yes, free for spectators + + + + + no + + + + + buddies only + + + + + reg. users only + + + + + not allowed + + + + + Room + + + + + Description + + + + + Creator + + + + + Game type + + + + + Password + + + + + Restrictions + + + + + Players + + + + + Spectators + + + + + GeneralSettingsPage + + + + English + + + + + + + Choose path + + + + + Personal settings + + + + + Language: + + + + + Download card pictures on the fly + + + + + Paths + + + + + Decks directory: + + + + + Pictures directory: + + + + + Path to card database: + + + + + MainWindow + + + There are too many concurrent connections from your address. + + + + + Banned by moderator. + + + + + Scheduled server shutdown. + + + + + Unknown reason. + + + + + Connection closed + + + + + The server has terminated your connection. +Reason: %1 + + + + + Scheduled server shutdown + + + + + The server is going to be restarted in %n minute(s). +All running games will be lost. +Reason for shutdown: %1 + + + + + + + + + Number of players + + + + + Please enter the number of players. + + + + + + Player %1 + + + + + About Cockatrice + + + + + Version %1 + + + + + Authors: + + + + + Translators: + + + + + Spanish: + + + + + Portugese (Portugal): + + + + + Portugese (Brazil): + + + + + French: + + + + + Japanese: + + + + + Russian: + + + + + Czech: + + + + + Slovak: + + + + + + + + + + Error + + + + + Server timeout + + + + + Invalid login data. + + + + + There is already an active session using this user name. +Please close that session first and re-login. + + + + + Socket error: %1 + + + + + You are trying to connect to an obsolete server. Please downgrade your Cockatrice version or connect to a suitable server. +Local version is %1, remote version is %2. + + + + + Your Cockatrice client is obsolete. Please update your Cockatrice version. +Local version is %1, remote version is %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? + + + + + MessageLogWidget + + + The game has been closed. + + + + + %1 is now watching the game. + + + + + %1 is not watching the game any more. + + + + + The game has started. + + + + + You have joined game #%1. + female + + + + + You have joined game #%1. + male + + + + + %1 has joined the game. + female + + + + + %1 has joined the game. + male + + + + + %1 has left the game. + female + + + + + %1 has left the game. + male + + + + + %1 has loaded a local deck. + female + + + + + %1 has loaded a local deck. + male + + + + + %1 has loaded deck #%2. + female + + + + + %1 has loaded deck #%2. + male + + + + + %1 is ready to start the game. + female + + + + + %1 is ready to start the game. + male + + + + + %1 is not ready to start the game any more. + female + + + + + %1 is not ready to start the game any more. + male + + + + + %1 has conceded the game. + female + + + + + %1 has conceded the game. + male + + + + + %1 has restored connection to the game. + female + + + + + %1 has restored connection to the game. + male + + + + + %1 has lost connection to the game. + female + + + + + %1 has lost connection to the game. + male + + + + + %1 shuffles %2. + female + + + + + %1 shuffles %2. + male + + + + + %1 rolls a %2 with a %3-sided die. + female + + + + + %1 rolls a %2 with a %3-sided die. + male + + + + + %1 draws %n card(s). + female + + + + + + + + + %1 draws %n card(s). + male + + + + + + + + + %1 undoes his last draw. + + + + + %1 undoes her last draw. + + + + + %1 undoes his last draw (%2). + + + + + %1 undoes her last draw (%2). + + + + + from table + + + + + from graveyard + + + + + from exile + + + + + from hand + + + + + the bottom card of his library + + + + + the bottom card of her library + + + + + from the bottom of his library + + + + + from the bottom of her library + + + + + the top card of his library + + + + + the top card of her library + + + + + from the top of his library + + + + + from the top of her library + + + + + from library + + + + + from sideboard + + + + + from the stack + + + + + + a card + + + + + %1 gives %2 control over %3. + + + + + %1 puts %2 into play tapped%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 into her library. + + + + + %1 puts %2%3 on bottom of his library. + + + + + %1 puts %2%3 on bottom of her library. + + + + + %1 puts %2%3 on top of his library. + + + + + %1 puts %2%3 on top of her library. + + + + + %1 puts %2%3 into his library at position %4. + + + + + %1 puts %2%3 into her library at position %4. + + + + + %1 moves %2%3 to sideboard. + + + + + %1 plays %2%3. + + + + + %1 takes a mulligan to %n. + female + + + + + + + + + %1 takes a mulligan to %n. + male + + + + + + + + + %1 flips %2 face-down. + female + + + + + %1 flips %2 face-down. + male + + + + + %1 flips %2 face-up. + female + + + + + %1 flips %2 face-up. + male + + + + + %1 destroys %2. + female + + + + + %1 destroys %2. + male + + + + + %1 unattaches %2. + female + + + + + %1 unattaches %2. + male + + + + + %1 creates token: %2%3. + female + + + + + %1 creates token: %2%3. + male + + + + + %1 points from her %2 to herself. + female + + + + + %1 points from his %2 to himself. + male + + + + + %1 points from her %2 to %3. + p1 female, p2 female + + + + + %1 points from her %2 to %3. + p1 female, p2 male + + + + + %1 points from his %2 to %3. + p1 male, p2 female + + + + + %1 points from his %2 to %3. + p1 male, p2 male + + + + + %1 points from %2's %3 to herself. + card owner female, target female + + + + + %1 points from %2's %3 to herself. + card owner male, target female + + + + + %1 points from %2's %3 to himself. + card owner female, target male + + + + + %1 points from %2's %3 to himself. + card owner male, target male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4. + p1 male, p2 male, p3 male + + + + + %1 points from her %2 to her %3. + female + + + + + %1 points from his %2 to his %3. + male + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 female + + + + + %1 points from her %2 to %3's %4. + p1 female, p2 male + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 female + + + + + %1 points from his %2 to %3's %4. + p1 male, p2 male + + + + + %1 points from %2's %3 to her own %4. + card owner female, target female + + + + + %1 points from %2's %3 to her own %4. + card owner male, target female + + + + + %1 points from %2's %3 to his own %4. + card owner female, target male + + + + + %1 points from %2's %3 to his own %4. + card owner male, target male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 female, p2 male, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 female, p3 male + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 female + + + + + %1 points from %2's %3 to %4's %5. + p1 male, p2 male, p3 male + + + + + %1 places %n %2 counter(s) on %3 (now %4). + female + + + + + + + + + %1 places %n %2 counter(s) on %3 (now %4). + male + + + + + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + female + + + + + + + + + %1 removes %n %2 counter(s) from %3 (now %4). + male + + + + + + + + + %1 taps her permanents. + female + + + + + %1 untaps her permanents. + female + + + + + %1 taps his permanents. + male + + + + + %1 untaps his permanents. + male + + + + + %1 taps %2. + female + + + + + %1 untaps %2. + female + + + + + %1 taps %2. + male + + + + + %1 untaps %2. + male + + + + + %1 sets counter %2 to %3 (%4%5). + female + + + + + %1 sets counter %2 to %3 (%4%5). + male + + + + + %1 sets %2 to not untap normally. + female + + + + + %1 sets %2 to not untap normally. + male + + + + + %1 sets %2 to untap normally. + female + + + + + %1 sets %2 to untap normally. + male + + + + + %1 sets PT of %2 to %3. + female + + + + + %1 sets PT of %2 to %3. + male + + + + + %1 sets annotation of %2 to %3. + female + + + + + %1 sets annotation of %2 to %3. + male + + + + + %1 is looking at the top %2 cards %3. + female + + + + + %1 is looking at the top %2 cards %3. + male + + + + + %1 is looking at %2. + female + + + + + %1 is looking at %2. + male + + + + + %1 stops looking at %2. + female + + + + + %1 stops looking at %2. + male + + + + + %1 reveals %2 to %3. + p1 female, p2 female + + + + + %1 reveals %2 to %3. + p1 female, p2 male + + + + + %1 reveals %2 to %3. + p1 male, p2 female + + + + + %1 reveals %2 to %3. + p1 male, p2 male + + + + + %1 reveals %2. + female + + + + + %1 reveals %2. + male + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 randomly reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 randomly reveals %2%3. + female + + + + + %1 randomly reveals %2%3. + male + + + + + %1 reveals %2%3 to %4. + p1 female, p2 female + + + + + %1 reveals %2%3 to %4. + p1 female, p2 male + + + + + %1 reveals %2%3 to %4. + p1 male, p2 female + + + + + %1 reveals %2%3 to %4. + p1 male, p2 male + + + + + %1 reveals %2%3. + female + + + + + %1 reveals %2%3. + male + + + + + It is now %1's turn. + female + + + + + It is now %1's turn. + male + + + + + %1 draws his initial hand. + + + + + %1 draws her initial hand. + + + + + %1 attaches %2 to %3's %4. + p1 female, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 female, p2 male + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 female + + + + + %1 attaches %2 to %3's %4. + p1 male, p2 male + + + + + red + + + + + + + + + yellow + + + + + + + + + green + + + + + + + + + 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 + + + + + ending phase + + + + + It is now the %1. + + + + + MessagesSettingsPage + + + Add message + + + + + Message: + + + + + &Add + + + + + &Remove + + + + + 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 + + + + + Player + + + &View graveyard + + + + + &View exile + + + + + Player "%1" + + + + + &Graveyard + + + + + &Exile + + + + + + + Move to &top of library + + + + + + + Move to &bottom of library + + + + + + Move to &graveyard + + + + + + Move to &exile + + + + + + Move to &hand + + + + + &View library + + + + + View &top cards of library... + + + + + Reveal &library to + + + + + Reveal t&op card to + + + + + &View sideboard + + + + + &Draw card + + + + + D&raw cards... + + + + + &Undo last draw + + + + + Take &mulligan + + + + + &Shuffle + + + + + Move top cards to &graveyard... + + + + + Move top cards to &exile... + + + + + Put top card on &bottom + + + + + &Hand + + + + + &Reveal to + + + + + Reveal r&andom card to + + + + + &Sideboard + + + + + &Library + + + + + &Counters + + + + + &Untap all permanents + + + + + R&oll die... + + + + + &Create token... + + + + + C&reate another token + + + + + S&ay + + + + + C&ard + + + + + &All players + + + + + Ctrl+F3 + + + + + F3 + + + + + Ctrl+W + + + + + F4 + + + + + Ctrl+D + + + + + Ctrl+E + + + + + Ctrl+Shift+D + + + + + Ctrl+M + + + + + Ctrl+S + + + + + Ctrl+U + + + + + Ctrl+I + + + + + Ctrl+T + + + + + Ctrl+G + + + + + View top cards of library + + + + + Number of cards: + + + + + 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 + + + + + PlayerListWidget + + + local deck + + + + + deck #%1 + + + + + User &details + + + + + Direct &chat + + + + + Add to &buddy list + + + + + Remove from &buddy list + + + + + Add to &ignore list + + + + + Remove from &ignore list + + + + + Kick from &game + + + + + 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 + + + + + SetsModel + + + Short name + + + + + Long name + + + + + ShutdownDialog + + + &Reason for shutdown: + + + + + &Time until shutdown (minutes): + + + + + &OK + + + + + &Cancel + + + + + Shut down server + + + + + TabAdmin + + + Update server &message + + + + + &Shut down server + + + + + Server administration functions + + + + + &Unlock functions + + + + + &Lock functions + + + + + Unlock administration functions + + + + + Do you really want to unlock the administration functions? + + + + + Administration + + + + + 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 + + + F5 + + + + + F6 + + + + + F7 + + + + + F8 + + + + + F9 + + + + + F10 + + + + + &Phases + + + + + &Game + + + + + Next &phase + + + + + Ctrl+Space + + + + + Next &turn + + + + + Ctrl+Return + + + + + Ctrl+Enter + + + + + &Remove all local arrows + + + + + Ctrl+R + + + + + &Concede + + + + + F2 + + + + + &Leave game + + + + + Ctrl+Q + + + + + &Say: + + + + + Concede + + + + + Are you sure you want to concede this game? + + + + + Leave game + + + + + Are you sure you want to leave this game? + + + + + Kicked + + + + + You have been kicked out of the game. + + + + + Game %1: %2 + + + + + TabMessage + + + Personal &talk + + + + + &Leave + + + + + This user is ignoring you. + + + + + %1 has left the server. + + + + + %1 has joined the server. + + + + + Talking to %1 + + + + + TabRoom + + + &Say: + + + + + Chat + + + + + &Room + + + + + &Leave room + + + + + You are flooding the chat. Please wait a couple of seconds. + + + + + TabServer + + + Server + + + + + TabUserLists + + + User lists + + + + + UserInfoBox + + + User information + + + + + Real name: + + + + + Gender: + + + + + Location: + + + + + User level: + + + + + Administrator + + + + + Moderator + + + + + Registered user + + + + + Unregistered user + + + + + UserInterfaceSettingsPage + + + General interface settings + + + + + &Double-click cards to play them (instead of single-click) + + + + + Animation settings + + + + + &Tap/untap animation + + + + + Enable &sounds + + + + + Path to sounds directory: + + + + + Choose path + + + + + UserList + + + Users online: %1 + + + + + Users in this room: %1 + + + + + Buddies online: %1 / %2 + + + + + Ignored users online: %1 / %2 + + + + + %1's games + + + + + User &details + + + + + Direct &chat + + + + + Show this user's &games + + + + + Add to &buddy list + + + + + Remove from &buddy list + + + + + Add to &ignore list + + + + + Remove from &ignore list + + + + + Ban from &server + + + + + WndDeckEditor + + + &Search... + + + + + &Clear search + + + + + &Search for: + + + + + Deck &name: + + + + + &Comments: + + + + + &Update prices + + + + + Ctrl+U + + + + + Deck editor [*] + + + + + &New deck + + + + + &Load deck... + + + + + &Save deck + + + + + Save deck &as... + + + + + Load deck from cl&ipboard... + + + + + Save deck to clip&board + + + + + &Print deck... + + + + + &Close + + + + + Ctrl+Q + + + + + &Edit sets... + + + + + &Deck + + + + + &Card database + + + + + Add card to &maindeck + + + + + Return + + + + + Enter + + + + + Add card to &sideboard + + + + + Ctrl+Return + + + + + Ctrl+Enter + + + + + &Remove row + + + + + Del + + + + + &Increment number + + + + + + + + + + + &Decrement number + + + + + - + + + + + Are you sure? + + + + + The decklist has been modified. +Do you want to save the changes? + + + + + Load deck + + + + + + Error + + + + + + The deck could not be saved. +Please check that the directory is writable and try again. + + + + + Save deck + + + + + WndSets + + + Edit sets + + + + + ZoneViewWidget + + + sort by name + + + + + sort by type + + + + + shuffle when closing + + + + diff --git a/common/decklist.cpp b/common/decklist.cpp index 75a26514a..6aed8f89f 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -127,6 +127,19 @@ int InnerDecklistNode::recursiveCount(bool countTotalCards) const return result; } +float InnerDecklistNode::recursivePrice(bool countTotalCards) const +{ + float result = 0; + for (int i = 0; i < size(); i++) { + InnerDecklistNode *node = dynamic_cast(at(i)); + if (node) + result += node->recursivePrice(countTotalCards); + else if (countTotalCards) + result += dynamic_cast(at(i))->getTotalPrice(); + } + return result; +} + bool InnerDecklistNode::compare(AbstractDecklistNode *other) const { InnerDecklistNode *other2 = dynamic_cast(other); @@ -165,11 +178,12 @@ bool InnerDecklistNode::readElement(QXmlStreamReader *xml) } if (xml->isStartElement() && (xml->name() == "zone")) currentItem = new InnerDecklistNode(xml->attributes().value("name").toString(), this); - else if (xml->isStartElement() && (xml->name() == "card")) - currentItem = new DecklistCardNode(xml->attributes().value("name").toString(), xml->attributes().value("number").toString().toInt(), this); - else if (xml->isEndElement() && (xml->name() == "zone")) + else if (xml->isStartElement() && (xml->name() == "card")) { + float price = (xml->attributes().value("price") != NULL) ? xml->attributes().value("price").toString().toFloat() : 0; + currentItem = new DecklistCardNode(xml->attributes().value("name").toString(), xml->attributes().value("number").toString().toInt(), price, this); + } else if (xml->isEndElement() && (xml->name() == "zone")) return true; - + return false; } @@ -194,6 +208,7 @@ void AbstractDecklistCardNode::writeElement(QXmlStreamWriter *xml) { xml->writeEmptyElement("card"); xml->writeAttribute("number", QString::number(getNumber())); + xml->writeAttribute("price", QString::number(getPrice())); xml->writeAttribute("name", getName()); } diff --git a/common/decklist.h b/common/decklist.h index 379421743..d0f2b7cf7 100644 --- a/common/decklist.h +++ b/common/decklist.h @@ -69,6 +69,7 @@ public: AbstractDecklistNode *findChild(const QString &name); int height() const; int recursiveCount(bool countTotalCards = false) const; + float recursivePrice(bool countTotalCards = false) const; bool compare(AbstractDecklistNode *other) const; QVector > sort(Qt::SortOrder order = Qt::AscendingOrder); @@ -83,6 +84,9 @@ public: virtual void setNumber(int _number) = 0; virtual QString getName() const = 0; virtual void setName(const QString &_name) = 0; + virtual float getPrice() const = 0; + virtual void setPrice(float _price) = 0; + float getTotalPrice() const { return getNumber() * getPrice(); } int height() const { return 0; } bool compare(AbstractDecklistNode *other) const; @@ -94,14 +98,18 @@ class DecklistCardNode : public AbstractDecklistCardNode { private: QString name; int number; + float price; public: - DecklistCardNode(const QString &_name = QString(), int _number = 1, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number) { } + DecklistCardNode(const QString &_name = QString(), int _number = 1, float _price = 0, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number), price(_price) { } + DecklistCardNode(const QString &_name = QString(), int _number = 1, InnerDecklistNode *_parent = 0) : AbstractDecklistCardNode(_parent), name(_name), number(_number), price(0) { } DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent); int getNumber() const { return number; } void setNumber(int _number) { number = _number; } QString getName() const { return name; } void setName(const QString &_name) { name = _name; } -}; + float getPrice() const { return price; } + void setPrice(const float _price) { price = _price; } + }; class DeckList : public SerializableItem { Q_OBJECT diff --git a/common/protocol.cpp b/common/protocol.cpp index fe3997add..85c581d0f 100644 --- a/common/protocol.cpp +++ b/common/protocol.cpp @@ -44,6 +44,7 @@ void ProtocolItem::initializeHash() ProtocolResponse::initializeHash(); registerSerializableItem("respjoin_room", Response_JoinRoom::newItem); registerSerializableItem("resplist_users", Response_ListUsers::newItem); + registerSerializableItem("respget_games_of_user", Response_GetGamesOfUser::newItem); registerSerializableItem("respget_user_info", Response_GetUserInfo::newItem); registerSerializableItem("respdeck_list", Response_DeckList::newItem); registerSerializableItem("respdeck_download", Response_DeckDownload::newItem); @@ -74,7 +75,7 @@ TopLevelProtocolItem::TopLevelProtocolItem() bool TopLevelProtocolItem::readCurrentItem(QXmlStreamReader *xml) { if (currentItem) { - if (currentItem->readElement(xml)) { + if (currentItem->read(xml)) { emit protocolItemReceived(currentItem); currentItem = 0; } @@ -92,6 +93,8 @@ bool TopLevelProtocolItem::readElement(QXmlStreamReader *xml) currentItem = dynamic_cast(getNewItem(childName + childSubType)); if (!currentItem) currentItem = new ProtocolItem_Invalid; + if (xml->attributes().value("comp").toString().toInt() == 1) + currentItem->setCompressed(true); readCurrentItem(xml); } @@ -254,6 +257,7 @@ void ProtocolResponse::initializeHash() { responseHash.insert(QString(), RespNothing); responseHash.insert("ok", RespOk); + responseHash.insert("not_in_room", RespNotInRoom); responseHash.insert("internal_error", RespInternalError); responseHash.insert("invalid_command", RespInvalidCommand); responseHash.insert("name_not_found", RespNameNotFound); @@ -294,6 +298,34 @@ Response_DeckList::Response_DeckList(int _cmdId, ResponseCode _responseCode, Dec insertItem(_root); } +Response_GetGamesOfUser::Response_GetGamesOfUser(int _cmdId, ResponseCode _responseCode, const QList &_roomList, const QList &_gameList) + : ProtocolResponse(_cmdId, _responseCode, "get_games_of_user") +{ + roomList = _roomList; + for (int i = 0; i < _roomList.size(); ++i) + itemList.append(_roomList[i]); + + gameList = _gameList; + for (int i = 0; i < _gameList.size(); ++i) + itemList.append(_gameList[i]); +} + +void Response_GetGamesOfUser::extractData() +{ + for (int i = 0; i < itemList.size(); ++i) { + ServerInfo_Room *room = dynamic_cast(itemList[i]); + if (room) { + roomList.append(room); + continue; + } + ServerInfo_Game *game = dynamic_cast(itemList[i]); + if (game) { + gameList.append(game); + continue; + } + } +} + Response_GetUserInfo::Response_GetUserInfo(int _cmdId, ResponseCode _responseCode, ServerInfo_User *_user) : ProtocolResponse(_cmdId, _responseCode, "get_user_info") { diff --git a/common/protocol.h b/common/protocol.h index b72deb107..beb09d496 100644 --- a/common/protocol.h +++ b/common/protocol.h @@ -42,13 +42,14 @@ enum ItemId { ItemId_Event_Ping = ItemId_Other + 212, ItemId_Event_AddToList = ItemId_Other + 213, ItemId_Response_ListUsers = ItemId_Other + 300, - ItemId_Response_GetUserInfo = ItemId_Other + 301, - ItemId_Response_DeckList = ItemId_Other + 302, - 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_Response_GetGamesOfUser = ItemId_Other + 301, + ItemId_Response_GetUserInfo = ItemId_Other + 302, + ItemId_Response_DeckList = ItemId_Other + 303, + ItemId_Response_DeckDownload = ItemId_Other + 304, + ItemId_Response_DeckUpload = ItemId_Other + 305, + ItemId_Response_DumpZone = ItemId_Other + 306, + ItemId_Response_JoinRoom = ItemId_Other + 307, + ItemId_Response_Login = ItemId_Other + 308, ItemId_Invalid = ItemId_Other + 1000 }; @@ -167,6 +168,15 @@ public: void setGameId(int _gameId) { static_cast(itemMap.value("game_id"))->setData(_gameId); } }; +class ModeratorCommand : public Command { + Q_OBJECT +public: + ModeratorCommand(const QString &_cmdName) + : Command(_cmdName) + { + } +}; + class AdminCommand : public Command { Q_OBJECT public: @@ -273,6 +283,21 @@ public: QList getUserList() const { return typecastItemList(); } }; +class Response_GetGamesOfUser : public ProtocolResponse { + Q_OBJECT +private: + QList gameList; + QList roomList; +protected: + void extractData(); +public: + Response_GetGamesOfUser(int _cmdId = -1, ResponseCode _responseCode = RespOk, const QList &_roomList = QList(), const QList &_gameList = QList()); + int getItemId() const { return ItemId_Response_GetGamesOfUser; } + static SerializableItem *newItem() { return new Response_GetGamesOfUser; } + QList getRoomList() const { return roomList; } + QList getGameList() const { return gameList; } +}; + class Response_GetUserInfo : public ProtocolResponse { Q_OBJECT public: diff --git a/common/protocol_datastructures.cpp b/common/protocol_datastructures.cpp index 687bf8dfa..7d68434af 100644 --- a/common/protocol_datastructures.cpp +++ b/common/protocol_datastructures.cpp @@ -11,12 +11,13 @@ CardToMove::CardToMove(int _cardId, const QString &_pt, bool _tapped) insertItem(new SerializableItem_Bool("tapped", _tapped)); } -ServerInfo_User::ServerInfo_User(const QString &_name, int _userLevel, const QString &_realName, const QString &_country, const QByteArray &_avatarBmp) +ServerInfo_User::ServerInfo_User(const QString &_name, int _userLevel, const QString &_realName, Gender _gender, 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_Int("gender", _gender)); insertItem(new SerializableItem_String("country", _country)); insertItem(new SerializableItem_ByteArray("avatar_bmp", _avatarBmp)); } @@ -27,6 +28,7 @@ ServerInfo_User::ServerInfo_User(const ServerInfo_User *other, bool complete) 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_Int("gender", other->getGender())); insertItem(new SerializableItem_String("country", other->getCountry())); insertItem(new SerializableItem_ByteArray("avatar_bmp", complete ? other->getAvatarBmp() : QByteArray())); } @@ -38,14 +40,16 @@ ServerInfo_UserList::ServerInfo_UserList(const QString &_itemType, const QList &_gameTypes, ServerInfo_User *_creatorInfo, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, int _spectatorCount) +ServerInfo_Game::ServerInfo_Game(int _roomId, int _gameId, const QString &_description, bool _hasPassword, int _playerCount, int _maxPlayers, bool _started, const QList &_gameTypes, ServerInfo_User *_creatorInfo, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, int _spectatorCount) : SerializableItem_Map("game") { + insertItem(new SerializableItem_Int("room_id", _roomId)); insertItem(new SerializableItem_Int("game_id", _gameId)); insertItem(new SerializableItem_String("description", _description)); insertItem(new SerializableItem_Bool("has_password", _hasPassword)); insertItem(new SerializableItem_Int("player_count", _playerCount)); insertItem(new SerializableItem_Int("max_players", _maxPlayers)); + insertItem(new SerializableItem_Bool("started", _started)); if (!_creatorInfo) _creatorInfo = new ServerInfo_User; insertItem(_creatorInfo); @@ -115,7 +119,7 @@ ServerInfo_CardCounter::ServerInfo_CardCounter(int _id, int _value) insertItem(new SerializableItem_Int("value", _value)); } -ServerInfo_Card::ServerInfo_Card(int _id, const QString &_name, int _x, int _y, bool _tapped, bool _attacking, const QString &_color, const QString &_pt, const QString &_annotation, bool _destroyOnZoneChange, const QList &_counters, int _attachPlayerId, const QString &_attachZone, int _attachCardId) +ServerInfo_Card::ServerInfo_Card(int _id, const QString &_name, int _x, int _y, bool _tapped, bool _attacking, const QString &_color, const QString &_pt, const QString &_annotation, bool _destroyOnZoneChange, bool _doesntUntap, const QList &_counters, int _attachPlayerId, const QString &_attachZone, int _attachCardId) : SerializableItem_Map("card") { insertItem(new SerializableItem_Int("id", _id)); @@ -128,6 +132,7 @@ ServerInfo_Card::ServerInfo_Card(int _id, const QString &_name, int _x, int _y, insertItem(new SerializableItem_String("pt", _pt)); insertItem(new SerializableItem_String("annotation", _annotation)); insertItem(new SerializableItem_Bool("destroy_on_zone_change", _destroyOnZoneChange)); + insertItem(new SerializableItem_Bool("doesnt_untap", _doesntUntap)); insertItem(new SerializableItem_Int("attach_player_id", _attachPlayerId)); insertItem(new SerializableItem_String("attach_zone", _attachZone)); insertItem(new SerializableItem_Int("attach_card_id", _attachCardId)); diff --git a/common/protocol_datastructures.h b/common/protocol_datastructures.h index 8e3d9826a..a3843a3d7 100644 --- a/common/protocol_datastructures.h +++ b/common/protocol_datastructures.h @@ -8,7 +8,7 @@ class DeckList; -enum ResponseCode { RespNothing, RespOk, RespInternalError, RespInvalidCommand, RespInvalidData, RespNameNotFound, RespLoginNeeded, RespFunctionNotAllowed, RespGameNotStarted, RespGameFull, RespContextError, RespWrongPassword, RespSpectatorsNotAllowed, RespOnlyBuddies, RespUserLevelTooLow, RespInIgnoreList, RespWouldOverwriteOldSession, RespChatFlood }; +enum ResponseCode { RespNothing, RespOk, RespNotInRoom, RespInternalError, RespInvalidCommand, RespInvalidData, RespNameNotFound, RespLoginNeeded, RespFunctionNotAllowed, RespGameNotStarted, RespGameFull, RespContextError, RespWrongPassword, RespSpectatorsNotAllowed, RespOnlyBuddies, RespUserLevelTooLow, RespInIgnoreList, RespWouldOverwriteOldSession, RespChatFlood }; // PrivateZone: Contents of the zone are always visible to the owner, // but not to anyone else. @@ -41,16 +41,22 @@ public: IsNothing = 0x00, IsUser = 0x01, IsRegistered = 0x02, - IsJudge = 0x04, + IsModerator = 0x04, IsAdmin = 0x08 }; - ServerInfo_User(const QString &_name = QString(), int _userLevel = IsNothing, const QString &_realName = QString(), const QString &_country = QString(), const QByteArray &_avatarBmp = QByteArray()); + enum Gender { + GenderUnknown = -1, + Male = 0, + Female = 1 + }; + ServerInfo_User(const QString &_name = QString(), int _userLevel = IsNothing, const QString &_realName = QString(), Gender _gender = GenderUnknown, 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(); } + Gender getGender() const { return static_cast(static_cast(itemMap.value("gender"))->getData()); } QString getCountry() const { return static_cast(itemMap.value("country"))->getData(); } QByteArray getAvatarBmp() const { return static_cast(itemMap.value("avatar_bmp"))->getData(); } }; @@ -63,13 +69,15 @@ public: class ServerInfo_Game : public SerializableItem_Map { public: - ServerInfo_Game(int _gameId = -1, const QString &_description = QString(), bool _hasPassword = false, int _playerCount = -1, int _maxPlayers = -1, const QList &_gameTypes = QList(), ServerInfo_User *creatorInfo = 0, bool _onlyBuddies = false, bool _onlyRegistered = false, bool _spectatorsAllowed = false, bool _spectatorsNeedPassword = false, int _spectatorCount = -1); + ServerInfo_Game(int _roomId = -1, int _gameId = -1, const QString &_description = QString(), bool _hasPassword = false, int _playerCount = -1, int _maxPlayers = -1, bool _started = false, const QList &_gameTypes = QList(), ServerInfo_User *creatorInfo = 0, bool _onlyBuddies = false, bool _onlyRegistered = false, bool _spectatorsAllowed = false, bool _spectatorsNeedPassword = false, int _spectatorCount = -1); static SerializableItem *newItem() { return new ServerInfo_Game; } + int getRoomId() const { return static_cast(itemMap.value("room_id"))->getData(); } int getGameId() const { return static_cast(itemMap.value("game_id"))->getData(); } QString getDescription() const { return static_cast(itemMap.value("description"))->getData(); } bool getHasPassword() const { return static_cast(itemMap.value("has_password"))->getData(); } int getPlayerCount() const { return static_cast(itemMap.value("player_count"))->getData(); } int getMaxPlayers() const { return static_cast(itemMap.value("max_players"))->getData(); } + bool getStarted() const { return static_cast(itemMap.value("started"))->getData(); } QList getGameTypes() const { return typecastItemList(); } ServerInfo_User *getCreatorInfo() const { return static_cast(itemMap.value("user")); } bool getOnlyBuddies() const { return static_cast(itemMap.value("only_buddies"))->getData(); } @@ -118,7 +126,7 @@ public: class ServerInfo_Card : public SerializableItem_Map { public: - ServerInfo_Card(int _id = -1, const QString &_name = QString(), int _x = -1, int _y = -1, bool _tapped = false, bool _attacking = false, const QString &_color = QString(), const QString &_pt = QString(), const QString &_annotation = QString(), bool _destroyOnZoneChange = false, const QList &_counterList = QList(), int attachPlayerId = -1, const QString &_attachZone = QString(), int attachCardId = -1); + ServerInfo_Card(int _id = -1, const QString &_name = QString(), int _x = -1, int _y = -1, bool _tapped = false, bool _attacking = false, const QString &_color = QString(), const QString &_pt = QString(), const QString &_annotation = QString(), bool _destroyOnZoneChange = false, bool _doesntUntap = false, const QList &_counterList = QList(), int attachPlayerId = -1, const QString &_attachZone = QString(), int attachCardId = -1); static SerializableItem *newItem() { return new ServerInfo_Card; } int getId() const { return static_cast(itemMap.value("id"))->getData(); } QString getName() const { return static_cast(itemMap.value("name"))->getData(); } @@ -130,6 +138,7 @@ public: QString getPT() const { return static_cast(itemMap.value("pt"))->getData(); } QString getAnnotation() const { return static_cast(itemMap.value("annotation"))->getData(); } bool getDestroyOnZoneChange() const { return static_cast(itemMap.value("destroy_on_zone_change"))->getData(); } + bool getDoesntUntap() const { return static_cast(itemMap.value("doesnt_untap"))->getData(); } QList getCounters() const { return typecastItemList(); } int getAttachPlayerId() const { return static_cast(itemMap.value("attach_player_id"))->getData(); } QString getAttachZone() const { return static_cast(itemMap.value("attach_zone"))->getData(); } diff --git a/common/protocol_item_ids.h b/common/protocol_item_ids.h index d45045d02..6d6cb37b1 100644 --- a/common/protocol_item_ids.h +++ b/common/protocol_item_ids.h @@ -3,80 +3,85 @@ ItemId_Command_Ping = 1001, ItemId_Command_Login = 1002, ItemId_Command_Message = 1003, ItemId_Command_ListUsers = 1004, -ItemId_Command_GetUserInfo = 1005, -ItemId_Command_AddToList = 1006, -ItemId_Command_RemoveFromList = 1007, -ItemId_Command_DeckList = 1008, -ItemId_Command_DeckNewDir = 1009, -ItemId_Command_DeckDelDir = 1010, -ItemId_Command_DeckDel = 1011, -ItemId_Command_DeckDownload = 1012, -ItemId_Command_ListRooms = 1013, -ItemId_Command_JoinRoom = 1014, -ItemId_Command_LeaveRoom = 1015, -ItemId_Command_RoomSay = 1016, -ItemId_Command_JoinGame = 1017, -ItemId_Command_KickFromGame = 1018, -ItemId_Command_LeaveGame = 1019, -ItemId_Command_Say = 1020, -ItemId_Command_Shuffle = 1021, -ItemId_Command_Mulligan = 1022, -ItemId_Command_RollDie = 1023, -ItemId_Command_DrawCards = 1024, -ItemId_Command_UndoDraw = 1025, -ItemId_Command_FlipCard = 1026, -ItemId_Command_AttachCard = 1027, -ItemId_Command_CreateToken = 1028, -ItemId_Command_CreateArrow = 1029, -ItemId_Command_DeleteArrow = 1030, -ItemId_Command_SetCardAttr = 1031, -ItemId_Command_SetCardCounter = 1032, -ItemId_Command_IncCardCounter = 1033, -ItemId_Command_ReadyStart = 1034, -ItemId_Command_Concede = 1035, -ItemId_Command_IncCounter = 1036, -ItemId_Command_CreateCounter = 1037, -ItemId_Command_SetCounter = 1038, -ItemId_Command_DelCounter = 1039, -ItemId_Command_NextTurn = 1040, -ItemId_Command_SetActivePhase = 1041, -ItemId_Command_DumpZone = 1042, -ItemId_Command_StopDumpZone = 1043, -ItemId_Command_RevealCards = 1044, -ItemId_Event_Say = 1045, -ItemId_Event_Leave = 1046, -ItemId_Event_GameClosed = 1047, -ItemId_Event_Kicked = 1048, -ItemId_Event_Shuffle = 1049, -ItemId_Event_RollDie = 1050, -ItemId_Event_MoveCard = 1051, -ItemId_Event_FlipCard = 1052, -ItemId_Event_DestroyCard = 1053, -ItemId_Event_AttachCard = 1054, -ItemId_Event_CreateToken = 1055, -ItemId_Event_DeleteArrow = 1056, -ItemId_Event_SetCardAttr = 1057, -ItemId_Event_SetCardCounter = 1058, -ItemId_Event_SetCounter = 1059, -ItemId_Event_DelCounter = 1060, -ItemId_Event_SetActivePlayer = 1061, -ItemId_Event_SetActivePhase = 1062, -ItemId_Event_DumpZone = 1063, -ItemId_Event_StopDumpZone = 1064, -ItemId_Event_RemoveFromList = 1065, -ItemId_Event_ServerMessage = 1066, -ItemId_Event_ConnectionClosed = 1067, -ItemId_Event_Message = 1068, -ItemId_Event_GameJoined = 1069, -ItemId_Event_UserLeft = 1070, -ItemId_Event_LeaveRoom = 1071, -ItemId_Event_RoomSay = 1072, -ItemId_Context_ReadyStart = 1073, -ItemId_Context_Concede = 1074, -ItemId_Context_DeckSelect = 1075, -ItemId_Context_UndoDraw = 1076, -ItemId_Context_MoveCard = 1077, -ItemId_Command_UpdateServerMessage = 1078, -ItemId_Command_BanFromServer = 1079, -ItemId_Other = 1080 +ItemId_Command_GetGamesOfUser = 1005, +ItemId_Command_GetUserInfo = 1006, +ItemId_Command_AddToList = 1007, +ItemId_Command_RemoveFromList = 1008, +ItemId_Command_DeckList = 1009, +ItemId_Command_DeckNewDir = 1010, +ItemId_Command_DeckDelDir = 1011, +ItemId_Command_DeckDel = 1012, +ItemId_Command_DeckDownload = 1013, +ItemId_Command_ListRooms = 1014, +ItemId_Command_JoinRoom = 1015, +ItemId_Command_LeaveRoom = 1016, +ItemId_Command_RoomSay = 1017, +ItemId_Command_JoinGame = 1018, +ItemId_Command_KickFromGame = 1019, +ItemId_Command_LeaveGame = 1020, +ItemId_Command_Say = 1021, +ItemId_Command_Shuffle = 1022, +ItemId_Command_Mulligan = 1023, +ItemId_Command_RollDie = 1024, +ItemId_Command_DrawCards = 1025, +ItemId_Command_UndoDraw = 1026, +ItemId_Command_FlipCard = 1027, +ItemId_Command_AttachCard = 1028, +ItemId_Command_CreateToken = 1029, +ItemId_Command_CreateArrow = 1030, +ItemId_Command_DeleteArrow = 1031, +ItemId_Command_SetCardAttr = 1032, +ItemId_Command_SetCardCounter = 1033, +ItemId_Command_IncCardCounter = 1034, +ItemId_Command_ReadyStart = 1035, +ItemId_Command_Concede = 1036, +ItemId_Command_IncCounter = 1037, +ItemId_Command_CreateCounter = 1038, +ItemId_Command_SetCounter = 1039, +ItemId_Command_DelCounter = 1040, +ItemId_Command_NextTurn = 1041, +ItemId_Command_SetActivePhase = 1042, +ItemId_Command_DumpZone = 1043, +ItemId_Command_StopDumpZone = 1044, +ItemId_Command_RevealCards = 1045, +ItemId_Event_ConnectionStateChanged = 1046, +ItemId_Event_Say = 1047, +ItemId_Event_Leave = 1048, +ItemId_Event_GameClosed = 1049, +ItemId_Event_Kicked = 1050, +ItemId_Event_Shuffle = 1051, +ItemId_Event_RollDie = 1052, +ItemId_Event_MoveCard = 1053, +ItemId_Event_FlipCard = 1054, +ItemId_Event_DestroyCard = 1055, +ItemId_Event_AttachCard = 1056, +ItemId_Event_CreateToken = 1057, +ItemId_Event_DeleteArrow = 1058, +ItemId_Event_SetCardAttr = 1059, +ItemId_Event_SetCardCounter = 1060, +ItemId_Event_SetCounter = 1061, +ItemId_Event_DelCounter = 1062, +ItemId_Event_SetActivePlayer = 1063, +ItemId_Event_SetActivePhase = 1064, +ItemId_Event_DumpZone = 1065, +ItemId_Event_StopDumpZone = 1066, +ItemId_Event_RemoveFromList = 1067, +ItemId_Event_ServerMessage = 1068, +ItemId_Event_ServerShutdown = 1069, +ItemId_Event_ConnectionClosed = 1070, +ItemId_Event_Message = 1071, +ItemId_Event_GameJoined = 1072, +ItemId_Event_UserLeft = 1073, +ItemId_Event_LeaveRoom = 1074, +ItemId_Event_RoomSay = 1075, +ItemId_Context_ReadyStart = 1076, +ItemId_Context_Concede = 1077, +ItemId_Context_DeckSelect = 1078, +ItemId_Context_UndoDraw = 1079, +ItemId_Context_MoveCard = 1080, +ItemId_Context_Mulligan = 1081, +ItemId_Command_UpdateServerMessage = 1082, +ItemId_Command_ShutdownServer = 1083, +ItemId_Command_BanFromServer = 1084, +ItemId_Other = 1085 }; diff --git a/common/protocol_items.cpp b/common/protocol_items.cpp index c75a991ed..db7ffc1a2 100644 --- a/common/protocol_items.cpp +++ b/common/protocol_items.cpp @@ -21,6 +21,11 @@ Command_ListUsers::Command_ListUsers() : Command("list_users") { } +Command_GetGamesOfUser::Command_GetGamesOfUser(const QString &_userName) + : Command("get_games_of_user") +{ + insertItem(new SerializableItem_String("user_name", _userName)); +} Command_GetUserInfo::Command_GetUserInfo(const QString &_userName) : Command("get_user_info") { @@ -255,6 +260,11 @@ Command_RevealCards::Command_RevealCards(int _gameId, const QString &_zoneName, insertItem(new SerializableItem_Int("card_id", _cardId)); insertItem(new SerializableItem_Int("player_id", _playerId)); } +Event_ConnectionStateChanged::Event_ConnectionStateChanged(int _playerId, bool _connected) + : GameEvent("connection_state_changed", _playerId) +{ + insertItem(new SerializableItem_Bool("connected", _connected)); +} Event_Say::Event_Say(int _playerId, const QString &_message) : GameEvent("say", _playerId) { @@ -398,6 +408,12 @@ Event_ServerMessage::Event_ServerMessage(const QString &_message) { insertItem(new SerializableItem_String("message", _message)); } +Event_ServerShutdown::Event_ServerShutdown(const QString &_reason, int _minutes) + : GenericEvent("server_shutdown") +{ + insertItem(new SerializableItem_String("reason", _reason)); + insertItem(new SerializableItem_Int("minutes", _minutes)); +} Event_ConnectionClosed::Event_ConnectionClosed(const QString &_reason) : GenericEvent("connection_closed") { @@ -458,15 +474,27 @@ Context_MoveCard::Context_MoveCard() : GameEventContext("move_card") { } +Context_Mulligan::Context_Mulligan(int _number) + : GameEventContext("mulligan") +{ + insertItem(new SerializableItem_Int("number", _number)); +} Command_UpdateServerMessage::Command_UpdateServerMessage() : AdminCommand("update_server_message") { } -Command_BanFromServer::Command_BanFromServer(const QString &_userName, int _minutes) - : AdminCommand("ban_from_server") +Command_ShutdownServer::Command_ShutdownServer(const QString &_reason, int _minutes) + : AdminCommand("shutdown_server") +{ + insertItem(new SerializableItem_String("reason", _reason)); + insertItem(new SerializableItem_Int("minutes", _minutes)); +} +Command_BanFromServer::Command_BanFromServer(const QString &_userName, int _minutes, const QString &_reason) + : ModeratorCommand("ban_from_server") { insertItem(new SerializableItem_String("user_name", _userName)); insertItem(new SerializableItem_Int("minutes", _minutes)); + insertItem(new SerializableItem_String("reason", _reason)); } void ProtocolItem::initializeHashAuto() { @@ -474,6 +502,7 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("cmdlogin", Command_Login::newItem); itemNameHash.insert("cmdmessage", Command_Message::newItem); itemNameHash.insert("cmdlist_users", Command_ListUsers::newItem); + itemNameHash.insert("cmdget_games_of_user", Command_GetGamesOfUser::newItem); itemNameHash.insert("cmdget_user_info", Command_GetUserInfo::newItem); itemNameHash.insert("cmdadd_to_list", Command_AddToList::newItem); itemNameHash.insert("cmdremove_from_list", Command_RemoveFromList::newItem); @@ -514,6 +543,7 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("cmddump_zone", Command_DumpZone::newItem); itemNameHash.insert("cmdstop_dump_zone", Command_StopDumpZone::newItem); itemNameHash.insert("cmdreveal_cards", Command_RevealCards::newItem); + itemNameHash.insert("game_eventconnection_state_changed", Event_ConnectionStateChanged::newItem); itemNameHash.insert("game_eventsay", Event_Say::newItem); itemNameHash.insert("game_eventleave", Event_Leave::newItem); itemNameHash.insert("game_eventgame_closed", Event_GameClosed::newItem); @@ -536,6 +566,7 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("game_eventstop_dump_zone", Event_StopDumpZone::newItem); itemNameHash.insert("generic_eventremove_from_list", Event_RemoveFromList::newItem); itemNameHash.insert("generic_eventserver_message", Event_ServerMessage::newItem); + itemNameHash.insert("generic_eventserver_shutdown", Event_ServerShutdown::newItem); itemNameHash.insert("generic_eventconnection_closed", Event_ConnectionClosed::newItem); itemNameHash.insert("generic_eventmessage", Event_Message::newItem); itemNameHash.insert("generic_eventgame_joined", Event_GameJoined::newItem); @@ -547,6 +578,8 @@ void ProtocolItem::initializeHashAuto() itemNameHash.insert("game_event_contextdeck_select", Context_DeckSelect::newItem); itemNameHash.insert("game_event_contextundo_draw", Context_UndoDraw::newItem); itemNameHash.insert("game_event_contextmove_card", Context_MoveCard::newItem); + itemNameHash.insert("game_event_contextmulligan", Context_Mulligan::newItem); itemNameHash.insert("cmdupdate_server_message", Command_UpdateServerMessage::newItem); + itemNameHash.insert("cmdshutdown_server", Command_ShutdownServer::newItem); itemNameHash.insert("cmdban_from_server", Command_BanFromServer::newItem); } diff --git a/common/protocol_items.dat b/common/protocol_items.dat index 4e37333df..716959329 100644 --- a/common/protocol_items.dat +++ b/common/protocol_items.dat @@ -2,6 +2,7 @@ 0:login:s,username:s,password 0:message:s,user_name:s,text 0:list_users +0:get_games_of_user:s,user_name 0:get_user_info:s,user_name 0:add_to_list:s,list:s,user_name 0:remove_from_list:s,list:s,user_name @@ -42,6 +43,7 @@ 2:dump_zone:i,player_id:s,zone_name:i,number_cards 2:stop_dump_zone:i,player_id:s,zone_name 2:reveal_cards:s,zone_name:i,card_id:i,player_id +3:connection_state_changed:b,connected 3:say:s,message 3:leave 3:game_closed @@ -64,6 +66,7 @@ 3:stop_dump_zone:i,zone_owner_id:s,zone 4:remove_from_list:s,list:s,user_name 4:server_message:s,message +4:server_shutdown:s,reason:i,minutes 4:connection_closed:s,reason 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 @@ -75,5 +78,7 @@ 6:deck_select:i,deck_id 6:undo_draw 6:move_card +6:mulligan:i,number 7:update_server_message -7:ban_from_server:s,user_name:i,minutes \ No newline at end of file +7:shutdown_server:s,reason:i,minutes +8:ban_from_server:s,user_name:i,minutes:s,reason \ No newline at end of file diff --git a/common/protocol_items.h b/common/protocol_items.h index 14d6eb1ff..48401ee3b 100644 --- a/common/protocol_items.h +++ b/common/protocol_items.h @@ -35,6 +35,14 @@ public: static SerializableItem *newItem() { return new Command_ListUsers; } int getItemId() const { return ItemId_Command_ListUsers; } }; +class Command_GetGamesOfUser : public Command { + Q_OBJECT +public: + Command_GetGamesOfUser(const QString &_userName = QString()); + QString getUserName() const { return static_cast(itemMap.value("user_name"))->getData(); }; + static SerializableItem *newItem() { return new Command_GetGamesOfUser; } + int getItemId() const { return ItemId_Command_GetGamesOfUser; } +}; class Command_GetUserInfo : public Command { Q_OBJECT public: @@ -389,6 +397,14 @@ public: static SerializableItem *newItem() { return new Command_RevealCards; } int getItemId() const { return ItemId_Command_RevealCards; } }; +class Event_ConnectionStateChanged : public GameEvent { + Q_OBJECT +public: + Event_ConnectionStateChanged(int _playerId = -1, bool _connected = false); + bool getConnected() const { return static_cast(itemMap.value("connected"))->getData(); }; + static SerializableItem *newItem() { return new Event_ConnectionStateChanged; } + int getItemId() const { return ItemId_Event_ConnectionStateChanged; } +}; class Event_Say : public GameEvent { Q_OBJECT public: @@ -598,6 +614,15 @@ public: static SerializableItem *newItem() { return new Event_ServerMessage; } int getItemId() const { return ItemId_Event_ServerMessage; } }; +class Event_ServerShutdown : public GenericEvent { + Q_OBJECT +public: + Event_ServerShutdown(const QString &_reason = QString(), int _minutes = -1); + QString getReason() const { return static_cast(itemMap.value("reason"))->getData(); }; + int getMinutes() const { return static_cast(itemMap.value("minutes"))->getData(); }; + static SerializableItem *newItem() { return new Event_ServerShutdown; } + int getItemId() const { return ItemId_Event_ServerShutdown; } +}; class Event_ConnectionClosed : public GenericEvent { Q_OBJECT public: @@ -691,6 +716,14 @@ public: static SerializableItem *newItem() { return new Context_MoveCard; } int getItemId() const { return ItemId_Context_MoveCard; } }; +class Context_Mulligan : public GameEventContext { + Q_OBJECT +public: + Context_Mulligan(int _number = -1); + int getNumber() const { return static_cast(itemMap.value("number"))->getData(); }; + static SerializableItem *newItem() { return new Context_Mulligan; } + int getItemId() const { return ItemId_Context_Mulligan; } +}; class Command_UpdateServerMessage : public AdminCommand { Q_OBJECT public: @@ -698,12 +731,22 @@ public: static SerializableItem *newItem() { return new Command_UpdateServerMessage; } int getItemId() const { return ItemId_Command_UpdateServerMessage; } }; -class Command_BanFromServer : public AdminCommand { +class Command_ShutdownServer : public AdminCommand { Q_OBJECT public: - Command_BanFromServer(const QString &_userName = QString(), int _minutes = -1); + Command_ShutdownServer(const QString &_reason = QString(), int _minutes = -1); + QString getReason() const { return static_cast(itemMap.value("reason"))->getData(); }; + int getMinutes() const { return static_cast(itemMap.value("minutes"))->getData(); }; + static SerializableItem *newItem() { return new Command_ShutdownServer; } + int getItemId() const { return ItemId_Command_ShutdownServer; } +}; +class Command_BanFromServer : public ModeratorCommand { + Q_OBJECT +public: + Command_BanFromServer(const QString &_userName = QString(), int _minutes = -1, const QString &_reason = QString()); QString getUserName() const { return static_cast(itemMap.value("user_name"))->getData(); }; int getMinutes() const { return static_cast(itemMap.value("minutes"))->getData(); }; + QString getReason() const { return static_cast(itemMap.value("reason"))->getData(); }; static SerializableItem *newItem() { return new Command_BanFromServer; } int getItemId() const { return ItemId_Command_BanFromServer; } }; diff --git a/common/protocol_mc.pl b/common/protocol_mc.pl index 31e85b1ff..2b1c96b76 100755 --- a/common/protocol_mc.pl +++ b/common/protocol_mc.pl @@ -80,6 +80,13 @@ while () { $parentConstructorCall = "$baseClass(\"$name1\")"; $constructorParamsH = ""; $constructorParamsCpp = ""; + } elsif ($type == 8) { + $type = 'cmd'; + $namePrefix = 'Command'; + $baseClass = 'ModeratorCommand'; + $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 9c1a7c81c..42c142514 100644 --- a/common/serializable_item.cpp +++ b/common/serializable_item.cpp @@ -1,7 +1,8 @@ #include "serializable_item.h" #include #include -#include +#include + QHash SerializableItem::itemNameHash; SerializableItem *SerializableItem::getNewItem(const QString &name) @@ -16,6 +17,32 @@ void SerializableItem::registerSerializableItem(const QString &name, NewItemFunc itemNameHash.insert(name, func); } +bool SerializableItem::read(QXmlStreamReader *xml) +{ + if (!compressed) + return readElement(xml); + if (xml->isEndElement() && (xml->name() == itemType)) { + QByteArray uncompressedData = "" + qUncompress(QByteArray::fromBase64(compressedData)) + ""; + compressedData.clear(); + QBuffer compressedBuffer(&uncompressedData); + compressedBuffer.open(QIODevice::ReadOnly); + QXmlStreamReader *xml2 = new QXmlStreamReader(&compressedBuffer); + while (!xml2->atEnd()) { + xml2->readNext(); + if (xml2->name() == "d") + continue; + readElement(xml2); + } + delete xml2; + compressedBuffer.close(); + + return readElement(xml); + } else { + compressedData.append(xml->text().toString()); + return false; + } +} + bool SerializableItem::readElement(QXmlStreamReader *xml) { if (xml->isEndElement() && (xml->name() == itemType)) @@ -31,7 +58,19 @@ void SerializableItem::write(QXmlStreamWriter *xml) xml->writeStartElement(itemType); if (!itemSubType.isEmpty()) xml->writeAttribute("type", itemSubType); - writeElement(xml); + if (compressed) { + xml->writeAttribute("comp", "1"); + + QBuffer compressBuffer; + compressBuffer.open(QIODevice::WriteOnly); + QXmlStreamWriter *xml2 = new QXmlStreamWriter(&compressBuffer); + writeElement(xml2); + delete xml2; + compressBuffer.close(); + + xml->writeCharacters(qCompress(compressBuffer.data()).toBase64()); + } else + writeElement(xml); xml->writeEndElement(); } @@ -47,7 +86,7 @@ SerializableItem_Map::~SerializableItem_Map() bool SerializableItem_Map::readElement(QXmlStreamReader *xml) { if (currentItem) { - if (currentItem->readElement(xml)) + if (currentItem->read(xml)) currentItem = 0; return false; } else if (firstItem) @@ -57,6 +96,7 @@ bool SerializableItem_Map::readElement(QXmlStreamReader *xml) else if (xml->isStartElement()) { QString childName = xml->name().toString(); QString childSubType = xml->attributes().value("type").toString(); + bool childCompressed = xml->attributes().value("comp").toString().toInt() == 1; currentItem = itemMap.value(childName); if (!currentItem) { currentItem = getNewItem(childName + childSubType); @@ -64,7 +104,8 @@ bool SerializableItem_Map::readElement(QXmlStreamReader *xml) if (!currentItem) currentItem = new SerializableItem_Invalid(childName); } - if (currentItem->readElement(xml)) + currentItem->setCompressed(childCompressed); + if (currentItem->read(xml)) currentItem = 0; } return SerializableItem::readElement(xml); diff --git a/common/serializable_item.h b/common/serializable_item.h index 979ebb981..50da5e368 100644 --- a/common/serializable_item.h +++ b/common/serializable_item.h @@ -15,6 +15,10 @@ class QXmlStreamWriter; class SerializableItem : public QObject { Q_OBJECT +private: + bool compressed; + QByteArray compressedData; + QXmlStreamReader *compressedReader; protected: typedef SerializableItem *(*NewItemFunction)(); static QHash itemNameHash; @@ -23,7 +27,7 @@ protected: bool firstItem; public: SerializableItem(const QString &_itemType, const QString &_itemSubType = QString()) - : QObject(), itemType(_itemType), itemSubType(_itemSubType), firstItem(true) { } + : QObject(), compressed(false), itemType(_itemType), itemSubType(_itemSubType), firstItem(true) { } static void registerSerializableItem(const QString &name, NewItemFunction func); static SerializableItem *getNewItem(const QString &name); const QString &getItemType() const { return itemType; } @@ -31,6 +35,8 @@ public: virtual bool readElement(QXmlStreamReader *xml); virtual void writeElement(QXmlStreamWriter *xml) = 0; virtual bool isEmpty() const = 0; + void setCompressed(bool _compressed) { compressed = _compressed; } + bool read(QXmlStreamReader *xml); void write(QXmlStreamWriter *xml); }; diff --git a/common/server.cpp b/common/server.cpp index ab5ca8b52..704510181 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -23,34 +23,42 @@ #include "server_room.h" #include "server_protocolhandler.h" #include "protocol_datastructures.h" +#include #include Server::Server(QObject *parent) - : QObject(parent), nextGameId(0) + : QObject(parent), serverMutex(QMutex::Recursive), nextGameId(0) { } Server::~Server() { +} + +void Server::prepareDestroy() +{ + QMutexLocker locker(&serverMutex); + while (!clients.isEmpty()) delete clients.takeFirst(); + + QMapIterator roomIterator(rooms); + while (roomIterator.hasNext()) + delete roomIterator.next().value(); } AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password) { + QMutexLocker locker(&serverMutex); if (name.size() > 35) name = name.left(35); - AuthenticationResult authState = checkUserPassword(name, password); + AuthenticationResult authState = checkUserPassword(session, name, password); if (authState == PasswordWrong) return authState; if (authState == PasswordRight) { - Server_ProtocolHandler *oldSession = users.value(name); - if (oldSession) { - if (!(oldSession->getUserInfo()->getUserLevel() & ServerInfo_User::IsRegistered)) - return WouldOverwriteOldSession; - delete oldSession; // ~Server_ProtocolHandler() will call Server::removeClient - } + if (users.contains(name)) + return WouldOverwriteOldSession; } else if (authState == UnknownUser) { // Change user name so that no two users have the same names, // don't interfere with registered user names though. @@ -66,6 +74,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString session->setUserInfo(data); users.insert(name, session); + qDebug() << "Server::loginUser: name=" << name; Event_UserJoined *event = new Event_UserJoined(new ServerInfo_User(data, false)); for (int i = 0; i < clients.size(); ++i) @@ -78,11 +87,13 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString void Server::addClient(Server_ProtocolHandler *client) { + QMutexLocker locker(&serverMutex); clients << client; } void Server::removeClient(Server_ProtocolHandler *client) { + QMutexLocker locker(&serverMutex); clients.removeAt(clients.indexOf(client)); ServerInfo_User *data = client->getUserInfo(); if (data) { @@ -93,20 +104,19 @@ void Server::removeClient(Server_ProtocolHandler *client) delete event; users.remove(data->getName()); + qDebug() << "Server::removeClient: name=" << data->getName(); } - qDebug() << "Server::removeClient: " << clients.size() << "clients; " << users.size() << "users left"; -} - -Server_Game *Server::getGame(int gameId) const -{ - return games.value(gameId); + qDebug() << "Server::removeClient:" << clients.size() << "clients; " << users.size() << "users left"; } void Server::broadcastRoomUpdate() { + QMutexLocker locker(&serverMutex); Server_Room *room = static_cast(sender()); QList eventRoomList; + room->roomMutex.lock(); eventRoomList.append(new ServerInfo_Room(room->getId(), room->getName(), room->getDescription(), room->getGames().size(), room->size(), room->getAutoJoin())); + room->roomMutex.unlock(); Event_ListRooms *event = new Event_ListRooms(eventRoomList); for (int i = 0; i < clients.size(); ++i) @@ -115,21 +125,28 @@ void Server::broadcastRoomUpdate() delete event; } -void Server::gameCreated(Server_Game *game) -{ - games.insert(game->getGameId(), game); -} - -void Server::gameClosing(int gameId) -{ - qDebug("Server::gameClosing"); - games.remove(gameId); -} - void Server::addRoom(Server_Room *newRoom) { + QMutexLocker locker(&serverMutex); 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))); +} + +int Server::getUsersCount() const +{ + QMutexLocker locker(&serverMutex); + return users.size(); +} + +int Server::getGamesCount() const +{ + int result = 0; + QMutexLocker locker(&serverMutex); + QMapIterator roomIterator(rooms); + while (roomIterator.hasNext()) { + Server_Room *room = roomIterator.next().value(); + QMutexLocker roomLocker(&room->roomMutex); + result += room->getGames().size(); + } + return result; } diff --git a/common/server.h b/common/server.h index 552fd8ea8..de8dd2a5f 100644 --- a/common/server.h +++ b/common/server.h @@ -4,6 +4,7 @@ #include #include #include +#include class Server_Game; class Server_Room; @@ -18,15 +19,12 @@ class Server : public QObject signals: void pingClockTimeout(); private slots: - void gameCreated(Server_Game *game); - void gameClosing(int gameId); void broadcastRoomUpdate(); public: + mutable QMutex serverMutex; 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 &getRooms() { return rooms; } int getNextGameId() { return nextGameId++; } @@ -41,19 +39,22 @@ public: virtual int getMessageCountingInterval() const { return 0; } virtual int getMaxMessageCountPerInterval() const { return 0; } virtual int getMaxMessageSizePerInterval() const { return 0; } + virtual int getMaxGamesPerUser() const { return 0; } + virtual bool getThreaded() const = 0; virtual QMap getBuddyList(const QString &name) = 0; virtual QMap getIgnoreList(const QString &name) = 0; - virtual bool getUserBanned(Server_ProtocolHandler * /*client*/, const QString & /*userName*/) const { return false; } protected: - QMap games; + void prepareDestroy(); QList clients; QMap users; QMap rooms; virtual bool userExists(const QString &user) = 0; - virtual AuthenticationResult checkUserPassword(const QString &user, const QString &password) = 0; + virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password) = 0; virtual ServerInfo_User *getUserData(const QString &name) = 0; + int getUsersCount() const; + int getGamesCount() const; int nextGameId; void addRoom(Server_Room *newRoom); }; diff --git a/common/server_card.cpp b/common/server_card.cpp index 4c47f20d2..6cafdd903 100644 --- a/common/server_card.cpp +++ b/common/server_card.cpp @@ -19,8 +19,8 @@ ***************************************************************************/ #include "server_card.h" -Server_Card::Server_Card(QString _name, int _id, int _coord_x, int _coord_y) - : id(_id), coord_x(_coord_x), coord_y(_coord_y), name(_name), tapped(false), attacking(false), facedown(false), color(QString()), power(-1), toughness(-1), annotation(QString()), destroyOnZoneChange(false), doesntUntap(false), parentCard(0) +Server_Card::Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone) + : zone(_zone), id(_id), coord_x(_coord_x), coord_y(_coord_y), name(_name), tapped(false), attacking(false), facedown(false), color(QString()), power(-1), toughness(-1), annotation(QString()), destroyOnZoneChange(false), doesntUntap(false), parentCard(0) { } @@ -39,8 +39,8 @@ void Server_Card::resetState() counters.clear(); setTapped(false); setAttacking(false); - power = 0; - toughness = 0; + power = -1; + toughness = -1; setAnnotation(QString()); setDoesntUntap(false); } diff --git a/common/server_card.h b/common/server_card.h index de84d21ce..a908befaf 100644 --- a/common/server_card.h +++ b/common/server_card.h @@ -46,7 +46,7 @@ private: Server_Card *parentCard; QList attachedCards; public: - Server_Card(QString _name, int _id, int _coord_x, int _coord_y); + Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone = 0); ~Server_Card(); Server_CardZone *getZone() const { return zone; } diff --git a/common/server_cardzone.cpp b/common/server_cardzone.cpp index 6e70a9a16..dd1db3eee 100644 --- a/common/server_cardzone.cpp +++ b/common/server_cardzone.cpp @@ -23,6 +23,7 @@ #include "rng_abstract.h" #include #include +#include "server_game.h" 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) @@ -37,6 +38,8 @@ Server_CardZone::~Server_CardZone() void Server_CardZone::shuffle() { + QMutexLocker locker(&player->getGame()->gameMutex); + QList temp; for (int i = cards.size(); i; i--) temp.append(cards.takeAt(rng->getNumber(0, i - 1))); @@ -45,23 +48,25 @@ void Server_CardZone::shuffle() int Server_CardZone::removeCard(Server_Card *card) { + QMutexLocker locker(&player->getGame()->gameMutex); + int index = cards.indexOf(card); cards.removeAt(index); + card->setZone(0); + return index; } -Server_Card *Server_CardZone::getCard(int id, bool remove, int *position) +Server_Card *Server_CardZone::getCard(int id, int *position) { + QMutexLocker locker(&player->getGame()->gameMutex); + if (type != HiddenZone) { QListIterator CardIterator(cards); int i = 0; while (CardIterator.hasNext()) { Server_Card *tmp = CardIterator.next(); if (tmp->getId() == id) { - if (remove) { - cards.removeAt(i); - tmp->setZone(0); - } if (position) *position = i; return tmp; @@ -73,10 +78,6 @@ Server_Card *Server_CardZone::getCard(int id, bool remove, int *position) if ((id >= cards.size()) || (id < 0)) return NULL; Server_Card *tmp = cards[id]; - if (remove) { - cards.removeAt(id); - tmp->setZone(0); - } if (position) *position = id; return tmp; @@ -85,6 +86,8 @@ Server_Card *Server_CardZone::getCard(int id, bool remove, int *position) int Server_CardZone::getFreeGridColumn(int x, int y, const QString &cardName) const { + QMutexLocker locker(&player->getGame()->gameMutex); + QMap coordMap; for (int i = 0; i < cards.size(); ++i) if (cards[i]->getY() == y) @@ -131,6 +134,8 @@ bool Server_CardZone::isColumnStacked(int x, int y) const if (!has_coords) return false; + QMutexLocker locker(&player->getGame()->gameMutex); + QMap coordMap; for (int i = 0; i < cards.size(); ++i) if (cards[i]->getY() == y) @@ -144,6 +149,8 @@ bool Server_CardZone::isColumnEmpty(int x, int y) const if (!has_coords) return true; + QMutexLocker locker(&player->getGame()->gameMutex); + QMap coordMap; for (int i = 0; i < cards.size(); ++i) if (cards[i]->getY() == y) @@ -154,6 +161,8 @@ bool Server_CardZone::isColumnEmpty(int x, int y) const void Server_CardZone::moveCard(CommandContainer *cont, QMap &coordMap, Server_Card *card, int x, int y) { + QMutexLocker locker(&player->getGame()->gameMutex); + coordMap.remove(card->getY() * 10000 + card->getX()); CardToMove *cardToMove = new CardToMove(card->getId()); @@ -165,6 +174,8 @@ void Server_CardZone::moveCard(CommandContainer *cont, QMap void Server_CardZone::fixFreeSpaces(CommandContainer *cont) { + QMutexLocker locker(&player->getGame()->gameMutex); + QMap coordMap; QSet placesToLook; for (int i = 0; i < cards.size(); ++i) { @@ -194,6 +205,8 @@ void Server_CardZone::fixFreeSpaces(CommandContainer *cont) void Server_CardZone::insertCard(Server_Card *card, int x, int y) { + QMutexLocker locker(&player->getGame()->gameMutex); + if (hasCoords()) { card->setCoords(x, y); cards.append(card); @@ -206,6 +219,8 @@ void Server_CardZone::insertCard(Server_Card *card, int x, int y) void Server_CardZone::clear() { + QMutexLocker locker(&player->getGame()->gameMutex); + for (int i = 0; i < cards.size(); i++) delete cards.at(i); cards.clear(); diff --git a/common/server_cardzone.h b/common/server_cardzone.h index 62a129a1d..898e89c78 100644 --- a/common/server_cardzone.h +++ b/common/server_cardzone.h @@ -41,7 +41,7 @@ public: ~Server_CardZone(); int removeCard(Server_Card *card); - Server_Card *getCard(int id, bool remove, int *position = NULL); + Server_Card *getCard(int id, int *position = NULL); int getCardsBeingLookedAt() const { return cardsBeingLookedAt; } void setCardsBeingLookedAt(int _cardsBeingLookedAt) { cardsBeingLookedAt = _cardsBeingLookedAt; } diff --git a/common/server_game.cpp b/common/server_game.cpp index 92501dfe0..5838e3f97 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -28,12 +28,14 @@ #include #include -Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, 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), gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies), onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0), secondsElapsed(0) +Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *_room) + : QObject(), room(_room), creatorInfo(new ServerInfo_User(_creator->getUserInfo())), gameStarted(false), gameId(_gameId), description(_description), password(_password), maxPlayers(_maxPlayers), gameTypes(_gameTypes), activePlayer(-1), activePhase(-1), onlyBuddies(_onlyBuddies), onlyRegistered(_onlyRegistered), spectatorsAllowed(_spectatorsAllowed), spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0), secondsElapsed(0), gameMutex(QMutex::Recursive) { + connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection); + addPlayer(_creator, false, false); - if (parent->getServer()->getGameShouldPing()) { + if (room->getServer()->getGameShouldPing()) { pingClock = new QTimer(this); connect(pingClock, SIGNAL(timeout()), this, SLOT(pingClockTimeout())); pingClock->start(1000); @@ -42,27 +44,34 @@ Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QS Server_Game::~Server_Game() { + QMutexLocker roomLocker(&room->roomMutex); + QMutexLocker locker(&gameMutex); + sendGameEvent(new Event_GameClosed); QMapIterator playerIterator(players); while (playerIterator.hasNext()) - delete playerIterator.next().value(); + playerIterator.next().value()->prepareDestroy(); players.clear(); - emit gameClosing(); + room->removeGame(this); delete creatorInfo; qDebug("Server_Game destructor"); } void Server_Game::pingClockTimeout() { + QMutexLocker locker(&gameMutex); ++secondsElapsed; QList pingList; QMapIterator playerIterator(players); bool allPlayersInactive = true; + int playerCount = 0; while (playerIterator.hasNext()) { Server_Player *player = playerIterator.next().value(); + if (!player->getSpectator()) + ++playerCount; int pingTime; if (player->getProtocolHandler()) { pingTime = player->getProtocolHandler()->getLastCommandTime(); @@ -73,9 +82,9 @@ void Server_Game::pingClockTimeout() } sendGameEvent(new Event_Ping(secondsElapsed, pingList)); - const int maxTime = static_cast(parent())->getServer()->getMaxGameInactivityTime(); + const int maxTime = room->getServer()->getMaxGameInactivityTime(); if (allPlayersInactive) { - if ((++inactivityCounter >= maxTime) && (maxTime > 0)) + if (((++inactivityCounter >= maxTime) && (maxTime > 0)) || (playerCount < maxPlayers)) deleteLater(); } else inactivityCounter = 0; @@ -83,6 +92,8 @@ void Server_Game::pingClockTimeout() int Server_Game::getPlayerCount() const { + QMutexLocker locker(&gameMutex); + QMapIterator playerIterator(players); int result = 0; while (playerIterator.hasNext()) @@ -93,6 +104,8 @@ int Server_Game::getPlayerCount() const int Server_Game::getSpectatorCount() const { + QMutexLocker locker(&gameMutex); + QMapIterator playerIterator(players); int result = 0; while (playerIterator.hasNext()) @@ -101,8 +114,10 @@ int Server_Game::getSpectatorCount() const return result; } -void Server_Game::startGameIfReady() +void Server_Game::doStartGameIfReady() { + QMutexLocker locker(&gameMutex); + if (getPlayerCount() < maxPlayers) return; QMapIterator playerIterator(players); @@ -145,10 +160,19 @@ void Server_Game::startGameIfReady() */ activePlayer = -1; nextTurn(); + + room->broadcastGameListUpdate(this); +} + +void Server_Game::startGameIfReady() +{ + emit sigStartGameIfReady(); } void Server_Game::stopGameIfFinished() { + QMutexLocker locker(&gameMutex); + QMapIterator playerIterator(players); int playing = 0; while (playerIterator.hasNext()) { @@ -179,9 +203,9 @@ ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_passw if (!(user->getUserLevel() & ServerInfo_User::IsRegistered) && onlyRegistered) return RespUserLevelTooLow; if (onlyBuddies) - if (!static_cast(parent())->getServer()->getBuddyList(creatorInfo->getName()).contains(user->getName())) + if (!room->getServer()->getBuddyList(creatorInfo->getName()).contains(user->getName())) return RespOnlyBuddies; - if (static_cast(parent())->getServer()->getIgnoreList(creatorInfo->getName()).contains(user->getName())) + if (room->getServer()->getIgnoreList(creatorInfo->getName()).contains(user->getName())) return RespInIgnoreList; if (spectator) { if (!spectatorsAllowed) @@ -192,30 +216,47 @@ ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_passw return RespOk; } +bool Server_Game::containsUser(const QString &userName) const +{ + QMutexLocker locker(&gameMutex); + + QMapIterator playerIterator(players); + while (playerIterator.hasNext()) + if (playerIterator.next().value()->getUserInfo()->getName() == userName) + return true; + return false; +} + Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spectator, bool broadcastUpdate) { + QMutexLocker locker(&gameMutex); + const QList &keyList = players.keys(); int playerId = keyList.isEmpty() ? 0 : (keyList.last() + 1); Server_Player *newPlayer = new Server_Player(this, playerId, handler->getUserInfo(), spectator, handler); + newPlayer->moveToThread(thread()); sendGameEvent(new Event_Join(newPlayer->getProperties())); players.insert(playerId, newPlayer); if (broadcastUpdate) - qobject_cast(parent())->broadcastGameListUpdate(this); + room->broadcastGameListUpdate(this); return newPlayer; } void Server_Game::removePlayer(Server_Player *player) { + QMutexLocker roomLocker(&room->roomMutex); + QMutexLocker locker(&gameMutex); + players.remove(player->getPlayerId()); removeArrowsToPlayer(player); sendGameEvent(new Event_Leave(player->getPlayerId())); bool playerActive = activePlayer == player->getPlayerId(); bool spectator = player->getSpectator(); - delete player; + player->prepareDestroy(); if (!getPlayerCount()) deleteLater(); @@ -224,11 +265,13 @@ void Server_Game::removePlayer(Server_Player *player) if (gameStarted && playerActive) nextTurn(); } - qobject_cast(parent())->broadcastGameListUpdate(this); + room->broadcastGameListUpdate(this); } void Server_Game::removeArrowsToPlayer(Server_Player *player) { + QMutexLocker locker(&gameMutex); + // Remove all arrows of other players pointing to the player being removed or to one of his cards. QMapIterator playerIterator(players); while (playerIterator.hasNext()) { @@ -253,6 +296,9 @@ void Server_Game::removeArrowsToPlayer(Server_Player *player) bool Server_Game::kickPlayer(int playerId) { + QMutexLocker roomLocker(&room->roomMutex); + QMutexLocker locker(&gameMutex); + Server_Player *playerToKick = players.value(playerId); if (!playerToKick) return false; @@ -265,6 +311,8 @@ bool Server_Game::kickPlayer(int playerId) void Server_Game::setActivePlayer(int _activePlayer) { + QMutexLocker locker(&gameMutex); + activePlayer = _activePlayer; sendGameEvent(new Event_SetActivePlayer(activePlayer, activePlayer)); setActivePhase(0); @@ -272,6 +320,8 @@ void Server_Game::setActivePlayer(int _activePlayer) void Server_Game::setActivePhase(int _activePhase) { + QMutexLocker locker(&gameMutex); + QMapIterator playerIterator(players); while (playerIterator.hasNext()) { Server_Player *player = playerIterator.next().value(); @@ -289,6 +339,8 @@ void Server_Game::setActivePhase(int _activePhase) void Server_Game::nextTurn() { + QMutexLocker locker(&gameMutex); + const QList keys = players.keys(); int listPos = -1; if (activePlayer != -1) @@ -302,8 +354,17 @@ void Server_Game::nextTurn() setActivePlayer(keys[listPos]); } +void Server_Game::postConnectionStatusUpdate(Server_Player *player, bool connectionStatus) +{ + QMutexLocker locker(&gameMutex); + + sendGameEvent(new Event_ConnectionStateChanged(player->getPlayerId(), connectionStatus)); +} + QList Server_Game::getGameState(Server_Player *playerWhosAsking) const { + QMutexLocker locker(&gameMutex); + QList result; QMapIterator playerIterator(players); while (playerIterator.hasNext()) { @@ -374,7 +435,7 @@ QList Server_Game::getGameState(Server_Player *playerWhosAs attachZone = card->getParentCard()->getZone()->getName(); attachCardId = card->getParentCard()->getId(); } - cardList.append(new ServerInfo_Card(card->getId(), displayedName, card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), cardCounterList, attachPlayerId, attachZone, attachCardId)); + cardList.append(new ServerInfo_Card(card->getId(), displayedName, card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), card->getDoesntUntap(), cardCounterList, attachPlayerId, attachZone, attachCardId)); } } zoneList.append(new ServerInfo_Zone(zone->getName(), zone->getType(), zone->hasCoords(), zone->cards.size(), cardList)); @@ -392,6 +453,8 @@ void Server_Game::sendGameEvent(GameEvent *event, GameEventContext *context, Ser void Server_Game::sendGameEventContainer(GameEventContainer *cont, Server_Player *exclude, bool excludeOmniscient) { + QMutexLocker locker(&gameMutex); + cont->setGameId(gameId); QMapIterator playerIterator(players); while (playerIterator.hasNext()) { @@ -405,6 +468,8 @@ void Server_Game::sendGameEventContainer(GameEventContainer *cont, Server_Player void Server_Game::sendGameEventContainerOmniscient(GameEventContainer *cont, Server_Player *exclude) { + QMutexLocker locker(&gameMutex); + cont->setGameId(gameId); QMapIterator playerIterator(players); while (playerIterator.hasNext()) { @@ -423,9 +488,11 @@ void Server_Game::sendGameEventToPlayer(Server_Player *player, GameEvent *event) ServerInfo_Game *Server_Game::getInfo() const { + QMutexLocker locker(&gameMutex); + if (players.isEmpty()) // Game is closing - return new ServerInfo_Game(getGameId(), QString(), false, 0, getMaxPlayers(), QList(), 0, false, 0); + return new ServerInfo_Game(room->getId(), getGameId(), QString(), false, 0, getMaxPlayers(), false, QList(), 0, false, 0); else { // Game is open @@ -434,11 +501,13 @@ ServerInfo_Game *Server_Game::getInfo() const gameTypeList.append(new GameTypeId(gameTypes[i])); return new ServerInfo_Game( + room->getId(), getGameId(), getDescription(), !getPassword().isEmpty(), getPlayerCount(), getMaxPlayers(), + gameStarted, gameTypeList, new ServerInfo_User(getCreatorInfo(), false), onlyBuddies, diff --git a/common/server_game.h b/common/server_game.h index 02e8ffdb0..f3d761f3e 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "server_player.h" #include "protocol.h" @@ -33,6 +34,7 @@ class ServerInfo_User; class Server_Game : public QObject { Q_OBJECT private: + Server_Room *room; ServerInfo_User *creatorInfo; QMap players; bool gameStarted; @@ -51,10 +53,12 @@ private: int secondsElapsed; QTimer *pingClock; signals: - void gameClosing(); + void sigStartGameIfReady(); private slots: void pingClockTimeout(); + void doStartGameIfReady(); public: + mutable QMutex gameMutex; Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *parent); ~Server_Game(); ServerInfo_Game *getInfo() const; @@ -73,6 +77,7 @@ public: bool getSpectatorsCanTalk() const { return spectatorsCanTalk; } bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; } ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator); + bool containsUser(const QString &userName) const; Server_Player *addPlayer(Server_ProtocolHandler *handler, bool spectator, bool broadcastUpdate = true); void removePlayer(Server_Player *player); void removeArrowsToPlayer(Server_Player *player); @@ -84,6 +89,7 @@ public: void setActivePlayer(int _activePlayer); void setActivePhase(int _activePhase); void nextTurn(); + void postConnectionStatusUpdate(Server_Player *player, bool connectionStatus); QList getGameState(Server_Player *playerWhosAsking) const; void sendGameEvent(GameEvent *event, GameEventContext *context = 0, Server_Player *exclude = 0); diff --git a/common/server_player.cpp b/common/server_player.cpp index ab29820f1..3a9899a97 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -17,22 +17,43 @@ Server_Player::Server_Player(Server_Game *_game, int _playerId, ServerInfo_User Server_Player::~Server_Player() { +} + +void Server_Player::prepareDestroy() +{ + QMutexLocker locker(&game->gameMutex); + delete deck; + playerMutex.lock(); if (handler) handler->playerRemovedFromGame(game); + playerMutex.unlock(); + delete userInfo; clearZones(); + + deleteLater(); +} + +void Server_Player::moveToThread(QThread *thread) +{ + QObject::moveToThread(thread); + userInfo->moveToThread(thread); } int Server_Player::newCardId() { + QMutexLocker locker(&game->gameMutex); + return nextCardId++; } int Server_Player::newCounterId() const { + QMutexLocker locker(&game->gameMutex); + int id = 0; QMapIterator i(counters); while (i.hasNext()) { @@ -45,6 +66,8 @@ int Server_Player::newCounterId() const int Server_Player::newArrowId() const { + QMutexLocker locker(&game->gameMutex); + int id = 0; QMapIterator i(arrows); while (i.hasNext()) { @@ -57,6 +80,8 @@ int Server_Player::newArrowId() const void Server_Player::setupZones() { + QMutexLocker locker(&game->gameMutex); + // This may need to be customized according to the game rules. // ------------------------------------------------------------------ @@ -102,7 +127,7 @@ void Server_Player::setupZones() if (!currentCard) continue; for (int k = 0; k < currentCard->getNumber(); ++k) - z->cards.append(new Server_Card(currentCard->getName(), nextCardId++, 0, 0)); + z->cards.append(new Server_Card(currentCard->getName(), nextCardId++, 0, 0, z)); } } @@ -138,6 +163,8 @@ void Server_Player::setupZones() void Server_Player::clearZones() { + QMutexLocker locker(&game->gameMutex); + QMapIterator zoneIterator(zones); while (zoneIterator.hasNext()) delete zoneIterator.next().value(); @@ -158,11 +185,15 @@ void Server_Player::clearZones() ServerInfo_PlayerProperties *Server_Player::getProperties() { + QMutexLocker locker(&game->gameMutex); + return new ServerInfo_PlayerProperties(playerId, new ServerInfo_User(userInfo), spectator, conceded, readyStart, deckId); } void Server_Player::setDeck(DeckList *_deck, int _deckId) { + QMutexLocker locker(&game->gameMutex); + delete deck; deck = _deck; deckId = _deckId; @@ -170,16 +201,22 @@ void Server_Player::setDeck(DeckList *_deck, int _deckId) void Server_Player::addZone(Server_CardZone *zone) { + QMutexLocker locker(&game->gameMutex); + zones.insert(zone->getName(), zone); } void Server_Player::addArrow(Server_Arrow *arrow) { + QMutexLocker locker(&game->gameMutex); + arrows.insert(arrow->getId(), arrow); } bool Server_Player::deleteArrow(int arrowId) { + QMutexLocker locker(&game->gameMutex); + Server_Arrow *arrow = arrows.value(arrowId, 0); if (!arrow) return false; @@ -190,11 +227,15 @@ bool Server_Player::deleteArrow(int arrowId) void Server_Player::addCounter(Server_Counter *counter) { + QMutexLocker locker(&game->gameMutex); + counters.insert(counter->getId(), counter); } bool Server_Player::deleteCounter(int counterId) { + QMutexLocker locker(&game->gameMutex); + Server_Counter *counter = counters.value(counterId, 0); if (!counter) return false; @@ -205,6 +246,8 @@ bool Server_Player::deleteCounter(int counterId) ResponseCode Server_Player::drawCards(CommandContainer *cont, int number) { + QMutexLocker locker(&game->gameMutex); + Server_CardZone *deckZone = zones.value("deck"); Server_CardZone *handZone = zones.value("hand"); if (deckZone->cards.size() < number) @@ -228,6 +271,8 @@ ResponseCode Server_Player::drawCards(CommandContainer *cont, int number) ResponseCode Server_Player::undoDraw(CommandContainer *cont) { + QMutexLocker locker(&game->gameMutex); + if (lastDrawList.isEmpty()) return RespContextError; @@ -240,6 +285,8 @@ ResponseCode Server_Player::undoDraw(CommandContainer *cont) ResponseCode Server_Player::moveCard(CommandContainer *cont, const QString &_startZone, const QList &_cards, int targetPlayerId, const QString &_targetZone, int x, int y, bool faceDown) { + QMutexLocker locker(&game->gameMutex); + Server_CardZone *startzone = getZones().value(_startZone); Server_Player *targetPlayer = game->getPlayers().value(targetPlayerId); if (!targetPlayer) @@ -274,6 +321,8 @@ public: ResponseCode Server_Player::moveCard(CommandContainer *cont, Server_CardZone *startzone, const QList &_cards, Server_CardZone *targetzone, int x, int y, bool faceDown, bool fixFreeSpaces, bool undoingDraw) { + QMutexLocker locker(&game->gameMutex); + // Disallow controller change to other zones than the table. if (((targetzone->getType() != PublicZone) || !targetzone->hasCoords()) && (startzone->getPlayer() != targetzone->getPlayer())) return RespContextError; @@ -285,7 +334,7 @@ ResponseCode Server_Player::moveCard(CommandContainer *cont, Server_CardZone *st QMap cardProperties; for (int i = 0; i < _cards.size(); ++i) { int position; - Server_Card *card = startzone->getCard(_cards[i]->getCardId(), false, &position); + Server_Card *card = startzone->getCard(_cards[i]->getCardId(), &position); if (!card) return RespNameNotFound; if (!card->getAttachedCards().isEmpty() && !targetzone->isColumnEmpty(x, y)) @@ -353,6 +402,7 @@ ResponseCode Server_Player::moveCard(CommandContainer *cont, Server_CardZone *st if (card->getDestroyOnZoneChange() && (startzone->getName() != targetzone->getName())) { cont->enqueueGameEventPrivate(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId(), -1, new Context_MoveCard); + cont->enqueueGameEventOmniscient(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId(), new Context_MoveCard); cont->enqueueGameEventPublic(new Event_DestroyCard(getPlayerId(), startzone->getName(), card->getId()), game->getGameId(), new Context_MoveCard); card->deleteLater(); } else { @@ -428,6 +478,8 @@ ResponseCode Server_Player::moveCard(CommandContainer *cont, Server_CardZone *st void Server_Player::unattachCard(CommandContainer *cont, Server_Card *card) { + QMutexLocker locker(&game->gameMutex); + Server_CardZone *zone = card->getZone(); card->setParentCard(0); @@ -441,6 +493,8 @@ void Server_Player::unattachCard(CommandContainer *cont, Server_Card *card) ResponseCode Server_Player::setCardAttrHelper(CommandContainer *cont, const QString &zoneName, int cardId, const QString &attrName, const QString &attrValue) { + QMutexLocker locker(&game->gameMutex); + Server_CardZone *zone = getZones().value(zoneName); if (!zone) return RespNameNotFound; @@ -456,7 +510,7 @@ ResponseCode Server_Player::setCardAttrHelper(CommandContainer *cont, const QStr return RespInvalidCommand; } } else { - Server_Card *card = zone->getCard(cardId, false); + Server_Card *card = zone->getCard(cardId); if (!card) return RespNameNotFound; result = card->setAttribute(attrName, attrValue, false); @@ -471,6 +525,8 @@ ResponseCode Server_Player::setCardAttrHelper(CommandContainer *cont, const QStr void Server_Player::sendProtocolItem(ProtocolItem *item, bool deleteItem) { + QMutexLocker locker(&playerMutex); + if (handler) handler->sendProtocolItem(item, deleteItem); } diff --git a/common/server_player.h b/common/server_player.h index 433c90b4a..955dd77cf 100644 --- a/common/server_player.h +++ b/common/server_player.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "protocol_datastructures.h" class DeckList; @@ -22,6 +23,7 @@ class CommandContainer; class Server_Player : public Server_ArrowTarget { Q_OBJECT private: + mutable QMutex playerMutex; class MoveCardCompareFunctor; Server_Game *game; Server_ProtocolHandler *handler; @@ -41,8 +43,10 @@ private: public: Server_Player(Server_Game *_game, int _playerId, ServerInfo_User *_userInfo, bool _spectator, Server_ProtocolHandler *_handler); ~Server_Player(); + void prepareDestroy(); + void moveToThread(QThread *thread); Server_ProtocolHandler *getProtocolHandler() const { return handler; } - void setProtocolHandler(Server_ProtocolHandler *_handler) { handler = _handler; } + void setProtocolHandler(Server_ProtocolHandler *_handler) { playerMutex.lock(); handler = _handler; playerMutex.unlock(); } void setPlayerId(int _id) { playerId = _id; } int getInitialCards() const { return initialCards; } @@ -57,6 +61,7 @@ public: ServerInfo_User *getUserInfo() const { return userInfo; } void setDeck(DeckList *_deck, int _deckId); DeckList *getDeck() const { return deck; } + Server_Game *getGame() const { return game; } const QMap &getZones() const { return zones; } const QMap &getCounters() const { return counters; } const QMap &getArrows() const { return arrows; } diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 03828c6aa..a4167009e 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -14,21 +14,30 @@ #include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent) - : QObject(parent), server(_server), authState(PasswordWrong), acceptsUserListChanges(false), acceptsRoomListChanges(false), userInfo(0), timeRunning(0), lastDataReceived(0) + : QObject(parent), server(_server), authState(PasswordWrong), acceptsUserListChanges(false), acceptsRoomListChanges(false), userInfo(0), timeRunning(0), lastDataReceived(0), gameListMutex(QMutex::Recursive) { connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); } Server_ProtocolHandler::~Server_ProtocolHandler() { - // The socket has to be removed from the server's list before it is removed from the game's list - // so it will not receive the game update event. - server->removeClient(this); +} +// This is essentially the destructor, but it needs to be called from the +// child's destructor so that the server mutex does not get unlocked during +// finalization. +void Server_ProtocolHandler::prepareDestroy() +{ + QMutexLocker locker(&server->serverMutex); + qDebug("Server_ProtocolHandler::prepareDestroy"); + + server->removeClient(this); + QMapIterator roomIterator(rooms); while (roomIterator.hasNext()) roomIterator.next().value()->removeClient(this); + gameListMutex.lock(); QMapIterator > gameIterator(games); while (gameIterator.hasNext()) { gameIterator.next(); @@ -37,9 +46,12 @@ Server_ProtocolHandler::~Server_ProtocolHandler() if ((authState == UnknownUser) || p->getSpectator()) g->removePlayer(p); - else + else { p->setProtocolHandler(0); + g->postConnectionStatusUpdate(p, false); + } } + gameListMutex.unlock(); delete userInfo; QMapIterator i(buddyList); @@ -53,6 +65,8 @@ Server_ProtocolHandler::~Server_ProtocolHandler() void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game) { qDebug() << "Server_ProtocolHandler::playerRemovedFromGame(): gameId =" << game->getGameId(); + + QMutexLocker locker(&gameListMutex); games.remove(game->getGameId()); } @@ -66,7 +80,9 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm Server_Room *room = rooms.value(roomCommand->getRoomId(), 0); if (!room) - return RespNameNotFound; + return RespNotInRoom; + + QMutexLocker locker(&room->roomMutex); switch (command->getItemId()) { case ItemId_Command_LeaveRoom: return cmdLeaveRoom(static_cast(command), cont, room); @@ -81,15 +97,19 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm qDebug() << "received GameCommand: game =" << gameCommand->getGameId(); if (authState == PasswordWrong) return RespLoginNeeded; - + + gameListMutex.lock(); if (!games.contains(gameCommand->getGameId())) { qDebug() << "invalid game"; - return RespNameNotFound; + return RespNotInRoom; } QPair gamePair = games.value(gameCommand->getGameId()); Server_Game *game = gamePair.first; Server_Player *player = gamePair.second; + QMutexLocker locker(&game->gameMutex); + gameListMutex.unlock(); + switch (command->getItemId()) { case ItemId_Command_DeckSelect: return cmdDeckSelect(static_cast(command), cont, game, player); case ItemId_Command_SetSideboardPlan: return cmdSetSideboardPlan(static_cast(command), cont, game, player); @@ -124,6 +144,17 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm default: return RespInvalidCommand; } } + ModeratorCommand *moderatorCommand = qobject_cast(command); + if (moderatorCommand) { + qDebug() << "received ModeratorCommand"; + if (!(userInfo->getUserLevel() & ServerInfo_User::IsModerator)) + return RespLoginNeeded; + + switch (command->getItemId()) { + case ItemId_Command_BanFromServer: return cmdBanFromServer(static_cast(command), cont); + default: return RespInvalidCommand; + } + } AdminCommand *adminCommand = qobject_cast(command); if (adminCommand) { qDebug() << "received AdminCommand"; @@ -131,8 +162,8 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm return RespLoginNeeded; switch (command->getItemId()) { + case ItemId_Command_ShutdownServer: return cmdShutdownServer(static_cast(command), cont); case ItemId_Command_UpdateServerMessage: return cmdUpdateServerMessage(static_cast(command), cont); - case ItemId_Command_BanFromServer: return cmdBanFromServer(static_cast(command), cont); default: return RespInvalidCommand; } } @@ -148,6 +179,7 @@ ResponseCode Server_ProtocolHandler::processCommandHelper(Command *command, Comm 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_GetGamesOfUser: return cmdGetGamesOfUser(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); @@ -171,7 +203,8 @@ void Server_ProtocolHandler::processCommandContainer(CommandContainer *cont) ProtocolResponse *pr = cont->getResponse(); if (!pr) pr = new ProtocolResponse(cont->getCmdId(), finalResponseCode); - + + gameListMutex.lock(); GameEventContainer *gQPublic = cont->getGameEventQueuePublic(); if (gQPublic) { Server_Game *game = games.value(gQPublic->getGameId()).first; @@ -194,6 +227,7 @@ void Server_ProtocolHandler::processCommandContainer(CommandContainer *cont) } else game->sendGameEventContainer(gQPublic); } + gameListMutex.unlock(); const QList &iQ = cont->getItemQueue(); for (int i = 0; i < iQ.size(); ++i) @@ -247,45 +281,36 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain QString userName = cmd->getUsername().simplified(); if (userName.isEmpty() || (userInfo != 0)) return RespContextError; - if (server->getUserBanned(this, userName)) - return RespWrongPassword; authState = server->loginUser(this, userName, cmd->getPassword()); if (authState == PasswordWrong) return RespWrongPassword; if (authState == WouldOverwriteOldSession) return RespWouldOverwriteOldSession; - enqueueProtocolItem(new Event_ServerMessage(server->getLoginMessage())); + ProtocolItem *serverMessage = new Event_ServerMessage(server->getLoginMessage()); + if (getCompressionSupport()) + serverMessage->setCompressed(true); + enqueueProtocolItem(serverMessage); + QList _buddyList, _ignoreList; if (authState == PasswordRight) { buddyList = server->getBuddyList(userInfo->getName()); + + QMapIterator buddyIterator(buddyList); + while (buddyIterator.hasNext()) + _buddyList.append(new ServerInfo_User(buddyIterator.next().value())); + ignoreList = server->getIgnoreList(userInfo->getName()); - // This might not scale very well. Use an extra QMap if it becomes a problem. - const QList &serverGames = server->getGames(); - for (int i = 0; i < serverGames.size(); ++i) { - const QList &gamePlayers = serverGames[i]->getPlayers().values(); - for (int j = 0; j < gamePlayers.size(); ++j) - if (gamePlayers[j]->getUserInfo()->getName() == userInfo->getName()) { - gamePlayers[j]->setProtocolHandler(this); - games.insert(serverGames[i]->getGameId(), QPair(serverGames[i], gamePlayers[j])); - - enqueueProtocolItem(new Event_GameJoined(serverGames[i]->getGameId(), serverGames[i]->getDescription(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator(), serverGames[i]->getSpectatorsCanTalk(), serverGames[i]->getSpectatorsSeeEverything(), true)); - enqueueProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(serverGames[i]->getGameStarted(), serverGames[i]->getActivePlayer(), serverGames[i]->getActivePhase(), serverGames[i]->getGameState(gamePlayers[j])), serverGames[i]->getGameId())); - } - } + QMapIterator ignoreIterator(ignoreList); + while (ignoreIterator.hasNext()) + _ignoreList.append(new ServerInfo_User(ignoreIterator.next().value())); } - QList _buddyList; - QMapIterator buddyIterator(buddyList); - while (buddyIterator.hasNext()) - _buddyList.append(new ServerInfo_User(buddyIterator.next().value())); - QList _ignoreList; - QMapIterator ignoreIterator(ignoreList); - while (ignoreIterator.hasNext()) - _ignoreList.append(new ServerInfo_User(ignoreIterator.next().value())); - - cont->setResponse(new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true), _buddyList, _ignoreList)); + ProtocolResponse *resp = new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true), _buddyList, _ignoreList); + if (getCompressionSupport()) + resp->setCompressed(true); + cont->setResponse(resp); return RespNothing; } @@ -296,6 +321,7 @@ ResponseCode Server_ProtocolHandler::cmdMessage(Command_Message *cmd, CommandCon QString receiver = cmd->getUserName(); Server_ProtocolHandler *userHandler = server->getUsers().value(receiver); + qDebug() << "cmdMessage: recv=" << receiver << (userHandler == 0 ? "not found" : "found"); if (!userHandler) return RespNameNotFound; if (userHandler->getIgnoreList().contains(userInfo->getName())) @@ -306,6 +332,34 @@ ResponseCode Server_ProtocolHandler::cmdMessage(Command_Message *cmd, CommandCon return RespOk; } +ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(Command_GetGamesOfUser *cmd, CommandContainer *cont) +{ + if (authState == PasswordWrong) + return RespLoginNeeded; + + server->serverMutex.lock(); + if (!server->getUsers().contains(cmd->getUserName())) + return RespNameNotFound; + + QList roomList; + QList gameList; + QMapIterator roomIterator(server->getRooms()); + while (roomIterator.hasNext()) { + Server_Room *room = roomIterator.next().value(); + room->roomMutex.lock(); + roomList.append(room->getInfo(false, true)); + gameList << room->getGamesOfUser(cmd->getUserName()); + room->roomMutex.unlock(); + } + server->serverMutex.unlock(); + + ProtocolResponse *resp = new Response_GetGamesOfUser(cont->getCmdId(), RespOk, roomList, gameList); + if (getCompressionSupport()) + resp->setCompressed(true); + cont->setResponse(resp); + return RespNothing; +} + ResponseCode Server_ProtocolHandler::cmdGetUserInfo(Command_GetUserInfo *cmd, CommandContainer *cont) { if (authState == PasswordWrong) @@ -351,13 +405,38 @@ ResponseCode Server_ProtocolHandler::cmdJoinRoom(Command_JoinRoom *cmd, CommandC Server_Room *r = server->getRooms().value(cmd->getRoomId(), 0); if (!r) return RespNameNotFound; - + + QMutexLocker serverLocker(&server->serverMutex); + QMutexLocker roomLocker(&r->roomMutex); 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))); + // This might not scale very well. Use an extra QMap if it becomes a problem. + QMutexLocker gameListLocker(&gameListMutex); + QMapIterator gameIterator(r->getGames()); + while (gameIterator.hasNext()) { + Server_Game *game = gameIterator.next().value(); + QMutexLocker gameLocker(&game->gameMutex); + const QList &gamePlayers = game->getPlayers().values(); + for (int j = 0; j < gamePlayers.size(); ++j) + if (gamePlayers[j]->getUserInfo()->getName() == userInfo->getName()) { + gamePlayers[j]->setProtocolHandler(this); + game->postConnectionStatusUpdate(gamePlayers[j], true); + games.insert(game->getGameId(), QPair(game, gamePlayers[j])); + + enqueueProtocolItem(new Event_GameJoined(game->getGameId(), game->getDescription(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator(), game->getSpectatorsCanTalk(), game->getSpectatorsSeeEverything(), true)); + enqueueProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(game->getGameStarted(), game->getActivePlayer(), game->getActivePhase(), game->getGameState(gamePlayers[j])), game->getGameId())); + + break; + } + } + + ServerInfo_Room *info = r->getInfo(true); + if (getCompressionSupport()) + info->setCompressed(true); + cont->setResponse(new Response_JoinRoom(cont->getCmdId(), RespOk, info)); return RespNothing; } @@ -389,8 +468,9 @@ ResponseCode Server_ProtocolHandler::cmdRoomSay(Command_RoomSay *cmd, CommandCon if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval())) return RespChatFlood; } + msg.replace(QChar('\n'), QChar(' ')); - room->say(this, cmd->getMessage()); + room->say(this, msg); return RespOk; } @@ -406,7 +486,10 @@ ResponseCode Server_ProtocolHandler::cmdListUsers(Command_ListUsers * /*cmd*/, C acceptsUserListChanges = true; - cont->setResponse(new Response_ListUsers(cont->getCmdId(), RespOk, resultList)); + ProtocolResponse *resp = new Response_ListUsers(cont->getCmdId(), RespOk, resultList); + if (getCompressionSupport()) + resp->setCompressed(true); + cont->setResponse(resp); return RespNothing; } @@ -414,18 +497,31 @@ ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, Comm { if (authState == PasswordWrong) return RespLoginNeeded; + + if (server->getMaxGamesPerUser() > 0) + if (room->getGamesCreatedByUser(userInfo->getName()) >= server->getMaxGamesPerUser()) + return RespContextError; QList gameTypes; QList gameTypeList = cmd->getGameTypes(); for (int i = 0; i < gameTypeList.size(); ++i) gameTypes.append(gameTypeList[i]->getData()); - Server_Game *game = room->createGame(cmd->getDescription(), cmd->getPassword(), cmd->getMaxPlayers(), gameTypes, cmd->getOnlyBuddies(), cmd->getOnlyRegistered(), cmd->getSpectatorsAllowed(), cmd->getSpectatorsNeedPassword(), cmd->getSpectatorsCanTalk(), cmd->getSpectatorsSeeEverything(), this); + QString description = cmd->getDescription(); + if (description.size() > 60) + description = description.left(60); + Server_Game *game = room->createGame(description, cmd->getPassword(), cmd->getMaxPlayers(), gameTypes, cmd->getOnlyBuddies(), cmd->getOnlyRegistered(), cmd->getSpectatorsAllowed(), cmd->getSpectatorsNeedPassword(), cmd->getSpectatorsCanTalk(), cmd->getSpectatorsSeeEverything(), this); + Server_Player *creator = game->getPlayers().values().first(); + + QMutexLocker gameListLocker(&gameListMutex); games.insert(game->getGameId(), QPair(game, creator)); - enqueueProtocolItem(new Event_GameJoined(game->getGameId(), game->getDescription(), creator->getPlayerId(), false, game->getSpectatorsCanTalk(), game->getSpectatorsSeeEverything(), false)); - enqueueProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(game->getGameStarted(), game->getActivePlayer(), game->getActivePhase(), game->getGameState(creator)), game->getGameId())); + sendProtocolItem(new Event_GameJoined(game->getGameId(), game->getDescription(), creator->getPlayerId(), false, game->getSpectatorsCanTalk(), game->getSpectatorsSeeEverything(), false)); + sendProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(game->getGameStarted(), game->getActivePlayer(), game->getActivePhase(), game->getGameState(creator)), game->getGameId())); + + game->gameMutex.unlock(); + return RespOk; } @@ -434,13 +530,17 @@ ResponseCode Server_ProtocolHandler::cmdJoinGame(Command_JoinGame *cmd, CommandC if (authState == PasswordWrong) return RespLoginNeeded; + QMutexLocker gameListLocker(&gameListMutex); + if (games.contains(cmd->getGameId())) return RespContextError; Server_Game *g = room->getGames().value(cmd->getGameId()); if (!g) return RespNameNotFound; - + + QMutexLocker locker(&g->gameMutex); + ResponseCode result = g->checkJoin(userInfo, cmd->getPassword(), cmd->getSpectator()); if (result == RespOk) { Server_Player *player = g->addPlayer(this, cmd->getSpectator()); @@ -591,9 +691,16 @@ ResponseCode Server_ProtocolHandler::cmdMulligan(Command_Mulligan * /*cmd*/, Com deck->shuffle(); cont->enqueueGameEventPrivate(new Event_Shuffle(player->getPlayerId()), game->getGameId()); + cont->enqueueGameEventOmniscient(new Event_Shuffle(player->getPlayerId()), game->getGameId()); cont->enqueueGameEventPublic(new Event_Shuffle(player->getPlayerId()), game->getGameId()); player->drawCards(cont, number); + + if (number == player->getInitialCards()) + number = -1; + cont->getGameEventQueuePrivate()->setContext(new Context_Mulligan(number)); + cont->getGameEventQueuePublic()->setContext(new Context_Mulligan(number)); + cont->getGameEventQueueOmniscient()->setContext(new Context_Mulligan(number)); return RespOk; } @@ -664,7 +771,7 @@ ResponseCode Server_ProtocolHandler::cmdFlipCard(Command_FlipCard *cmd, CommandC if (!zone->hasCoords()) return RespContextError; - Server_Card *card = zone->getCard(cmd->getCardId(), false); + Server_Card *card = zone->getCard(cmd->getCardId()); if (!card) return RespNameNotFound; @@ -693,7 +800,7 @@ ResponseCode Server_ProtocolHandler::cmdAttachCard(Command_AttachCard *cmd, Comm if (!startzone) return RespNameNotFound; - Server_Card *card = startzone->getCard(cmd->getCardId(), false); + Server_Card *card = startzone->getCard(cmd->getCardId()); if (!card) return RespNameNotFound; @@ -715,7 +822,7 @@ ResponseCode Server_ProtocolHandler::cmdAttachCard(Command_AttachCard *cmd, Comm // Possibly a flag will have to be introduced for this sometime. if (!targetzone->hasCoords()) return RespContextError; - targetCard = targetzone->getCard(cmd->getTargetCardId(), false); + targetCard = targetzone->getCard(cmd->getTargetCardId()); if (targetCard) if (targetCard->getParentCard()) return RespContextError; @@ -790,6 +897,7 @@ ResponseCode Server_ProtocolHandler::cmdCreateToken(Command_CreateToken *cmd, Co y = 0; Server_Card *card = new Server_Card(cmd->getCardName(), player->newCardId(), x, y); + card->moveToThread(player->thread()); card->setPT(cmd->getPt()); card->setColor(cmd->getColor()); card->setAnnotation(cmd->getAnnotation()); @@ -824,14 +932,14 @@ ResponseCode Server_ProtocolHandler::cmdCreateArrow(Command_CreateArrow *cmd, Co return RespNameNotFound; if (startZone->getType() != PublicZone) return RespContextError; - Server_Card *startCard = startZone->getCard(cmd->getStartCardId(), false); + Server_Card *startCard = startZone->getCard(cmd->getStartCardId()); if (!startCard) return RespNameNotFound; Server_Card *targetCard = 0; if (!playerTarget) { if (targetZone->getType() != PublicZone) return RespContextError; - targetCard = targetZone->getCard(cmd->getTargetCardId(), false); + targetCard = targetZone->getCard(cmd->getTargetCardId()); } Server_ArrowTarget *targetItem; @@ -910,7 +1018,7 @@ ResponseCode Server_ProtocolHandler::cmdSetCardCounter(Command_SetCardCounter *c if (!zone->hasCoords()) return RespContextError; - Server_Card *card = zone->getCard(cmd->getCardId(), false); + Server_Card *card = zone->getCard(cmd->getCardId()); if (!card) return RespNameNotFound; @@ -937,7 +1045,7 @@ ResponseCode Server_ProtocolHandler::cmdIncCardCounter(Command_IncCardCounter *c if (!zone->hasCoords()) return RespContextError; - Server_Card *card = zone->getCard(cmd->getCardId(), false); + Server_Card *card = zone->getCard(cmd->getCardId()); if (!card) return RespNameNotFound; @@ -1090,7 +1198,7 @@ ResponseCode Server_ProtocolHandler::cmdDumpZone(Command_DumpZone *cmd, CommandC attachCardId = card->getParentCard()->getId(); } - respCardList.append(new ServerInfo_Card(card->getId(), displayedName, card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), cardCounterList, attachPlayerId, attachZone, attachCardId)); + respCardList.append(new ServerInfo_Card(card->getId(), displayedName, card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), card->getDoesntUntap(), cardCounterList, attachPlayerId, attachZone, attachCardId)); } } if (zone->getType() == HiddenZone) { @@ -1150,7 +1258,7 @@ ResponseCode Server_ProtocolHandler::cmdRevealCards(Command_RevealCards *cmd, Co return RespContextError; cardsToReveal.append(zone->cards.at(rng->getNumber(0, zone->cards.size() - 1))); } else { - Server_Card *card = zone->getCard(cmd->getCardId(), false); + Server_Card *card = zone->getCard(cmd->getCardId()); if (!card) return RespNameNotFound; cardsToReveal.append(card); @@ -1178,8 +1286,8 @@ ResponseCode Server_ProtocolHandler::cmdRevealCards(Command_RevealCards *cmd, Co } if (cmd->getPlayerId() != -1) - respCardListPrivate.append(new ServerInfo_Card(card->getId(), card->getName(), card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), cardCounterListPrivate, attachPlayerId, attachZone, attachCardId)); - respCardListOmniscient.append(new ServerInfo_Card(card->getId(), card->getName(), card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), cardCounterListOmniscient, attachPlayerId, attachZone, attachCardId)); + respCardListPrivate.append(new ServerInfo_Card(card->getId(), card->getName(), card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), card->getDoesntUntap(), cardCounterListPrivate, attachPlayerId, attachZone, attachCardId)); + respCardListOmniscient.append(new ServerInfo_Card(card->getId(), card->getName(), card->getX(), card->getY(), card->getTapped(), card->getAttacking(), card->getColor(), card->getPT(), card->getAnnotation(), card->getDestroyOnZoneChange(), card->getDoesntUntap(), cardCounterListOmniscient, attachPlayerId, attachZone, attachCardId)); } if (cmd->getPlayerId() == -1) diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index 677ba0956..1902f1d80 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -28,6 +28,9 @@ protected: bool acceptsRoomListChanges; ServerInfo_User *userInfo; QMap buddyList, ignoreList; + + void prepareDestroy(); + virtual bool getCompressionSupport() const = 0; private: QList itemQueue; QList messageSizeOverTime, messageCountOverTime; @@ -47,6 +50,7 @@ private: virtual ResponseCode cmdDeckDel(Command_DeckDel *cmd, CommandContainer *cont) = 0; virtual ResponseCode cmdDeckUpload(Command_DeckUpload *cmd, CommandContainer *cont) = 0; virtual ResponseCode cmdDeckDownload(Command_DeckDownload *cmd, CommandContainer *cont) = 0; + ResponseCode cmdGetGamesOfUser(Command_GetGamesOfUser *cmd, CommandContainer *cont); ResponseCode cmdGetUserInfo(Command_GetUserInfo *cmd, CommandContainer *cont); ResponseCode cmdListRooms(Command_ListRooms *cmd, CommandContainer *cont); ResponseCode cmdJoinRoom(Command_JoinRoom *cmd, CommandContainer *cont); @@ -85,13 +89,16 @@ 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; virtual ResponseCode cmdBanFromServer(Command_BanFromServer *cmd, CommandContainer *cont) = 0; + virtual ResponseCode cmdShutdownServer(Command_ShutdownServer *cmd, CommandContainer *cont) = 0; + virtual ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont) = 0; ResponseCode processCommandHelper(Command *command, CommandContainer *cont); private slots: void pingClockTimeout(); public: + QMutex gameListMutex; + Server_ProtocolHandler(Server *_server, QObject *parent = 0); ~Server_ProtocolHandler(); void playerRemovedFromGame(Server_Game *game); diff --git a/common/server_room.cpp b/common/server_room.cpp index fe7b83ee9..9e9aa571c 100644 --- a/common/server_room.cpp +++ b/common/server_room.cpp @@ -4,17 +4,32 @@ #include Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent) - : QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes) + : QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes), roomMutex(QMutex::Recursive) { } +Server_Room::~Server_Room() +{ + QMutexLocker locker(&roomMutex); + qDebug("Server_Room destructor"); + + const QList gameList = games.values(); + for (int i = 0; i < gameList.size(); ++i) + delete gameList[i]; + games.clear(); + + clear(); +} + Server *Server_Room::getServer() const { return static_cast(parent()); } -ServerInfo_Room *Server_Room::getInfo(bool complete) const +ServerInfo_Room *Server_Room::getInfo(bool complete, bool showGameTypes) const { + QMutexLocker locker(&roomMutex); + QList gameList; QList userList; QList gameTypeList; @@ -25,16 +40,18 @@ ServerInfo_Room *Server_Room::getInfo(bool complete) const for (int i = 0; i < size(); ++i) userList.append(new ServerInfo_User(at(i)->getUserInfo(), false)); - + } + if (complete || showGameTypes) for (int i = 0; i < gameTypes.size(); ++i) gameTypeList.append(new ServerInfo_GameType(i, gameTypes[i])); - } return new ServerInfo_Room(id, name, description, games.size(), size(), autoJoin, gameList, userList, gameTypeList); } void Server_Room::addClient(Server_ProtocolHandler *client) { + QMutexLocker locker(&roomMutex); + sendRoomEvent(new Event_JoinRoom(id, new ServerInfo_User(client->getUserInfo(), false))); append(client); emit roomInfoChanged(); @@ -42,6 +59,8 @@ void Server_Room::addClient(Server_ProtocolHandler *client) void Server_Room::removeClient(Server_ProtocolHandler *client) { + QMutexLocker locker(&roomMutex); + removeAt(indexOf(client)); sendRoomEvent(new Event_LeaveRoom(id, client->getUserInfo()->getName())); emit roomInfoChanged(); @@ -54,6 +73,8 @@ void Server_Room::say(Server_ProtocolHandler *client, const QString &s) void Server_Room::sendRoomEvent(RoomEvent *event) { + QMutexLocker locker(&roomMutex); + for (int i = 0; i < size(); ++i) at(i)->sendProtocolItem(event, false); delete event; @@ -61,6 +82,8 @@ void Server_Room::sendRoomEvent(RoomEvent *event) void Server_Room::broadcastGameListUpdate(Server_Game *game) { + QMutexLocker locker(&roomMutex); + Event_ListGames *event = new Event_ListGames(id, QList() << game->getInfo()); for (int i = 0; i < size(); i++) @@ -70,24 +93,52 @@ void Server_Room::broadcastGameListUpdate(Server_Game *game) Server_Game *Server_Room::createGame(const QString &description, const QString &password, int maxPlayers, const QList &gameTypes, bool onlyBuddies, bool onlyRegistered, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator) { + QMutexLocker locker(&roomMutex); + Server_Game *newGame = new Server_Game(creator, static_cast(parent())->getNextGameId(), description, password, maxPlayers, gameTypes, onlyBuddies, onlyRegistered, spectatorsAllowed, spectatorsNeedPassword, spectatorsCanTalk, spectatorsSeeEverything, this); + newGame->moveToThread(thread()); + // This mutex needs to be unlocked by the caller. + newGame->gameMutex.lock(); 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() +void Server_Room::removeGame(Server_Game *game) { - Server_Game *game = static_cast(sender()); + // No need to lock roomMutex or gameMutex. This method is only + // called from ~Server_Game, which locks both mutexes anyway beforehand. + broadcastGameListUpdate(game); games.remove(game->getGameId()); - emit gameClosing(game->getGameId()); emit roomInfoChanged(); } + +int Server_Room::getGamesCreatedByUser(const QString &userName) const +{ + QMutexLocker locker(&roomMutex); + + QMapIterator gamesIterator(games); + int result = 0; + while (gamesIterator.hasNext()) + if (gamesIterator.next().value()->getCreatorInfo()->getName() == userName) + ++result; + return result; +} + +QList Server_Room::getGamesOfUser(const QString &userName) const +{ + QList result; + QMapIterator gamesIterator(games); + while (gamesIterator.hasNext()) { + Server_Game *game = gamesIterator.next().value(); + if (game->containsUser(userName)) + result.append(game->getInfo()); + } + return result; +} diff --git a/common/server_room.h b/common/server_room.h index 8571f04ea..663c9cee3 100644 --- a/common/server_room.h +++ b/common/server_room.h @@ -5,11 +5,13 @@ #include #include #include +#include class Server_ProtocolHandler; class RoomEvent; class ServerInfo_User; class ServerInfo_Room; +class ServerInfo_Game; class Server_Game; class Server; @@ -17,8 +19,6 @@ 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; @@ -27,10 +27,10 @@ private: QString joinMessage; QStringList gameTypes; QMap games; -private slots: - void removeGame(); public: + mutable QMutex roomMutex; Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent); + ~Server_Room(); int getId() const { return id; } QString getName() const { return name; } QString getDescription() const { return description; } @@ -38,13 +38,16 @@ public: QString getJoinMessage() const { return joinMessage; } const QMap &getGames() const { return games; } Server *getServer() const; - ServerInfo_Room *getInfo(bool complete) const; + ServerInfo_Room *getInfo(bool complete, bool showGameTypes = false) const; + int getGamesCreatedByUser(const QString &name) const; + QList getGamesOfUser(const QString &name) 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, const QList &_gameTypes, bool onlyBuddies, bool onlyRegistered, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator); + void removeGame(Server_Game *game); void sendRoomEvent(RoomEvent *event); }; diff --git a/nsis/cockatrice.nsi b/nsis/cockatrice.nsi index 6e182a600..8c4c31a68 100644 --- a/nsis/cockatrice.nsi +++ b/nsis/cockatrice.nsi @@ -40,6 +40,7 @@ Section "Application" SecApplication File data\QtNetwork4.dll File data\QtSvg4.dll File data\QtXml4.dll + File data\QtMultimedia4.dll SetOutPath "$INSTDIR\zonebg" File /r ..\zonebg\*.* @@ -47,6 +48,9 @@ Section "Application" SecApplication SetOutPath "$INSTDIR\plugins" File /r data\plugins\*.* + SetOutPath "$INSTDIR\sounds" + File /r ..\sounds\*.* + SetOutPath "$INSTDIR\pics" SetOutPath "$INSTDIR\decks" @@ -77,6 +81,7 @@ SectionEnd Section Uninstall RMDir /r "$INSTDIR\zonebg" RMDir /r "$INSTDIR\plugins" + RMDir /r "$INSTDIR\sounds" RMDir "$INSTDIR\decks" RMDir /r "$INSTDIR\pics\downloadedPics" RMDir "$INSTDIR\pics" diff --git a/oracle/sets.xml b/oracle/sets.xml index ab9302f2b..8e7dfda71 100644 --- a/oracle/sets.xml +++ b/oracle/sets.xml @@ -172,6 +172,10 @@ M11 Magic 2011 + + COM + Magic: The Gathering-Commander + MM Mercadian Masques @@ -196,6 +200,10 @@ NE Nemesis + + NPH + New Phyrexia + 9E Ninth Edition diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 5aa2b99fc..add5e538b 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -15,27 +15,27 @@ OracleImporter::OracleImporter(const QString &_dataDir, QObject *parent) connect(http, SIGNAL(dataReadProgress(int, int)), this, SIGNAL(dataReadProgress(int, int))); } -void OracleImporter::readSetsFromFile(const QString &fileName) +bool OracleImporter::readSetsFromFile(const QString &fileName) { QFile setsFile(fileName); if (!setsFile.open(QIODevice::ReadOnly | QIODevice::Text)) { QMessageBox::critical(0, tr("Error"), tr("Cannot open file '%1'.").arg(fileName)); - return; + return false; } QXmlStreamReader xml(&setsFile); - readSetsFromXml(xml); + return readSetsFromXml(xml); } -void OracleImporter::readSetsFromByteArray(const QByteArray &data) +bool OracleImporter::readSetsFromByteArray(const QByteArray &data) { QXmlStreamReader xml(data); - readSetsFromXml(xml); + return readSetsFromXml(xml); } -void OracleImporter::readSetsFromXml(QXmlStreamReader &xml) +bool OracleImporter::readSetsFromXml(QXmlStreamReader &xml) { - allSets.clear(); + QList newSetList; QString edition; QString editionLong; @@ -56,7 +56,7 @@ void OracleImporter::readSetsFromXml(QXmlStreamReader &xml) else if (xml.name() == "url") editionURL = xml.readElementText(); } - allSets << SetToDownload(edition, editionLong, editionURL, import); + newSetList.append(SetToDownload(edition, editionLong, editionURL, import)); edition = editionLong = editionURL = QString(); } else if (xml.name() == "picture_url") pictureUrl = xml.readElementText(); @@ -67,6 +67,10 @@ void OracleImporter::readSetsFromXml(QXmlStreamReader &xml) else if (xml.name() == "set_url") setUrl = xml.readElementText(); } + if (newSetList.isEmpty()) + return false; + allSets = newSetList; + return true; } CardInfo *OracleImporter::addCard(const QString &setName, QString cardName, int cardId, const QString &cardCost, const QString &cardType, const QString &cardPT, const QStringList &cardText) diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h index afee515fa..3f6e4899f 100644 --- a/oracle/src/oracleimporter.h +++ b/oracle/src/oracleimporter.h @@ -34,7 +34,7 @@ private: QString getPictureUrl(QString url, int cardId, QString name, const QString &setName) const; void downloadNextFile(); - void readSetsFromXml(QXmlStreamReader &xml); + bool readSetsFromXml(QXmlStreamReader &xml); CardInfo *addCard(const QString &setName, QString cardName, int cardId, const QString &cardCost, const QString &cardType, const QString &cardPT, const QStringList &cardText); private slots: void httpRequestFinished(int requestId, bool error); @@ -44,8 +44,8 @@ signals: void dataReadProgress(int bytesRead, int totalBytes); public: OracleImporter(const QString &_dataDir, QObject *parent = 0); - void readSetsFromByteArray(const QByteArray &data); - void readSetsFromFile(const QString &fileName); + bool readSetsFromByteArray(const QByteArray &data); + bool readSetsFromFile(const QString &fileName); int startDownload(); int importTextSpoiler(CardSet *set, const QByteArray &data); QList &getSets() { return allSets; } diff --git a/oracle/src/window_main.cpp b/oracle/src/window_main.cpp index 8f8f9aef4..9cf164e8d 100644 --- a/oracle/src/window_main.cpp +++ b/oracle/src/window_main.cpp @@ -94,6 +94,10 @@ WindowMain::WindowMain(QWidget *parent) QStringList args = qApp->arguments(); if (args.contains("-dlsets")) downloadSetsFile(defaultSetsUrl); + + statusLabel = new QLabel; + statusBar()->addWidget(statusLabel); + statusLabel->setText(tr("Sets data not loaded.")); } void WindowMain::updateSetList() @@ -110,6 +114,7 @@ void WindowMain::updateSetList() checkBoxLayout->addWidget(checkBox); checkBoxList << checkBox; } + statusLabel->setText(tr("Ready.")); } void WindowMain::actLoadSetsFile() @@ -121,8 +126,10 @@ void WindowMain::actLoadSetsFile() return; QString fileName = dialog.selectedFiles().at(0); - importer->readSetsFromFile(fileName); - updateSetList(); + if (importer->readSetsFromFile(fileName)) + updateSetList(); + else + QMessageBox::critical(this, tr("Error"), tr("This file does not contain any sets data.")); } void WindowMain::actDownloadSetsFile() @@ -141,9 +148,15 @@ void WindowMain::downloadSetsFile(const QString &url) void WindowMain::setsDownloadFinished() { QNetworkReply *reply = static_cast(sender()); - importer->readSetsFromByteArray(reply->readAll()); + QNetworkReply::NetworkError errorCode = reply->error(); + if (errorCode == QNetworkReply::NoError) { + if (importer->readSetsFromByteArray(reply->readAll())) + updateSetList(); + else + QMessageBox::critical(this, tr("Error"), tr("The file was retrieved successfully, but it does not contain any sets data.")); + } else + QMessageBox::critical(this, tr("Error"), tr("Network error: %1.").arg(reply->errorString())); reply->deleteLater(); - updateSetList(); } void WindowMain::updateTotalProgress(int cardsImported, int setIndex, const QString &nextSetName) @@ -205,6 +218,7 @@ void WindowMain::actStart() checkBoxList[i]->setEnabled(false); startButton->setEnabled(false); totalProgressBar->setMaximum(setsCount); + statusLabel->setText(tr("Downloading card data...")); } void WindowMain::checkBoxChanged(int state) diff --git a/oracle/src/window_main.h b/oracle/src/window_main.h index afcf897db..1fdba235b 100644 --- a/oracle/src/window_main.h +++ b/oracle/src/window_main.h @@ -31,6 +31,7 @@ private: QTextEdit *messageLog; QVBoxLayout *checkBoxLayout; QList checkBoxList; + QLabel *statusLabel; void downloadSetsFile(const QString &url); private slots: diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index 956ca0dfc..8a01bc85f 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -1,6 +1,9 @@ [server] port=4747 statusupdate=15000 +logfile=server.log +id=1 +threaded=0 [authentication] method=none @@ -33,3 +36,4 @@ max_users_per_address=4 message_counting_interval=10 max_message_size_per_interval=1000 max_message_count_per_interval=10 +max_games_per_user=5 diff --git a/servatrice/servatrice.pro b/servatrice/servatrice.pro index 86f1d960a..a8de8ad32 100755 --- a/servatrice/servatrice.pro +++ b/servatrice/servatrice.pro @@ -17,6 +17,7 @@ HEADERS += src/main.h \ src/servatrice.h \ src/serversocketinterface.h \ src/server_logger.h \ + src/serversocketthread.h \ ../common/color.h \ ../common/serializable_item.h \ ../common/decklist.h \ @@ -40,6 +41,7 @@ SOURCES += src/main.cpp \ src/servatrice.cpp \ src/serversocketinterface.cpp \ src/server_logger.cpp \ + src/serversocketthread.cpp \ ../common/serializable_item.cpp \ ../common/decklist.cpp \ ../common/protocol.cpp \ diff --git a/servatrice/servatrice.sql b/servatrice/servatrice.sql index 44298d85e..7bd64c58d 100644 --- a/servatrice/servatrice.sql +++ b/servatrice/servatrice.sql @@ -28,11 +28,12 @@ SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; CREATE TABLE IF NOT EXISTS `cockatrice_decklist_files` ( `id` int(7) unsigned zerofill NOT NULL auto_increment, `id_folder` int(7) unsigned zerofill NOT NULL, - `user` varchar(30) NOT NULL, + `user` varchar(35) NOT NULL, `name` varchar(50) NOT NULL, `upload_time` datetime NOT NULL, `content` text NOT NULL, - PRIMARY KEY (`id`) + PRIMARY KEY (`id`), + KEY `FolderPlusUser` (`id_folder`,`user`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=550 ; -- -------------------------------------------------------- @@ -44,10 +45,10 @@ CREATE TABLE IF NOT EXISTS `cockatrice_decklist_files` ( CREATE TABLE IF NOT EXISTS `cockatrice_decklist_folders` ( `id` int(7) unsigned zerofill NOT NULL auto_increment, `id_parent` int(7) unsigned zerofill NOT NULL, - `user` varchar(30) NOT NULL, + `user` varchar(35) NOT NULL, `name` varchar(30) NOT NULL, PRIMARY KEY (`id`), - KEY `id_parent` (`id_parent`,`name`) + KEY `ParentPlusUser` (`id_parent`,`user`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=80 ; -- -------------------------------------------------------- @@ -73,7 +74,7 @@ CREATE TABLE IF NOT EXISTS `cockatrice_games` ( CREATE TABLE IF NOT EXISTS `cockatrice_games_players` ( `id_game` int(7) unsigned zerofill NOT NULL, - `player` varchar(30) default NULL, + `player` varchar(35) default NULL, KEY `id_game` (`id_game`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1; @@ -101,21 +102,22 @@ CREATE TABLE IF NOT EXISTS `cockatrice_news` ( CREATE TABLE IF NOT EXISTS `cockatrice_users` ( `id` int(7) unsigned zerofill NOT NULL auto_increment, `admin` tinyint(1) NOT NULL, - `name` varchar(255) NOT NULL, + `name` varchar(35) NOT NULL, `realname` varchar(255) NOT NULL, + `gender` char(1) NOT NULL, `password` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, `country` char(2) NOT NULL, `avatar_bmp` blob NOT NULL, `registrationDate` datetime NOT NULL, `active` tinyint(1) NOT NULL, - `banned` tinyint(1) NOT NULL, `token` char(32) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=915 ; CREATE TABLE `cockatrice_uptime` ( + `id_server` tinyint(3) NOT NULL, `timest` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `uptime` int(11) DEFAULT NULL, `users_count` int(11) DEFAULT NULL, @@ -124,6 +126,7 @@ CREATE TABLE `cockatrice_uptime` ( ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE `cockatrice_servermessages` ( + `id_server` tinyint(3) not null default 0, `timest` datetime NOT NULL default '0000-00-00 00:00:00', `message` text, PRIMARY KEY (`timest`) @@ -132,12 +135,25 @@ CREATE TABLE `cockatrice_servermessages` ( CREATE TABLE `cockatrice_ignorelist` ( `id_user1` int(7) unsigned NOT NULL, `id_user2` int(7) unsigned NOT NULL, - UNIQUE KEY `key` (`id_user1`, `id_user2`) + UNIQUE KEY `key` (`id_user1`, `id_user2`), + KEY `id_user1` (`id_user1`), + KEY `id_user2` (`id_user2`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE `cockatrice_buddylist` ( `id_user1` int(7) unsigned NOT NULL, `id_user2` int(7) unsigned NOT NULL, - UNIQUE KEY `key` (`id_user1`, `id_user2`) + UNIQUE KEY `key` (`id_user1`, `id_user2`), + KEY `id_user1` (`id_user1`), + KEY `id_user2` (`id_user2`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +CREATE TABLE `cockatrice_bans` ( + `id_user` int(7) unsigned zerofill NOT NULL, + `id_admin` int(7) unsigned zerofill NOT NULL, + `time_from` datetime NOT NULL, + `minutes` int(6) NOT NULL, + `reason` text NOT NULL, + KEY `id_user` (`id_user`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp index 8dcd95fb4..247111be8 100644 --- a/servatrice/src/main.cpp +++ b/servatrice/src/main.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "servatrice.h" #include "server_logger.h" #include "rng_sfmt.h" @@ -30,6 +32,7 @@ RNG_Abstract *rng; ServerLogger *logger; +ServerLoggerThread *loggerThread; void testRNG() { @@ -65,14 +68,44 @@ void testRNG() std::cerr << std::endl << std::endl; } +void myMessageOutput(QtMsgType /*type*/, const char *msg) +{ + logger->logMessage(msg); +} + +#ifdef Q_OS_UNIX +void sigSegvHandler(int sig) +{ + if (sig == SIGSEGV) + logger->logMessage("CRASH: SIGSEGV"); + else if (sig == SIGABRT) + logger->logMessage("CRASH: SIGABRT"); + delete loggerThread; + raise(sig); +} +#endif + int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); app.setOrganizationName("Cockatrice"); app.setApplicationName("Servatrice"); + QStringList args = app.arguments(); + bool testRandom = args.contains("--test-random"); + + qRegisterMetaType >("QList"); + QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); - logger = new ServerLogger; + + QSettings *settings = new QSettings("servatrice.ini", QSettings::IniFormat); + + loggerThread = new ServerLoggerThread(settings->value("server/logfile").toString()); + loggerThread->start(); + loggerThread->waitForInit(); + logger = loggerThread->getLogger(); + + qInstallMsgHandler(myMessageOutput); #ifdef Q_OS_UNIX struct sigaction hup; hup.sa_handler = ServerLogger::hupSignalHandler; @@ -80,22 +113,36 @@ int main(int argc, char *argv[]) hup.sa_flags = 0; hup.sa_flags |= SA_RESTART; sigaction(SIGHUP, &hup, 0); + + struct sigaction segv; + segv.sa_handler = sigSegvHandler; + segv.sa_flags = SA_RESETHAND; + sigemptyset(&segv.sa_mask); + sigaction(SIGSEGV, &segv, 0); + sigaction(SIGABRT, &segv, 0); #endif rng = new RNG_SFMT; std::cerr << "Servatrice " << Servatrice::versionString.toStdString() << " starting." << std::endl; std::cerr << "-------------------------" << std::endl; - - testRNG(); - Servatrice server; + if (testRandom) + testRNG(); + + Servatrice *server = new Servatrice(settings); + QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()), Qt::QueuedConnection); std::cerr << "-------------------------" << std::endl; std::cerr << "Server initialized." << std::endl; int retval = app.exec(); + std::cerr << "Server quit." << std::endl; + std::cerr << "-------------------------" << std::endl; + delete rng; + delete settings; + delete loggerThread; return retval; } diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 8558de405..51ad91cbd 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -24,10 +24,27 @@ #include "servatrice.h" #include "server_room.h" #include "serversocketinterface.h" +#include "serversocketthread.h" #include "protocol.h" +#include "server_logger.h" +#include "main.h" -Servatrice::Servatrice(QObject *parent) - : Server(parent), uptime(0) +void Servatrice_TcpServer::incomingConnection(int socketDescriptor) +{ + if (threaded) { + ServerSocketThread *sst = new ServerSocketThread(socketDescriptor, server, this); + sst->start(); + } else { + QTcpSocket *socket = new QTcpSocket; + socket->setSocketDescriptor(socketDescriptor); + logger->logMessage(QString("incoming connection: %1").arg(socket->peerAddress().toString())); + + new ServerSocketInterface(server, socket); + } +} + +Servatrice::Servatrice(QSettings *_settings, QObject *parent) + : Server(parent), dbMutex(QMutex::Recursive), settings(_settings), uptime(0), shutdownTimer(0) { pingClock = new QTimer(this); connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout())); @@ -38,8 +55,8 @@ Servatrice::Servatrice(QObject *parent) banTimeoutClock->start(60000); ProtocolItem::initializeHash(); - settings = new QSettings("servatrice.ini", QSettings::IniFormat, this); + serverId = settings->value("server/id", 0).toInt(); int statusUpdateTime = settings->value("server/statusupdate").toInt(); statusUpdateClock = new QTimer(this); connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); @@ -48,11 +65,14 @@ Servatrice::Servatrice(QObject *parent) statusUpdateClock->start(statusUpdateTime); } - tcpServer = new QTcpServer(this); - connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); + threaded = settings->value("server/threaded", false).toInt(); + tcpServer = new Servatrice_TcpServer(this, threaded, this); int port = settings->value("server/port", 4747).toInt(); qDebug() << "Starting server on port" << port; - tcpServer->listen(QHostAddress::Any, port); + if (tcpServer->listen(QHostAddress::Any, port)) + qDebug() << "Server listening."; + else + qDebug() << "tcpServer->listen(): Error."; QString dbType = settings->value("database/type").toString(); dbPrefix = settings->value("database/prefix").toString(); @@ -93,10 +113,13 @@ Servatrice::Servatrice(QObject *parent) messageCountingInterval = settings->value("security/message_counting_interval").toInt(); maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt(); maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt(); + maxGamesPerUser = settings->value("security/max_games_per_user").toInt(); } Servatrice::~Servatrice() { + prepareDestroy(); + QSqlDatabase::database().close(); } bool Servatrice::openDatabase() @@ -133,6 +156,7 @@ bool Servatrice::openDatabase() void Servatrice::checkSql() { + QMutexLocker locker(&dbMutex); if (!QSqlDatabase::database().exec("select 1").isActive()) openDatabase(); } @@ -145,31 +169,32 @@ bool Servatrice::execSqlQuery(QSqlQuery &query) return false; } -void Servatrice::newConnection() +AuthenticationResult Servatrice::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password) { - QTcpSocket *socket = tcpServer->nextPendingConnection(); - ServerSocketInterface *ssi = new ServerSocketInterface(this, socket); - addClient(ssi); -} + serverMutex.lock(); + QHostAddress address = static_cast(handler)->getPeerAddress(); + for (int i = 0; i < addressBanList.size(); ++i) + if (address == addressBanList[i].first) + return PasswordWrong; + serverMutex.unlock(); -AuthenticationResult Servatrice::checkUserPassword(const QString &user, const QString &password) -{ + QMutexLocker locker(&dbMutex); const QString method = settings->value("authentication/method").toString(); if (method == "none") return UnknownUser; else if (method == "sql") { checkSql(); - + QSqlQuery query; - query.prepare("select banned, password from " + dbPrefix + "_users where name = :name and active = 1"); + query.prepare("select a.password, time_to_sec(timediff(now(), date_add(b.time_from, interval b.minutes minute))) < 0, b.minutes <=> 0 from " + dbPrefix + "_users a left join " + dbPrefix + "_bans b on b.id_user = a.id and b.time_from = (select max(c.time_from) from " + dbPrefix + "_bans c where c.id_user = a.id) where a.name = :name and a.active = 1"); query.bindValue(":name", user); if (!execSqlQuery(query)) return PasswordWrong; if (query.next()) { - if (query.value(0).toInt()) + if (query.value(1).toInt() || query.value(2).toInt()) return PasswordWrong; - if (query.value(1).toString() == password) + if (query.value(0).toString() == password) return PasswordRight; else return PasswordWrong; @@ -181,6 +206,7 @@ AuthenticationResult Servatrice::checkUserPassword(const QString &user, const QS bool Servatrice::userExists(const QString &user) { + QMutexLocker locker(&dbMutex); const QString method = settings->value("authentication/method").toString(); if (method == "sql") { checkSql(); @@ -199,19 +225,31 @@ ServerInfo_User *Servatrice::evalUserQueryResult(const QSqlQuery &query, bool co QString name = query.value(0).toString(); bool is_admin = query.value(1).toInt(); QString realName = query.value(2).toString(); - QString country = query.value(3).toString(); + QString genderStr = query.value(3).toString(); + QString country = query.value(4).toString(); QByteArray avatarBmp; if (complete) - avatarBmp = query.value(4).toByteArray(); + avatarBmp = query.value(5).toByteArray(); + + ServerInfo_User::Gender gender; + if (genderStr == "m") + gender = ServerInfo_User::Male; + else if (genderStr == "f") + gender = ServerInfo_User::Female; + else + gender = ServerInfo_User::GenderUnknown; int userLevel = ServerInfo_User::IsUser | ServerInfo_User::IsRegistered; - if (is_admin) - userLevel |= ServerInfo_User::IsAdmin; + if (is_admin == 1) + userLevel |= ServerInfo_User::IsAdmin | ServerInfo_User::IsModerator; + else if (is_admin == 2) + userLevel |= ServerInfo_User::IsModerator; return new ServerInfo_User( name, userLevel, realName, + gender, country, avatarBmp ); @@ -219,12 +257,13 @@ ServerInfo_User *Servatrice::evalUserQueryResult(const QSqlQuery &query, bool co ServerInfo_User *Servatrice::getUserData(const QString &name) { + QMutexLocker locker(&dbMutex); const QString method = settings->value("authentication/method").toString(); if (method == "sql") { checkSql(); QSqlQuery query; - query.prepare("select name, admin, realname, country, avatar_bmp from " + dbPrefix + "_users where name = :name and active = 1"); + query.prepare("select name, admin, realname, gender, 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); @@ -239,6 +278,7 @@ ServerInfo_User *Servatrice::getUserData(const QString &name) int Servatrice::getUsersWithAddress(const QHostAddress &address) const { + QMutexLocker locker(&serverMutex); int result = 0; for (int i = 0; i < clients.size(); ++i) if (static_cast(clients[i])->getPeerAddress() == address) @@ -248,6 +288,7 @@ int Servatrice::getUsersWithAddress(const QHostAddress &address) const QMap Servatrice::getBuddyList(const QString &name) { + QMutexLocker locker(&dbMutex); QMap result; const QString method = settings->value("authentication/method").toString(); @@ -255,7 +296,7 @@ QMap Servatrice::getBuddyList(const QString &name) checkSql(); QSqlQuery query; - query.prepare("select a.name, a.admin, a.realname, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_buddylist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name"); + query.prepare("select a.name, a.admin, a.realname, a.gender, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_buddylist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name"); query.bindValue(":name", name); if (!execSqlQuery(query)) return result; @@ -270,6 +311,7 @@ QMap Servatrice::getBuddyList(const QString &name) QMap Servatrice::getIgnoreList(const QString &name) { + QMutexLocker locker(&dbMutex); QMap result; const QString method = settings->value("authentication/method").toString(); @@ -277,7 +319,7 @@ QMap Servatrice::getIgnoreList(const QString &name) checkSql(); QSqlQuery query; - query.prepare("select a.name, a.admin, a.realname, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_ignorelist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name"); + query.prepare("select a.name, a.admin, a.realname, a.gender, a.country from " + dbPrefix + "_users a left join " + dbPrefix + "_ignorelist b on a.id = b.id_user2 left join " + dbPrefix + "_users c on b.id_user1 = c.id where c.name = :name"); query.bindValue(":name", name); if (!execSqlQuery(query)) return result; @@ -290,37 +332,23 @@ QMap Servatrice::getIgnoreList(const QString &name) return result; } -bool Servatrice::getUserBanned(Server_ProtocolHandler *client, const QString &userName) const -{ - QHostAddress address = static_cast(client)->getPeerAddress(); - for (int i = 0; i < addressBanList.size(); ++i) - if (address == addressBanList[i].first) - return true; - for (int i = 0; i < nameBanList.size(); ++i) - if (userName == nameBanList[i].first) - return true; - return false; -} - void Servatrice::updateBanTimer() { + QMutexLocker locker(&serverMutex); for (int i = 0; i < addressBanList.size(); ) if (--(addressBanList[i].second) <= 0) addressBanList.removeAt(i); else ++i; - for (int i = 0; i < nameBanList.size(); ) - if (--(nameBanList[i].second) <= 0) - nameBanList.removeAt(i); - else - ++i; } void Servatrice::updateLoginMessage() { + QMutexLocker locker(&dbMutex); checkSql(); QSqlQuery query; - query.prepare("select message from " + dbPrefix + "_servermessages order by timest desc limit 1"); + query.prepare("select message from " + dbPrefix + "_servermessages where id_server = :id_server order by timest desc limit 1"); + query.bindValue(":id_server", serverId); if (execSqlQuery(query)) if (query.next()) { loginMessage = query.value(0).toString(); @@ -336,16 +364,55 @@ void Servatrice::updateLoginMessage() void Servatrice::statusUpdate() { + const int uc = getUsersCount(); // for correct mutex locking order + const int gc = getGamesCount(); + uptime += statusUpdateClock->interval() / 1000; + QMutexLocker locker(&dbMutex); checkSql(); QSqlQuery query; - query.prepare("insert into " + dbPrefix + "_uptime (timest, uptime, users_count, games_count) values(NOW(), :uptime, :users_count, :games_count)"); + query.prepare("insert into " + dbPrefix + "_uptime (id_server, timest, uptime, users_count, games_count) values(:id, NOW(), :uptime, :users_count, :games_count)"); + query.bindValue(":id", serverId); query.bindValue(":uptime", uptime); - query.bindValue(":users_count", users.size()); - query.bindValue(":games_count", games.size()); + query.bindValue(":users_count", uc); + query.bindValue(":games_count", gc); execSqlQuery(query); } -const QString Servatrice::versionString = "Servatrice 0.20110303"; +void Servatrice::scheduleShutdown(const QString &reason, int minutes) +{ + QMutexLocker locker(&serverMutex); + + shutdownReason = reason; + shutdownMinutes = minutes + 1; + if (minutes > 0) { + shutdownTimer = new QTimer; + connect(shutdownTimer, SIGNAL(timeout()), this, SLOT(shutdownTimeout())); + shutdownTimer->start(60000); + } + shutdownTimeout(); +} + +void Servatrice::shutdownTimeout() +{ + QMutexLocker locker(&serverMutex); + + --shutdownMinutes; + + GenericEvent *event; + if (shutdownMinutes) + event = new Event_ServerShutdown(shutdownReason, shutdownMinutes); + else + event = new Event_ConnectionClosed("server_shutdown"); + + for (int i = 0; i < clients.size(); ++i) + clients[i]->sendProtocolItem(event, false); + delete event; + + if (!shutdownMinutes) + deleteLater(); +} + +const QString Servatrice::versionString = "Servatrice 0.20110625"; diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index c53b5338d..8dae2c91f 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -21,6 +21,7 @@ #define SERVATRICE_H #include +#include #include "server.h" class QSqlDatabase; @@ -28,16 +29,32 @@ class QSettings; class QSqlQuery; class QTimer; +class Servatrice; +class ServerSocketInterface; + +class Servatrice_TcpServer : public QTcpServer { + Q_OBJECT +private: + Servatrice *server; + bool threaded; +public: + Servatrice_TcpServer(Servatrice *_server, bool _threaded, QObject *parent = 0) + : QTcpServer(parent), server(_server), threaded(_threaded) { } +protected: + void incomingConnection(int socketDescriptor); +}; + class Servatrice : public Server { Q_OBJECT private slots: - void newConnection(); void statusUpdate(); void updateBanTimer(); + void shutdownTimeout(); public: + QMutex dbMutex; static const QString versionString; - Servatrice(QObject *parent = 0); + Servatrice(QSettings *_settings, QObject *parent = 0); ~Servatrice(); bool openDatabase(); void checkSql(); @@ -50,30 +67,36 @@ public: int getMessageCountingInterval() const { return messageCountingInterval; } int getMaxMessageCountPerInterval() const { return maxMessageCountPerInterval; } int getMaxMessageSizePerInterval() const { return maxMessageSizePerInterval; } + int getMaxGamesPerUser() const { return maxGamesPerUser; } + bool getThreaded() const { return threaded; } QString getDbPrefix() const { return dbPrefix; } void updateLoginMessage(); ServerInfo_User *getUserData(const QString &name); int getUsersWithAddress(const QHostAddress &address) const; QMap getBuddyList(const QString &name); QMap getIgnoreList(const QString &name); - bool getUserBanned(Server_ProtocolHandler *client, const QString &userName) const; void addAddressBan(const QHostAddress &address, int minutes) { addressBanList.append(QPair(address, minutes)); } - void addNameBan(const QString &name, int minutes) { nameBanList.append(QPair(name, minutes)); } + void scheduleShutdown(const QString &reason, int minutes); protected: bool userExists(const QString &user); - AuthenticationResult checkUserPassword(const QString &user, const QString &password); + AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password); private: QTimer *pingClock, *statusUpdateClock, *banTimeoutClock; QTcpServer *tcpServer; QString loginMessage; QString dbPrefix; QSettings *settings; + int serverId; + bool threaded; int uptime; QList > addressBanList; - QList > nameBanList; int maxGameInactivityTime, maxPlayerInactivityTime; - int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval; + int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser; ServerInfo_User *evalUserQueryResult(const QSqlQuery &query, bool complete); + + QString shutdownReason; + int shutdownMinutes; + QTimer *shutdownTimer; }; #endif diff --git a/servatrice/src/server_logger.cpp b/servatrice/src/server_logger.cpp index 60a056af3..7cfaf3ed3 100644 --- a/servatrice/src/server_logger.cpp +++ b/servatrice/src/server_logger.cpp @@ -2,39 +2,87 @@ #include #include #include -#include -#include - -ServerLogger::ServerLogger(QObject *parent) - : QObject(parent) -{ - logFile = new QFile("server.log", this); - logFile->open(QIODevice::Append); +#include #ifdef Q_OS_UNIX - ::socketpair(AF_UNIX, SOCK_STREAM, 0, sigHupFD); +# include +# include #endif - snHup = new QSocketNotifier(sigHupFD[1], QSocketNotifier::Read, this); - connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup())); + +ServerLogger::ServerLogger(const QString &logFileName, QObject *parent) + : QObject(parent), flushRunning(false) +{ + if (!logFileName.isEmpty()) { + logFile = new QFile("server.log", this); + logFile->open(QIODevice::Append); +#ifdef Q_OS_UNIX + ::socketpair(AF_UNIX, SOCK_STREAM, 0, sigHupFD); + + snHup = new QSocketNotifier(sigHupFD[1], QSocketNotifier::Read, this); + connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup())); +#endif + } else + logFile = 0; + + connect(this, SIGNAL(sigFlushBuffer()), this, SLOT(flushBuffer()), Qt::QueuedConnection); } ServerLogger::~ServerLogger() { + flushBuffer(); } -void ServerLogger::logMessage(QString message) +void ServerLogger::logMessage(QString message, ServerSocketInterface *ssi) { - QTextStream stream(logFile); - stream << message << "\n"; + if (!logFile) + return; + + bufferMutex.lock(); + QString ssiString; + if (ssi) + ssiString = QString::number((qulonglong) ssi) + " "; + buffer.append(QDateTime::currentDateTime().toString() + " " + QString::number((qulonglong) QThread::currentThread(), 16) + " " + ssiString + message); + bufferMutex.unlock(); + + emit sigFlushBuffer(); } +void ServerLogger::flushBuffer() +{ + if (flushRunning) + return; + + flushRunning = true; + QTextStream stream(logFile); + forever { + bufferMutex.lock(); + if (buffer.isEmpty()) { + bufferMutex.unlock(); + flushRunning = false; + return; + } + QString message = buffer.takeFirst(); + bufferMutex.unlock(); + + stream << message << "\n"; + stream.flush(); + } +} + +#ifdef Q_OS_UNIX void ServerLogger::hupSignalHandler(int /*unused*/) { + if (!logFile) + return; + char a = 1; ::write(sigHupFD[0], &a, sizeof(a)); } void ServerLogger::handleSigHup() { + if (!logFile) + return; + snHup->setEnabled(false); char tmp; ::read(sigHupFD[1], &tmp, sizeof(tmp)); @@ -44,6 +92,38 @@ void ServerLogger::handleSigHup() snHup->setEnabled(true); } +#endif QFile *ServerLogger::logFile; int ServerLogger::sigHupFD[2]; + +ServerLoggerThread::ServerLoggerThread(const QString &_fileName, QObject *parent) + : QThread(parent), fileName(_fileName) +{ +} + +ServerLoggerThread::~ServerLoggerThread() +{ + quit(); + wait(); +} + +void ServerLoggerThread::run() +{ + logger = new ServerLogger(fileName); + + usleep(100); + initWaitCondition.wakeAll(); + + exec(); + + delete logger; +} + +void ServerLoggerThread::waitForInit() +{ + QMutex mutex; + mutex.lock(); + initWaitCondition.wait(&mutex); + mutex.unlock(); +} diff --git a/servatrice/src/server_logger.h b/servatrice/src/server_logger.h index a9bd3eec1..77c7f12d7 100644 --- a/servatrice/src/server_logger.h +++ b/servatrice/src/server_logger.h @@ -2,24 +2,52 @@ #define SERVER_LOGGER_H #include +#include +#include +#include +#include class QSocketNotifier; class QFile; +class ServerSocketInterface; class ServerLogger : public QObject { Q_OBJECT public: - ServerLogger(QObject *parent = 0); + ServerLogger(const QString &logFileName, QObject *parent = 0); ~ServerLogger(); static void hupSignalHandler(int unused); public slots: - void logMessage(QString message); + void logMessage(QString message, ServerSocketInterface *ssi = 0); private slots: +#ifdef Q_OS_UNIX void handleSigHup(); +#endif + void flushBuffer(); +signals: + void sigFlushBuffer(); private: static int sigHupFD[2]; QSocketNotifier *snHup; static QFile *logFile; + bool flushRunning; + QStringList buffer; + QMutex bufferMutex; +}; + +class ServerLoggerThread : public QThread { + Q_OBJECT +private: + QString fileName; + ServerLogger *logger; + QWaitCondition initWaitCondition; +protected: + void run(); +public: + ServerLoggerThread(const QString &_fileName, QObject *parent = 0); + ~ServerLoggerThread(); + ServerLogger *getLogger() const { return logger; } + void waitForInit(); }; #endif diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index 115457b4c..91c7a6b95 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -33,20 +33,20 @@ #include "server_logger.h" ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent) - : Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), topLevelItem(0) + : Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), topLevelItem(0), compressionSupport(false) { - xmlWriter = new QXmlStreamWriter; - xmlWriter->setDevice(socket); - + xmlWriter = new QXmlStreamWriter(&xmlBuffer); xmlReader = new QXmlStreamReader; connect(socket, SIGNAL(readyRead()), this, SLOT(readClient())); connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(catchSocketError(QAbstractSocket::SocketError))); + connect(this, SIGNAL(xmlBufferChanged()), this, SLOT(flushXmlBuffer()), Qt::QueuedConnection); xmlWriter->writeStartDocument(); xmlWriter->writeStartElement("cockatrice_server_stream"); xmlWriter->writeAttribute("version", QString::number(ProtocolItem::protocolVersion)); + flushXmlBuffer(); int maxUsers = _server->getMaxUsersPerAddress(); if ((maxUsers > 0) && (_server->getUsersWithAddress(socket->peerAddress()) >= maxUsers)) { @@ -54,16 +54,22 @@ ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_s deleteLater(); } else sendProtocolItem(new Event_ServerMessage(Servatrice::versionString)); + + server->addClient(this); } ServerSocketInterface::~ServerSocketInterface() { logger->logMessage("ServerSocketInterface destructor"); - socket->flush(); + prepareDestroy(); + + flushXmlBuffer(); delete xmlWriter; delete xmlReader; delete socket; + socket = 0; + delete topLevelItem; } void ServerSocketInterface::processProtocolItem(ProtocolItem *item) @@ -75,10 +81,21 @@ void ServerSocketInterface::processProtocolItem(ProtocolItem *item) processCommandContainer(cont); } +void ServerSocketInterface::flushXmlBuffer() +{ + QMutexLocker locker(&xmlBufferMutex); + if (xmlBuffer.isEmpty()) + return; + socket->write(xmlBuffer.toUtf8()); + socket->flush(); + xmlBuffer.clear(); +} + void ServerSocketInterface::readClient() { QByteArray data = socket->readAll(); - logger->logMessage(QString(data)); + if (!data.contains("logMessage(QString(data), this); xmlReader->addData(data); while (!xmlReader->atEnd()) { @@ -86,6 +103,8 @@ void ServerSocketInterface::readClient() if (topLevelItem) topLevelItem->readElement(xmlReader); else if (xmlReader->isStartElement() && (xmlReader->name().toString() == "cockatrice_client_stream")) { + if (xmlReader->attributes().value("comp").toString().toInt() == 1) + compressionSupport = true; topLevelItem = new TopLevelProtocolItem; connect(topLevelItem, SIGNAL(protocolItemReceived(ProtocolItem *)), this, SLOT(processProtocolItem(ProtocolItem *))); } @@ -101,14 +120,18 @@ void ServerSocketInterface::catchSocketError(QAbstractSocket::SocketError socket void ServerSocketInterface::sendProtocolItem(ProtocolItem *item, bool deleteItem) { + QMutexLocker locker(&xmlBufferMutex); + item->write(xmlWriter); - socket->flush(); if (deleteItem) delete item; + + emit xmlBufferChanged(); } int ServerSocketInterface::getUserIdInDB(const QString &name) const { + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("select id from " + servatrice->getDbPrefix() + "_users where name = :name"); query.bindValue(":name", name); @@ -142,6 +165,7 @@ ResponseCode ServerSocketInterface::cmdAddToList(Command_AddToList *cmd, Command if (id1 == id2) return RespContextError; + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("insert into " + servatrice->getDbPrefix() + "_" + list + "list (id_user1, id_user2) values(:id1, :id2)"); query.bindValue(":id1", id1); @@ -180,6 +204,7 @@ ResponseCode ServerSocketInterface::cmdRemoveFromList(Command_RemoveFromList *cm if (id2 < 0) return RespNameNotFound; + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("delete from " + servatrice->getDbPrefix() + "_" + list + "list where id_user1 = :id1 and id_user2 = :id2"); query.bindValue(":id1", id1); @@ -206,6 +231,7 @@ int ServerSocketInterface::getDeckPathId(int basePathId, QStringList path) if (path[0].isEmpty()) return 0; + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("select id from " + servatrice->getDbPrefix() + "_decklist_folders where id_parent = :id_parent and name = :name and user = :user"); query.bindValue(":id_parent", basePathId); @@ -229,6 +255,7 @@ int ServerSocketInterface::getDeckPathId(const QString &path) bool ServerSocketInterface::deckListHelper(DeckList_Directory *folder) { + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("select id, name from " + servatrice->getDbPrefix() + "_decklist_folders where id_parent = :id_parent and user = :user"); query.bindValue(":id_parent", folder->getId()); @@ -272,7 +299,10 @@ ResponseCode ServerSocketInterface::cmdDeckList(Command_DeckList * /*cmd*/, Comm if (!deckListHelper(root)) return RespContextError; - cont->setResponse(new Response_DeckList(cont->getCmdId(), RespOk, root)); + ProtocolResponse *resp = new Response_DeckList(cont->getCmdId(), RespOk, root); + if (getCompressionSupport()) + resp->setCompressed(true); + cont->setResponse(resp); return RespNothing; } @@ -288,6 +318,7 @@ ResponseCode ServerSocketInterface::cmdDeckNewDir(Command_DeckNewDir *cmd, Comma if (folderId == -1) return RespNameNotFound; + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("insert into " + servatrice->getDbPrefix() + "_decklist_folders (id_parent, user, name) values(:id_parent, :user, :name)"); query.bindValue(":id_parent", folderId); @@ -302,6 +333,7 @@ void ServerSocketInterface::deckDelDirHelper(int basePathId) { servatrice->checkSql(); + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("select id from " + servatrice->getDbPrefix() + "_decklist_folders where id_parent = :id_parent"); @@ -340,6 +372,7 @@ ResponseCode ServerSocketInterface::cmdDeckDel(Command_DeckDel *cmd, CommandCont servatrice->checkSql(); + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("select id from " + servatrice->getDbPrefix() + "_decklist_files where id = :id and user = :user"); @@ -379,6 +412,7 @@ ResponseCode ServerSocketInterface::cmdDeckUpload(Command_DeckUpload *cmd, Comma if (deckName.isEmpty()) deckName = "Unnamed deck"; + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("insert into " + servatrice->getDbPrefix() + "_decklist_files (id_folder, user, name, upload_time, content) values(:id_folder, :user, :name, NOW(), :content)"); query.bindValue(":id_folder", folderId); @@ -395,6 +429,7 @@ DeckList *ServerSocketInterface::getDeckFromDatabase(int deckId) { servatrice->checkSql(); + QMutexLocker locker(&servatrice->dbMutex); QSqlQuery query; query.prepare("select content from " + servatrice->getDbPrefix() + "_decklist_files where id = :id and user = :user"); @@ -426,8 +461,8 @@ ResponseCode ServerSocketInterface::cmdDeckDownload(Command_DeckDownload *cmd, C return RespNothing; } -// ADMIN FUNCTIONS. -// Permission is checked by the calling function. +// MODERATOR FUNCTIONS. +// May be called by admins and moderators. Permission is checked by the calling function. ResponseCode ServerSocketInterface::cmdUpdateServerMessage(Command_UpdateServerMessage * /*cmd*/, CommandContainer * /*cont*/) { @@ -435,6 +470,15 @@ ResponseCode ServerSocketInterface::cmdUpdateServerMessage(Command_UpdateServerM return RespOk; } +// ADMIN FUNCTIONS. +// Permission is checked by the calling function. + +ResponseCode ServerSocketInterface::cmdShutdownServer(Command_ShutdownServer *cmd, CommandContainer * /*cont*/) +{ + servatrice->scheduleShutdown(cmd->getReason(), cmd->getMinutes()); + return RespOk; +} + ResponseCode ServerSocketInterface::cmdBanFromServer(Command_BanFromServer *cmd, CommandContainer * /*cont*/) { QString userName = cmd->getUserName(); @@ -446,13 +490,14 @@ ResponseCode ServerSocketInterface::cmdBanFromServer(Command_BanFromServer *cmd, ServerSocketInterface *user = static_cast(server->getUsers().value(userName)); if (user->getUserInfo()->getUserLevel() & ServerInfo_User::IsRegistered) { // Registered users can be banned by name. - if (minutes == 0) { - QSqlQuery query; - query.prepare("update " + servatrice->getDbPrefix() + "_users set banned=1 where name = :name"); - query.bindValue(":name", userName); - servatrice->execSqlQuery(query); - } else - servatrice->addNameBan(userName, minutes); + QMutexLocker locker(&servatrice->dbMutex); + QSqlQuery query; + query.prepare("insert into " + servatrice->getDbPrefix() + "_bans (id_user, id_admin, time_from, minutes, reason) values(:id_user, :id_admin, NOW(), :minutes, :reason)"); + query.bindValue(":id_user", getUserIdInDB(userName)); + query.bindValue(":id_admin", getUserIdInDB(userInfo->getName())); + query.bindValue(":minutes", minutes); + query.bindValue(":reason", cmd->getReason() + "\n"); + servatrice->execSqlQuery(query); } else { // Unregistered users must be banned by IP address. // Indefinite address bans are not reasonable -> default to 30 minutes. diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index f55dfd128..14cf7030e 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -22,6 +22,7 @@ #include #include +#include #include "server_protocolhandler.h" class QTcpSocket; @@ -30,6 +31,7 @@ class QXmlStreamReader; class QXmlStreamWriter; class DeckList; class TopLevelProtocolItem; +class QByteArray; class ServerSocketInterface : public Server_ProtocolHandler { @@ -38,12 +40,18 @@ private slots: void readClient(); void catchSocketError(QAbstractSocket::SocketError socketError); void processProtocolItem(ProtocolItem *item); + void flushXmlBuffer(); +signals: + void xmlBufferChanged(); private: + QMutex xmlBufferMutex; Servatrice *servatrice; QTcpSocket *socket; QXmlStreamWriter *xmlWriter; QXmlStreamReader *xmlReader; + QString xmlBuffer; TopLevelProtocolItem *topLevelItem; + bool compressionSupport; int getUserIdInDB(const QString &name) const; ResponseCode cmdAddToList(Command_AddToList *cmd, CommandContainer *cont); @@ -59,8 +67,11 @@ 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); ResponseCode cmdBanFromServer(Command_BanFromServer *cmd, CommandContainer *cont); + ResponseCode cmdShutdownServer(Command_ShutdownServer *cmd, CommandContainer *cont); + ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont); +protected: + bool getCompressionSupport() const { return compressionSupport; } public: ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent = 0); ~ServerSocketInterface(); diff --git a/servatrice/src/serversocketthread.cpp b/servatrice/src/serversocketthread.cpp new file mode 100644 index 000000000..9c08ce1b9 --- /dev/null +++ b/servatrice/src/serversocketthread.cpp @@ -0,0 +1,27 @@ +#include "serversocketthread.h" +#include "serversocketinterface.h" +#include "server_logger.h" +#include "main.h" + +ServerSocketThread::ServerSocketThread(int _socketDescriptor, Servatrice *_server, QObject *parent) + : QThread(parent), server(_server), socketDescriptor(_socketDescriptor) +{ +} + +ServerSocketThread::~ServerSocketThread() +{ + quit(); + wait(); +} + +void ServerSocketThread::run() +{ + QTcpSocket *socket = new QTcpSocket; + socket->setSocketDescriptor(socketDescriptor); + logger->logMessage(QString("incoming connection: %1").arg(socket->peerAddress().toString())); + + ssi = new ServerSocketInterface(server, socket); + connect(ssi, SIGNAL(destroyed()), this, SLOT(deleteLater())); + + exec(); +} diff --git a/servatrice/src/serversocketthread.h b/servatrice/src/serversocketthread.h new file mode 100644 index 000000000..2aa6dc8bd --- /dev/null +++ b/servatrice/src/serversocketthread.h @@ -0,0 +1,22 @@ +#ifndef SERVERSOCKETTHREAD_H +#define SERVERSOCKETTHREAD_H + +#include + +class Servatrice; +class ServerSocketInterface; + +class ServerSocketThread : public QThread { + Q_OBJECT +private: + Servatrice *server; + ServerSocketInterface *ssi; + int socketDescriptor; +public: + ServerSocketThread(int _socketDescriptor, Servatrice *_server, QObject *parent = 0); + ~ServerSocketThread(); +protected: + void run(); +}; + +#endif diff --git a/sounds/cuckoo.raw b/sounds/cuckoo.raw new file mode 100644 index 000000000..52f0cbb60 Binary files /dev/null and b/sounds/cuckoo.raw differ diff --git a/sounds/cuckoo.wav b/sounds/cuckoo.wav new file mode 100644 index 000000000..5eba46f97 Binary files /dev/null and b/sounds/cuckoo.wav differ diff --git a/sounds/draw.raw b/sounds/draw.raw new file mode 100644 index 000000000..3732125f2 Binary files /dev/null and b/sounds/draw.raw differ diff --git a/sounds/notification.raw b/sounds/notification.raw new file mode 100644 index 000000000..19906b48d Binary files /dev/null and b/sounds/notification.raw differ diff --git a/sounds/playcard.raw b/sounds/playcard.raw new file mode 100644 index 000000000..c9fb802dc Binary files /dev/null and b/sounds/playcard.raw differ diff --git a/sounds/shuffle.raw b/sounds/shuffle.raw new file mode 100644 index 000000000..f092e5678 Binary files /dev/null and b/sounds/shuffle.raw differ diff --git a/sounds/tap.raw b/sounds/tap.raw new file mode 100644 index 000000000..db5290a87 Binary files /dev/null and b/sounds/tap.raw differ diff --git a/sounds/untap.raw b/sounds/untap.raw new file mode 100644 index 000000000..938efe260 Binary files /dev/null and b/sounds/untap.raw differ