diff --git a/cmake/NSIS.template.in b/cmake/NSIS.template.in index 2e1910f5..c62a192c 100644 --- a/cmake/NSIS.template.in +++ b/cmake/NSIS.template.in @@ -16,7 +16,7 @@ InstallDir "$PROGRAMFILES\Cockatrice" !define MUI_HEADERIMAGE_UNBITMAP "${NSIS_SOURCE_PATH}\cmake\headerimage.bmp" !define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of Cockatrice.$\r$\n$\r$\nClick Next to continue." !define MUI_FINISHPAGE_RUN "$INSTDIR/oracle.exe" -!define MUI_FINISHPAGE_RUN_TEXT "Run card database downloader now" +!define MUI_FINISHPAGE_RUN_TEXT "Run 'Oracle' now to update your card database" !define MUI_FINISHPAGE_RUN_PARAMETERS "-dlsets" !insertmacro MUI_PAGE_WELCOME diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc index 08e2a43a..704e28cb 100644 --- a/cockatrice/cockatrice.qrc +++ b/cockatrice/cockatrice.qrc @@ -31,12 +31,14 @@ resources/icon_view.svg resources/hr.jpg resources/cockatrice.svg + resources/add_to_sideboard.svg resources/decrement.svg resources/increment.svg resources/remove_row.svg resources/arrow_left_green.svg resources/arrow_right_green.svg + resources/icon_ready_start.svg resources/icon_not_ready_start.svg resources/icon_conceded.svg @@ -320,8 +322,11 @@ resources/userlevels/normal.svg resources/userlevels/registered.svg + resources/userlevels/registered_buddy.svg resources/userlevels/moderator.svg + resources/userlevels/moderator_buddy.svg resources/userlevels/admin.svg + resources/userlevels/admin_buddy.svg resources/news/exclamation_mark.svg resources/news/question_mark.svg diff --git a/cockatrice/resources/decrement.svg b/cockatrice/resources/decrement.svg index 832e1991..0ceddf69 100644 --- a/cockatrice/resources/decrement.svg +++ b/cockatrice/resources/decrement.svg @@ -1,5 +1,6 @@ + @@ -161,15 +162,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7.625" - inkscape:cx="-58.636066" - inkscape:cy="34.091284" + inkscape:cx="26.34754" + inkscape:cy="29.107677" inkscape:document-units="px" inkscape:current-layer="layer2" showgrid="false" - inkscape:window-width="1272" - inkscape:window-height="723" + inkscape:window-width="1445" + inkscape:window-height="893" inkscape:window-x="0" - inkscape:window-y="25" /> + inkscape:window-y="25" + inkscape:window-maximized="0" /> @@ -192,7 +194,7 @@ inkscape:label="Pfeil" style="display:inline"> + @@ -316,15 +317,16 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7.625" - inkscape:cx="-50.74814" - inkscape:cy="31.784541" + inkscape:cx="-27.27273" + inkscape:cy="30.210771" inkscape:document-units="px" inkscape:current-layer="layer2" showgrid="false" inkscape:window-width="1272" inkscape:window-height="723" inkscape:window-x="0" - inkscape:window-y="25" /> + inkscape:window-y="25" + inkscape:window-maximized="0" /> @@ -347,7 +349,7 @@ inkscape:label="Pfeil" style="display:inline"> diff --git a/cockatrice/resources/userlevels/admin_buddy.svg b/cockatrice/resources/userlevels/admin_buddy.svg new file mode 100644 index 00000000..0d4defb5 --- /dev/null +++ b/cockatrice/resources/userlevels/admin_buddy.svg @@ -0,0 +1,125 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/userlevels/moderator_buddy.svg b/cockatrice/resources/userlevels/moderator_buddy.svg new file mode 100644 index 00000000..677c6e13 --- /dev/null +++ b/cockatrice/resources/userlevels/moderator_buddy.svg @@ -0,0 +1,147 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/resources/userlevels/registered_buddy.svg b/cockatrice/resources/userlevels/registered_buddy.svg new file mode 100644 index 00000000..14fcd596 --- /dev/null +++ b/cockatrice/resources/userlevels/registered_buddy.svg @@ -0,0 +1,115 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cockatrice/src/carddatabase.cpp b/cockatrice/src/carddatabase.cpp index 3cd9f313..31344a8f 100644 --- a/cockatrice/src/carddatabase.cpp +++ b/cockatrice/src/carddatabase.cpp @@ -365,6 +365,7 @@ CardInfo::CardInfo(CardDatabase *_db, const QString &_name, bool _isToken, const QString &_manacost, + const QString &_cmc, const QString &_cardtype, const QString &_powtough, const QString &_text, @@ -381,6 +382,7 @@ CardInfo::CardInfo(CardDatabase *_db, isToken(_isToken), sets(_sets), manacost(_manacost), + cmc(_cmc), cardtype(_cardtype), powtough(_powtough), text(_text), @@ -571,6 +573,7 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfo *info) xml.writeTextElement("color", colors[i]); xml.writeTextElement("manacost", info->getManaCost()); + xml.writeTextElement("cmc", info->getCmc()); xml.writeTextElement("type", info->getCardType()); if (!info->getPowTough().isEmpty()) xml.writeTextElement("pt", info->getPowTough()); @@ -731,7 +734,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens) if (xml.readNext() == QXmlStreamReader::EndElement) break; if (xml.name() == "card") { - QString name, manacost, type, pt, text; + QString name, manacost, cmc, type, pt, text; QStringList colors; QStringMap customPicURLs, customPicURLsHq; MuidMap muids; @@ -747,6 +750,8 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens) name = xml.readElementText(); else if (xml.name() == "manacost") manacost = xml.readElementText(); + else if (xml.name() == "cmc") + cmc = xml.readElementText(); else if (xml.name() == "type") type = xml.readElementText(); else if (xml.name() == "pt") @@ -779,7 +784,7 @@ void CardDatabase::loadCardsFromXml(QXmlStreamReader &xml, bool tokens) } if (isToken == tokens) { - addCard(new CardInfo(this, name, isToken, manacost, type, pt, text, colors, loyalty, cipt, tableRow, sets, customPicURLs, customPicURLsHq, muids)); + addCard(new CardInfo(this, name, isToken, manacost, cmc, type, pt, text, colors, loyalty, cipt, tableRow, sets, customPicURLs, customPicURLsHq, muids)); } } } diff --git a/cockatrice/src/carddatabase.h b/cockatrice/src/carddatabase.h index bbd0260f..56e18bc4 100644 --- a/cockatrice/src/carddatabase.h +++ b/cockatrice/src/carddatabase.h @@ -111,6 +111,7 @@ private: bool isToken; SetList sets; QString manacost; + QString cmc; QString cardtype; QString powtough; QString text; @@ -126,6 +127,7 @@ public: const QString &_name = QString(), bool _isToken = false, const QString &_manacost = QString(), + const QString &_cmc = QString(), const QString &_cardtype = QString(), const QString &_powtough = QString(), const QString &_text = QString(), @@ -142,12 +144,14 @@ public: bool getIsToken() const { return isToken; } const SetList &getSets() const { return sets; } const QString &getManaCost() const { return manacost; } + const QString &getCmc() const { return cmc; } const QString &getCardType() const { return cardtype; } const QString &getPowTough() const { return powtough; } const QString &getText() const { return text; } const int &getLoyalty() const { return loyalty; } bool getCipt() const { return cipt; } void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(this); } + void setCmc(const QString &_cmc) { cmc = _cmc; emit cardInfoChanged(this); } void setCardType(const QString &_cardType) { cardtype = _cardType; emit cardInfoChanged(this); } void setPowTough(const QString &_powTough) { powtough = _powTough; emit cardInfoChanged(this); } void setText(const QString &_text) { text = _text; emit cardInfoChanged(this); } diff --git a/cockatrice/src/cardfilter.cpp b/cockatrice/src/cardfilter.cpp index fb59adcf..06a41ca9 100644 --- a/cockatrice/src/cardfilter.cpp +++ b/cockatrice/src/cardfilter.cpp @@ -31,6 +31,8 @@ const char *CardFilter::attrName(Attr a) return "set"; case AttrManaCost: return "mana cost"; + case AttrCmc: + return "cmc"; default: return ""; } diff --git a/cockatrice/src/cardfilter.h b/cockatrice/src/cardfilter.h index e5f88123..4b7debb2 100644 --- a/cockatrice/src/cardfilter.h +++ b/cockatrice/src/cardfilter.h @@ -22,6 +22,7 @@ public: AttrText, AttrSet, AttrManaCost, + AttrCmc, AttrEnd }; diff --git a/cockatrice/src/chatview.cpp b/cockatrice/src/chatview.cpp index ff36a091..0bca6bf4 100644 --- a/cockatrice/src/chatview.cpp +++ b/cockatrice/src/chatview.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "chatview.h" #include "user_level.h" #include "user_context_menu.h" @@ -11,7 +13,7 @@ #include "main.h" #include "tab_userlists.h" -const QColor MENTION_COLOR = QColor(190, 25, 85); // maroon +const QColor DEFAULT_MENTION_COLOR = QColor(194, 31, 47); const QColor OTHER_USER_COLOR = QColor(0, 65, 255); // dark blue ChatView::ChatView(const TabSupervisor *_tabSupervisor, TabGame *_game, bool _showTimestamps, QWidget *parent) @@ -25,8 +27,6 @@ ChatView::ChatView(const TabSupervisor *_tabSupervisor, TabGame *_game, bool _sh mention = "@" + userName.toLower(); mentionFormat.setFontWeight(QFont::Bold); - mentionFormat.setForeground(QBrush(Qt::white)); - mentionFormat.setBackground(QBrush(MENTION_COLOR)); mentionFormatOtherUser.setFontWeight(QFont::Bold); mentionFormatOtherUser.setForeground(Qt::blue); @@ -117,8 +117,8 @@ void ChatView::appendMessage(QString message, QString sender, UserLevelFlags use QTextCharFormat senderFormat; if (tabSupervisor && tabSupervisor->getUserInfo() && (sender == QString::fromStdString(tabSupervisor->getUserInfo()->name()))) { + senderFormat.setForeground(QBrush(getCustomMentionColor())); senderFormat.setFontWeight(QFont::Bold); - senderFormat.setForeground(QBrush(MENTION_COLOR)); } else { senderFormat.setForeground(QBrush(OTHER_USER_COLOR)); if (playerBold) @@ -129,7 +129,8 @@ void ChatView::appendMessage(QString message, QString sender, UserLevelFlags use if (!sameSender) { if (!sender.isEmpty()) { const int pixelSize = QFontInfo(cursor.charFormat().font()).pixelSize(); - cursor.insertImage(UserLevelPixmapGenerator::generatePixmap(pixelSize, userLevel).toImage(), QString::number(pixelSize) + "_" + QString::number((int) userLevel)); + QMap buddyList = tabSupervisor->getUserListsTab()->getBuddyList()->getUsers(); + cursor.insertImage(UserLevelPixmapGenerator::generatePixmap(pixelSize, userLevel, buddyList.contains(sender)).toImage()); cursor.insertText(" "); } cursor.setCharFormat(senderFormat); @@ -194,12 +195,15 @@ void ChatView::appendMessage(QString message, QString sender, UserLevelFlags use break; // you have been mentioned if (message.toLower().startsWith(mention)) { + mentionFormat.setBackground(QBrush(getCustomMentionColor())); + mentionFormat.setForeground(settingsCache->getChatMentionForeground() ? QBrush(Qt::white):QBrush(Qt::black)); cursor.insertText("@" + userName, mentionFormat); message = message.mid(mention.size()); + QApplication::alert(this); } // another user has been mentioned else { - int mentionEndIndex = message.indexOf(" "); + int mentionEndIndex = message.indexOf(QRegExp("\\W"), 1);// from 1 as @ is non-char if (mentionEndIndex == -1) mentionEndIndex = message.size(); // there is no text after the mention QString userMention = message.left(mentionEndIndex); @@ -225,6 +229,12 @@ void ChatView::appendMessage(QString message, QString sender, UserLevelFlags use verticalScrollBar()->setValue(verticalScrollBar()->maximum()); } +QColor ChatView::getCustomMentionColor() { + QColor customColor; + customColor.setNamedColor("#" + settingsCache->getChatMentionColor()); + return customColor.isValid() ? customColor : DEFAULT_MENTION_COLOR; +} + /** Returns the correct case version of the provided username, if no correct casing version was found then the provided name is not available and will return an empty QString. diff --git a/cockatrice/src/chatview.h b/cockatrice/src/chatview.h index 17cdd398..693a7f8d 100644 --- a/cockatrice/src/chatview.h +++ b/cockatrice/src/chatview.h @@ -37,6 +37,7 @@ private: void appendCardTag(QTextCursor &cursor, const QString &cardName); void appendUrlTag(QTextCursor &cursor, QString url); QString getNameFromUserList(QMap &userList, QString &userName); + QColor getCustomMentionColor(); private slots: void openLink(const QUrl &link); public: diff --git a/cockatrice/src/deckstats_interface.cpp b/cockatrice/src/deckstats_interface.cpp index 6bdae12f..1d3b3104 100644 --- a/cockatrice/src/deckstats_interface.cpp +++ b/cockatrice/src/deckstats_interface.cpp @@ -32,7 +32,7 @@ void DeckStatsInterface::queryFinished(QNetworkReply *reply) QString data(reply->readAll()); reply->deleteLater(); - QRegExp rx("id=\"deckstats_deck_url\" value=\"([^\"]+)\""); + QRegExp rx(""); if (!rx.indexIn(data)) { QMessageBox::critical(0, tr("Error"), tr("The reply from the server could not be parsed.")); deleteLater(); @@ -53,11 +53,13 @@ void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data) #if QT_VERSION < 0x050000 QUrl params; params.addQueryItem("deck", deckWithoutTokens.writeToString_Plain()); + params.addQueryItem("decktitle", deck->getName()); data->append(params.encodedQuery()); #else QUrl params; QUrlQuery urlQuery; urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain()); + urlQuery.addQueryItem("decktitle", deck->getName()); params.setQuery(urlQuery); data->append(params.query(QUrl::EncodeReserved)); #endif diff --git a/cockatrice/src/dlg_creategame.cpp b/cockatrice/src/dlg_creategame.cpp index 65b340bb..8dea2676 100644 --- a/cockatrice/src/dlg_creategame.cpp +++ b/cockatrice/src/dlg_creategame.cpp @@ -31,13 +31,13 @@ void DlgCreateGame::sharedCtor() maxPlayersEdit->setMaximum(100); maxPlayersEdit->setValue(2); maxPlayersLabel->setBuddy(maxPlayersEdit); - + QGridLayout *generalGrid = new QGridLayout; generalGrid->addWidget(descriptionLabel, 0, 0); generalGrid->addWidget(descriptionEdit, 0, 1); generalGrid->addWidget(maxPlayersLabel, 1, 0); generalGrid->addWidget(maxPlayersEdit, 1, 1); - + QVBoxLayout *gameTypeLayout = new QVBoxLayout; QMapIterator gameTypeIterator(gameTypes); while (gameTypeIterator.hasNext()) { @@ -48,7 +48,7 @@ void DlgCreateGame::sharedCtor() } QGroupBox *gameTypeGroupBox = new QGroupBox(tr("Game type")); gameTypeGroupBox->setLayout(gameTypeLayout); - + passwordLabel = new QLabel(tr("&Password:")); passwordEdit = new QLineEdit; passwordLabel->setBuddy(passwordEdit); @@ -60,18 +60,18 @@ void DlgCreateGame::sharedCtor() onlyRegisteredCheckBox->setChecked(true); } else { onlyBuddiesCheckBox->setEnabled(false); - onlyRegisteredCheckBox->setEnabled(false); + onlyRegisteredCheckBox->setEnabled(false); } - + QGridLayout *joinRestrictionsLayout = new QGridLayout; joinRestrictionsLayout->addWidget(passwordLabel, 0, 0); joinRestrictionsLayout->addWidget(passwordEdit, 0, 1); joinRestrictionsLayout->addWidget(onlyBuddiesCheckBox, 1, 0, 1, 2); joinRestrictionsLayout->addWidget(onlyRegisteredCheckBox, 2, 0, 1, 2); - + QGroupBox *joinRestrictionsGroupBox = new QGroupBox(tr("Joining restrictions")); joinRestrictionsGroupBox->setLayout(joinRestrictionsLayout); - + spectatorsAllowedCheckBox = new QCheckBox(tr("&Spectators allowed")); spectatorsAllowedCheckBox->setChecked(true); connect(spectatorsAllowedCheckBox, SIGNAL(stateChanged(int)), this, SLOT(spectatorsAllowedChanged(int))); @@ -94,7 +94,7 @@ void DlgCreateGame::sharedCtor() buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - + QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addLayout(grid); mainLayout->addWidget(buttonBox); @@ -108,10 +108,10 @@ DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap &_gameType : QDialog(parent), room(_room), gameTypes(_gameTypes) { sharedCtor(); - + buttonBox->addButton(QDialogButtonBox::Cancel); connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOK())); - + setWindowTitle(tr("Create game")); } @@ -119,7 +119,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMapsetEnabled(false); maxPlayersEdit->setEnabled(false); passwordEdit->setEnabled(false); @@ -129,7 +129,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMapsetEnabled(false); spectatorsCanTalkCheckBox->setEnabled(false); spectatorsSeeEverythingCheckBox->setEnabled(false); - + descriptionEdit->setText(QString::fromStdString(gameInfo.description())); maxPlayersEdit->setValue(gameInfo.max_players()); onlyBuddiesCheckBox->setChecked(gameInfo.only_buddies()); @@ -138,29 +138,29 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMapsetChecked(gameInfo.spectators_need_password()); spectatorsCanTalkCheckBox->setChecked(gameInfo.spectators_can_chat()); spectatorsSeeEverythingCheckBox->setChecked(gameInfo.spectators_omniscient()); - + QSet types; for (int i = 0; i < gameInfo.game_types_size(); ++i) types.insert(gameInfo.game_types(i)); - + QMapIterator gameTypeIterator(gameTypes); while (gameTypeIterator.hasNext()) { gameTypeIterator.next(); - + QCheckBox *gameTypeCheckBox = gameTypeCheckBoxes.value(gameTypeIterator.key()); gameTypeCheckBox->setEnabled(false); gameTypeCheckBox->setChecked(types.contains(gameTypeIterator.key())); } - + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - + setWindowTitle(tr("Game information")); } void DlgCreateGame::actOK() { Command_CreateGame cmd; - cmd.set_description(descriptionEdit->text().toStdString()); + cmd.set_description(descriptionEdit->text().simplified().toStdString()); cmd.set_password(passwordEdit->text().toStdString()); cmd.set_max_players(maxPlayersEdit->value()); cmd.set_only_buddies(onlyBuddiesCheckBox->isChecked()); @@ -169,18 +169,18 @@ void DlgCreateGame::actOK() cmd.set_spectators_need_password(spectatorsNeedPasswordCheckBox->isChecked()); cmd.set_spectators_can_talk(spectatorsCanTalkCheckBox->isChecked()); cmd.set_spectators_see_everything(spectatorsSeeEverythingCheckBox->isChecked()); - + QMapIterator gameTypeCheckBoxIterator(gameTypeCheckBoxes); while (gameTypeCheckBoxIterator.hasNext()) { gameTypeCheckBoxIterator.next(); if (gameTypeCheckBoxIterator.value()->isChecked()) cmd.add_game_type_ids(gameTypeCheckBoxIterator.key()); } - + PendingCommand *pend = room->prepareRoomCommand(cmd); connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(checkResponse(Response))); room->sendRoomCommand(pend); - + buttonBox->setEnabled(false); } diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index 7d29b48b..1695c1d9 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -50,11 +50,6 @@ GeneralSettingsPage::GeneralSettingsPage() pixmapCacheEdit.setSingleStep(64); pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize()); pixmapCacheEdit.setSuffix(" MB"); - pixmapCacheEdit.setMinimum(64); - pixmapCacheEdit.setMaximum(8192); - pixmapCacheEdit.setSingleStep(64); - pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize()); - pixmapCacheEdit.setSuffix(" MB"); picDownloadHqCheckBox.setChecked(settingsCache->getPicDownloadHq()); picDownloadCheckBox.setChecked(settingsCache->getPicDownload()); @@ -571,16 +566,29 @@ void DeckEditorSettingsPage::radioPriceTagSourceClicked(bool checked) MessagesSettingsPage::MessagesSettingsPage() { - chatMentionCheckBox.setChecked(settingsCache->getChatMention()); connect(&chatMentionCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setChatMention(int))); ignoreUnregUsersMainChat.setChecked(settingsCache->getIgnoreUnregisteredUsers()); + ignoreUnregUserMessages.setChecked(settingsCache->getIgnoreUnregisteredUserMessages()); connect(&ignoreUnregUsersMainChat, SIGNAL(stateChanged(int)), settingsCache, SLOT(setIgnoreUnregisteredUsers(int))); + connect(&ignoreUnregUserMessages, SIGNAL(stateChanged(int)), settingsCache, SLOT(setIgnoreUnregisteredUserMessages(int))); + invertMentionForeground.setChecked(settingsCache->getChatMentionForeground()); + connect(&invertMentionForeground, SIGNAL(stateChanged(int)), this, SLOT(updateTextColor(int))); + + mentionColor = new QLineEdit(); + mentionColor->setText(settingsCache->getChatMentionColor()); + updateMentionPreview(); + connect(mentionColor, SIGNAL(textChanged(QString)), this, SLOT(updateColor(QString))); + QGridLayout *chatGrid = new QGridLayout; chatGrid->addWidget(&chatMentionCheckBox, 0, 0); + chatGrid->addWidget(&invertMentionForeground, 0, 1); + chatGrid->addWidget(mentionColor, 0, 2); chatGrid->addWidget(&ignoreUnregUsersMainChat, 1, 0); + chatGrid->addWidget(&hexLabel, 1, 2); + chatGrid->addWidget(&ignoreUnregUserMessages, 2, 0); chatGroupBox = new QGroupBox; chatGroupBox->setLayout(chatGrid); @@ -618,6 +626,25 @@ MessagesSettingsPage::MessagesSettingsPage() retranslateUi(); } +void MessagesSettingsPage::updateColor(const QString &value) { + QColor colorToSet; + colorToSet.setNamedColor("#" + value); + if (colorToSet.isValid()) { + settingsCache->setChatMentionColor(value); + updateMentionPreview(); + } +} + +void MessagesSettingsPage::updateTextColor(int value) { + settingsCache->setChatMentionForeground(value); + updateMentionPreview(); +} + +void MessagesSettingsPage::updateMentionPreview() { + mentionColor->setStyleSheet("QLineEdit{background:#" + settingsCache->getChatMentionColor() + + ";color: " + (settingsCache->getChatMentionForeground() ? "white" : "black") + ";}"); +} + void MessagesSettingsPage::storeSettings() { QSettings settings; @@ -650,9 +677,13 @@ void MessagesSettingsPage::retranslateUi() aAdd->setText(tr("&Add")); aRemove->setText(tr("&Remove")); chatGroupBox->setTitle(tr("Chat settings")); - chatMentionCheckBox.setText(tr("Enable chat mentions ('@yourusername' in chat log will be highlighted)")); + chatMentionCheckBox.setText(tr("Enable chat mentions")); messageShortcuts->setTitle(tr("In-game message macros")); ignoreUnregUsersMainChat.setText(tr("Ignore unregistered users in main chat")); + ignoreUnregUsersMainChat.setText(tr("Ignore chat room messages sent by unregistered users.")); + ignoreUnregUserMessages.setText(tr("Ignore private messages sent by unregistered users.")); + invertMentionForeground.setText(tr("Invert text color")); + hexLabel.setText(tr("(Color is hexadecimal)")); } DlgSettings::DlgSettings(QWidget *parent) diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index a3875c5c..cd525264 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -156,16 +156,23 @@ public: private slots: void actAdd(); void actRemove(); + void updateColor(const QString &value); + void updateTextColor(int value); private: QListWidget *messageList; QAction *aAdd; QAction *aRemove; QCheckBox chatMentionCheckBox; + QCheckBox invertMentionForeground; QCheckBox ignoreUnregUsersMainChat; + QCheckBox ignoreUnregUserMessages; QGroupBox *chatGroupBox; QGroupBox *messageShortcuts; + QLineEdit *mentionColor; + QLabel hexLabel; void storeSettings(); + void updateMentionPreview(); }; class DlgSettings : public QDialog { diff --git a/cockatrice/src/filtertree.cpp b/cockatrice/src/filtertree.cpp index 5fc516f3..c33e94be 100644 --- a/cockatrice/src/filtertree.cpp +++ b/cockatrice/src/filtertree.cpp @@ -199,34 +199,31 @@ bool FilterItem::acceptManaCost(const CardInfo *info) const return (info->getManaCost() == term); } +bool FilterItem::acceptCmc(const CardInfo *info) const +{ + return (info->getCmc() == term); +} + bool FilterItem::acceptCardAttr(const CardInfo *info, CardFilter::Attr attr) const { - bool status; - switch (attr) { case CardFilter::AttrName: - status = acceptName(info); - break; + return acceptName(info); case CardFilter::AttrType: - status = acceptType(info); - break; + return acceptType(info); case CardFilter::AttrColor: - status = acceptColor(info); - break; + return acceptColor(info); case CardFilter::AttrText: - status = acceptText(info); - break; + return acceptText(info); case CardFilter::AttrSet: - status = acceptSet(info); - break; + return acceptSet(info); case CardFilter::AttrManaCost: - status = acceptManaCost(info); - break; + return acceptManaCost(info); + case CardFilter::AttrCmc: + return acceptCmc(info); default: - status = true; /* ignore this attribute */ + return true; /* ignore this attribute */ } - - return status; } /* need to define these here to make QT happy, otherwise diff --git a/cockatrice/src/filtertree.h b/cockatrice/src/filtertree.h index 68f8fafb..6ee58a7e 100644 --- a/cockatrice/src/filtertree.h +++ b/cockatrice/src/filtertree.h @@ -117,6 +117,7 @@ public: bool acceptText(const CardInfo *info) const; bool acceptSet(const CardInfo *info) const; bool acceptManaCost(const CardInfo *info) const; + bool acceptCmc(const CardInfo *info) const; bool acceptCardAttr(const CardInfo *info, CardFilter::Attr attr) const; }; diff --git a/cockatrice/src/gamesmodel.cpp b/cockatrice/src/gamesmodel.cpp index 7672a806..289a7a5d 100644 --- a/cockatrice/src/gamesmodel.cpp +++ b/cockatrice/src/gamesmodel.cpp @@ -115,7 +115,7 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: return QString::fromStdString(g.creator_info().name()); case Qt::DecorationRole: { - QPixmap avatarPixmap = UserLevelPixmapGenerator::generatePixmap(13, (UserLevelFlags)g.creator_info().user_level()); + QPixmap avatarPixmap = UserLevelPixmapGenerator::generatePixmap(13, (UserLevelFlags)g.creator_info().user_level(), false); return QIcon(avatarPixmap); } default: diff --git a/cockatrice/src/pixmapgenerator.cpp b/cockatrice/src/pixmapgenerator.cpp index 8bae4853..4241a8f4 100644 --- a/cockatrice/src/pixmapgenerator.cpp +++ b/cockatrice/src/pixmapgenerator.cpp @@ -134,12 +134,13 @@ QPixmap CountryPixmapGenerator::generatePixmap(int height, const QString &countr QMap CountryPixmapGenerator::pmCache; -QPixmap UserLevelPixmapGenerator::generatePixmap(int height, UserLevelFlags userLevel) +QPixmap UserLevelPixmapGenerator::generatePixmap(int height, UserLevelFlags userLevel, bool isBuddy) { - int key = height * 10000 + (int) userLevel; + + int key = height * 10000 + (int) userLevel + (int) isBuddy; if (pmCache.contains(key)) return pmCache.value(key); - + QString levelString; if (userLevel.testFlag(ServerInfo_User::IsAdmin)) levelString = "admin"; @@ -149,13 +150,17 @@ QPixmap UserLevelPixmapGenerator::generatePixmap(int height, UserLevelFlags user levelString = "registered"; else levelString = "normal"; + + if (isBuddy) + levelString.append("_buddy"); + QSvgRenderer svg(QString(":/resources/userlevels/" + levelString + ".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; } diff --git a/cockatrice/src/pixmapgenerator.h b/cockatrice/src/pixmapgenerator.h index 67a8b2b2..9caeece9 100644 --- a/cockatrice/src/pixmapgenerator.h +++ b/cockatrice/src/pixmapgenerator.h @@ -50,7 +50,7 @@ class UserLevelPixmapGenerator { private: static QMap pmCache; public: - static QPixmap generatePixmap(int height, UserLevelFlags userLevel); + static QPixmap generatePixmap(int height, UserLevelFlags userLevel, bool isBuddy); static void clear() { pmCache.clear(); } }; diff --git a/cockatrice/src/playerlistwidget.cpp b/cockatrice/src/playerlistwidget.cpp index 4edf26ed..e18bab98 100644 --- a/cockatrice/src/playerlistwidget.cpp +++ b/cockatrice/src/playerlistwidget.cpp @@ -118,7 +118,7 @@ void PlayerListWidget::updatePlayerProperties(const ServerInfo_PlayerProperties player->setIcon(2, gameStarted ? (prop.conceded() ? concededIcon : QIcon()) : (prop.ready_start() ? readyIcon : notReadyIcon)); if (prop.has_user_info()) { player->setData(3, Qt::UserRole, prop.user_info().user_level()); - player->setIcon(3, QIcon(UserLevelPixmapGenerator::generatePixmap(12, UserLevelFlags(prop.user_info().user_level())))); + player->setIcon(3, QIcon(UserLevelPixmapGenerator::generatePixmap(12, UserLevelFlags(prop.user_info().user_level()), false))); player->setText(4, QString::fromStdString(prop.user_info().name())); const QString country = QString::fromStdString(prop.user_info().country()); if (!country.isEmpty()) diff --git a/cockatrice/src/playertarget.cpp b/cockatrice/src/playertarget.cpp index 98b266df..d1081797 100644 --- a/cockatrice/src/playertarget.cpp +++ b/cockatrice/src/playertarget.cpp @@ -98,7 +98,7 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o QPixmap tempPixmap; if (fullPixmap.isNull()) - tempPixmap = UserLevelPixmapGenerator::generatePixmap(translatedSize.height(), UserLevelFlags(info->user_level())); + tempPixmap = UserLevelPixmapGenerator::generatePixmap(translatedSize.height(), UserLevelFlags(info->user_level()), false); else tempPixmap = fullPixmap.scaled(translatedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 8bfbeb2d..624863a2 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -45,11 +45,12 @@ SettingsCache::SettingsCache() minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 5).toInt(); tapAnimation = settings->value("cards/tapanimation", true).toBool(); chatMention = settings->value("chat/mention", true).toBool(); + chatMentionForeground = settings->value("chat/mentionforeground", true).toBool(); + chatMentionColor = settings->value("chat/mentioncolor", "A6120D").toString(); zoneViewSortByName = settings->value("zoneview/sortbyname", true).toBool(); zoneViewSortByType = settings->value("zoneview/sortbytype", true).toBool(); zoneViewPileView = settings->value("zoneview/pileview", true).toBool(); - zoneViewShuffle = settings->value("zoneview/shuffle", true).toBool(); soundEnabled = settings->value("sound/enabled", false).toBool(); soundPath = settings->value("sound/path").toString(); @@ -58,6 +59,7 @@ SettingsCache::SettingsCache() priceTagSource = settings->value("deckeditor/pricetagsource", 0).toInt(); ignoreUnregisteredUsers = settings->value("chat/ignore_unregistered", false).toBool(); + ignoreUnregisteredUserMessages = settings->value("chat/ignore_unregistered_messages", false).toBool(); attemptAutoConnect = settings->value("server/auto_connect", 0).toBool(); } @@ -244,6 +246,16 @@ void SettingsCache::setChatMention(int _chatMention) { settings->setValue("chat/mention", chatMention); } +void SettingsCache::setChatMentionForeground(int _chatMentionForeground) { + chatMentionForeground = _chatMentionForeground; + settings->setValue("chat/mentionforeground", chatMentionForeground); +} + +void SettingsCache::setChatMentionColor(const QString &_chatMentionColor) { + chatMentionColor = _chatMentionColor; + settings->setValue("chat/mentioncolor", chatMentionColor); +} + void SettingsCache::setZoneViewSortByName(int _zoneViewSortByName) { zoneViewSortByName = _zoneViewSortByName; @@ -261,11 +273,6 @@ void SettingsCache::setZoneViewPileView(int _zoneViewPileView){ settings->setValue("zoneview/pileview", zoneViewPileView); } -void SettingsCache::setZoneViewShuffle(int _zoneViewShuffle) { - zoneViewShuffle = _zoneViewShuffle; - settings->setValue("zoneview/shuffle", zoneViewShuffle); -} - void SettingsCache::setSoundEnabled(int _soundEnabled) { soundEnabled = _soundEnabled; @@ -299,6 +306,12 @@ void SettingsCache::setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers) settings->setValue("chat/ignore_unregistered", ignoreUnregisteredUsers); } +void SettingsCache::setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages) +{ + ignoreUnregisteredUserMessages = _ignoreUnregisteredUserMessages; + settings->setValue("chat/ignore_unregistered_messages", ignoreUnregisteredUserMessages); +} + void SettingsCache::setMainWindowGeometry(const QByteArray &_mainWindowGeometry) { mainWindowGeometry = _mainWindowGeometry; diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index b4d6e9bf..2d7f99b2 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -36,6 +36,7 @@ signals: void soundPathChanged(); void priceTagFeatureChanged(int enabled); void ignoreUnregisteredUsersChanged(); + void ignoreUnregisteredUserMessagesChanged(); void pixmapCacheSizeChanged(int newSizeInMBs); private: QSettings *settings; @@ -57,12 +58,15 @@ private: int minPlayersForMultiColumnLayout; bool tapAnimation; bool chatMention; - bool zoneViewSortByName, zoneViewSortByType, zoneViewPileView, zoneViewShuffle; + QString chatMentionColor; + bool chatMentionForeground; + bool zoneViewSortByName, zoneViewSortByType, zoneViewPileView; bool soundEnabled; QString soundPath; bool priceTagFeature; int priceTagSource; bool ignoreUnregisteredUsers; + bool ignoreUnregisteredUserMessages; QString picUrl; QString picUrlHq; QString picUrlFallback; @@ -83,6 +87,7 @@ public: QString getTableBgPath() const { return tableBgPath; } QString getPlayerBgPath() const { return playerBgPath; } QString getCardBackPicturePath() const { return cardBackPicturePath; } + QString getChatMentionColor() const { return chatMentionColor; } bool getPicDownload() const { return picDownload; } bool getPicDownloadHq() const { return picDownloadHq; } bool getNotificationsEnabled() const { return notificationsEnabled; } @@ -96,6 +101,7 @@ public: int getMinPlayersForMultiColumnLayout() const { return minPlayersForMultiColumnLayout; } bool getTapAnimation() const { return tapAnimation; } bool getChatMention() const { return chatMention; } + bool getChatMentionForeground() const { return chatMentionForeground; } bool getZoneViewSortByName() const { return zoneViewSortByName; } bool getZoneViewSortByType() const { return zoneViewSortByType; } /** @@ -103,16 +109,12 @@ public: @return zoneViewPileView if the view should be sorted into pile view. */ bool getZoneViewPileView() const { return zoneViewPileView; } - /** - Returns if the view should be shuffled on closing. - @return zoneViewShuffle if the view should be shuffled on closing. - */ - bool getZoneViewShuffle() const { return zoneViewShuffle; } bool getSoundEnabled() const { return soundEnabled; } QString getSoundPath() const { return soundPath; } bool getPriceTagFeature() const { return priceTagFeature; } int getPriceTagSource() const { return priceTagSource; } bool getIgnoreUnregisteredUsers() const { return ignoreUnregisteredUsers; } + bool getIgnoreUnregisteredUserMessages() const { return ignoreUnregisteredUserMessages; } QString getPicUrl() const { return picUrl; } QString getPicUrlHq() const { return picUrlHq; } QString getPicUrlFallback() const { return picUrlFallback; } @@ -133,6 +135,7 @@ public slots: void setTableBgPath(const QString &_tableBgPath); void setPlayerBgPath(const QString &_playerBgPath); void setCardBackPicturePath(const QString &_cardBackPicturePath); + void setChatMentionColor(const QString &_chatMentionColor); void setPicDownload(int _picDownload); void setPicDownloadHq(int _picDownloadHq); void setNotificationsEnabled(int _notificationsEnabled); @@ -146,15 +149,16 @@ public slots: void setMinPlayersForMultiColumnLayout(int _minPlayersForMultiColumnLayout); void setTapAnimation(int _tapAnimation); void setChatMention(int _chatMention); + void setChatMentionForeground(int _chatMentionForeground); void setZoneViewSortByName(int _zoneViewSortByName); void setZoneViewSortByType(int _zoneViewSortByType); void setZoneViewPileView(int _zoneViewPileView); - void setZoneViewShuffle(int _zoneViewShuffle); void setSoundEnabled(int _soundEnabled); void setSoundPath(const QString &_soundPath); void setPriceTagFeature(int _priceTagFeature); void setPriceTagSource(int _priceTagSource); void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers); + void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages); void setPicUrl(const QString &_picUrl); void setPicUrlHq(const QString &_picUrlHq); void setPicUrlFallback(const QString &_picUrlFallback); diff --git a/cockatrice/src/tab_deck_editor.cpp b/cockatrice/src/tab_deck_editor.cpp index 7cfbff55..fdd41967 100644 --- a/cockatrice/src/tab_deck_editor.cpp +++ b/cockatrice/src/tab_deck_editor.cpp @@ -276,8 +276,8 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent) deckEditToolBar->addAction(aAddCard); deckEditToolBar->addAction(aAddCardToSideboard); deckEditToolBar->addAction(aRemoveCard); - deckEditToolBar->addAction(aIncrement); deckEditToolBar->addAction(aDecrement); + deckEditToolBar->addAction(aIncrement); deckEditToolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); retranslateUi(); diff --git a/cockatrice/src/tab_game.cpp b/cockatrice/src/tab_game.cpp index aefcf02e..6baac310 100644 --- a/cockatrice/src/tab_game.cpp +++ b/cockatrice/src/tab_game.cpp @@ -885,6 +885,7 @@ void TabGame::startGame(bool resuming) gameInfo.set_started(true); static_cast(gameView->scene())->rearrange(); gameView->show(); + sayEdit->setFocus(); } void TabGame::stopGame() diff --git a/cockatrice/src/tab_message.cpp b/cockatrice/src/tab_message.cpp index 6369f2a6..72779d99 100644 --- a/cockatrice/src/tab_message.cpp +++ b/cockatrice/src/tab_message.cpp @@ -18,6 +18,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, c chatView = new ChatView(tabSupervisor, 0, true); connect(chatView, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString))); connect(chatView, SIGNAL(deleteCardInfoPopup(QString)), this, SLOT(deleteCardInfoPopup(QString))); + connect(chatView, SIGNAL(addMentionTag(QString)), this, SLOT(addMentionTag(QString))); sayEdit = new QLineEdit; connect(sayEdit, SIGNAL(returnPressed()), this, SLOT(sendMessage())); @@ -43,6 +44,11 @@ TabMessage::~TabMessage() delete otherUserInfo; } +void TabMessage::addMentionTag(QString mentionTag) { + sayEdit->insert(mentionTag + " "); + sayEdit->setFocus(); +} + void TabMessage::retranslateUi() { messageMenu->setTitle(tr("Personal &talk")); diff --git a/cockatrice/src/tab_message.h b/cockatrice/src/tab_message.h index 80263975..9f2b19d2 100644 --- a/cockatrice/src/tab_message.h +++ b/cockatrice/src/tab_message.h @@ -29,6 +29,7 @@ private slots: void sendMessage(); void actLeave(); void messageSent(const Response &response); + void addMentionTag(QString mentionTag); public: TabMessage(TabSupervisor *_tabSupervisor, AbstractClient *_client, const ServerInfo_User &_ownUserInfo, const ServerInfo_User &_otherUserInfo); ~TabMessage(); diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index 166a766a..2666b42f 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -446,11 +446,21 @@ void TabSupervisor::processGameEventContainer(const GameEventContainer &cont) void TabSupervisor::processUserMessageEvent(const Event_UserMessage &event) { - TabMessage *tab = messageTabs.value(QString::fromStdString(event.sender_name())); + QString senderName = QString::fromStdString(event.sender_name()); + TabMessage *tab = messageTabs.value(senderName); if (!tab) tab = messageTabs.value(QString::fromStdString(event.receiver_name())); - if (!tab) + if (!tab) { + UserListTWI *twi = tabUserLists->getAllUsersList()->getUsers().value(senderName); + if (twi) { + UserLevelFlags userLevel = UserLevelFlags(twi->getUserInfo().user_level()); + if (settingsCache->getIgnoreUnregisteredUserMessages() && + !userLevel.testFlag(ServerInfo_User::IsRegistered)) + // Flags are additive, so reg/mod/admin are all IsRegistered + return; + } tab = addMessageTab(QString::fromStdString(event.sender_name()), false); + } if (!tab) return; tab->processUserMessageEvent(event); diff --git a/cockatrice/src/userinfobox.cpp b/cockatrice/src/userinfobox.cpp index a733f5bc..0fd0e569 100644 --- a/cockatrice/src/userinfobox.cpp +++ b/cockatrice/src/userinfobox.cpp @@ -31,6 +31,7 @@ UserInfoBox::UserInfoBox(AbstractClient *_client, bool _fullInfo, QWidget *paren mainLayout->addWidget(&genderLabel2, 3, 1, 1, 2); mainLayout->addWidget(&countryLabel1, 4, 0, 1, 1); mainLayout->addWidget(&countryLabel2, 4, 1, 1, 2); + mainLayout->addWidget(&countryLabel3, 4, 2, 1, 1); mainLayout->addWidget(&userLevelLabel1, 5, 0, 1, 1); mainLayout->addWidget(&userLevelLabel2, 5, 1, 1, 1); mainLayout->addWidget(&userLevelLabel3, 5, 2, 1, 1); @@ -59,14 +60,16 @@ void UserInfoBox::updateInfo(const ServerInfo_User &user) QPixmap avatarPixmap; const std::string bmp = user.avatar_bmp(); if (!avatarPixmap.loadFromData((const uchar *) bmp.data(), bmp.size())) - avatarPixmap = UserLevelPixmapGenerator::generatePixmap(64, userLevel); + avatarPixmap = UserLevelPixmapGenerator::generatePixmap(64, userLevel, false); avatarLabel.setPixmap(avatarPixmap); nameLabel.setText(QString::fromStdString(user.name())); realNameLabel2.setText(QString::fromStdString(user.real_name())); genderLabel2.setPixmap(GenderPixmapGenerator::generatePixmap(15, user.gender())); - countryLabel2.setPixmap(CountryPixmapGenerator::generatePixmap(15, QString::fromStdString(user.country()))); - userLevelLabel2.setPixmap(UserLevelPixmapGenerator::generatePixmap(15, userLevel)); + QString country = QString::fromStdString(user.country()); + countryLabel2.setPixmap(CountryPixmapGenerator::generatePixmap(15, country)); + countryLabel3.setText(QString("(%1)").arg(country.toUpper())); + userLevelLabel2.setPixmap(UserLevelPixmapGenerator::generatePixmap(15, userLevel, false)); QString userLevelText; if (userLevel.testFlag(ServerInfo_User::IsAdmin)) userLevelText = tr("Administrator"); diff --git a/cockatrice/src/userinfobox.h b/cockatrice/src/userinfobox.h index b64e29af..e144cd4c 100644 --- a/cockatrice/src/userinfobox.h +++ b/cockatrice/src/userinfobox.h @@ -14,8 +14,8 @@ class UserInfoBox : public QWidget { private: AbstractClient *client; bool fullInfo; - QLabel avatarLabel, nameLabel, realNameLabel1, realNameLabel2, genderLabel1, genderLabel2, countryLabel1, - countryLabel2, userLevelLabel1, userLevelLabel2, userLevelLabel3, accountAgeLebel1, accountAgeLabel2; + QLabel avatarLabel, nameLabel, realNameLabel1, realNameLabel2, genderLabel1, genderLabel2, countryLabel1, + countryLabel2, countryLabel3, userLevelLabel1, userLevelLabel2, userLevelLabel3, accountAgeLebel1, accountAgeLabel2; 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 c6174a6e..5e9e2490 100644 --- a/cockatrice/src/userlist.cpp +++ b/cockatrice/src/userlist.cpp @@ -181,7 +181,7 @@ void UserListTWI::setUserInfo(const ServerInfo_User &_userInfo) userInfo = _userInfo; setData(0, Qt::UserRole, userInfo.user_level()); - setIcon(0, QIcon(UserLevelPixmapGenerator::generatePixmap(12, UserLevelFlags(userInfo.user_level())))); + setIcon(0, QIcon(UserLevelPixmapGenerator::generatePixmap(12, UserLevelFlags(userInfo.user_level()), false))); setIcon(1, QIcon(CountryPixmapGenerator::generatePixmap(12, QString::fromStdString(userInfo.country())))); setData(2, Qt::UserRole, QString::fromStdString(userInfo.name())); setData(2, Qt::DisplayRole, QString::fromStdString(userInfo.name())); diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index 82f0cab1..ebc45754 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -344,6 +344,7 @@ void MainWindow::createMenus() cockatriceMenu = menuBar()->addMenu(QString()); cockatriceMenu->addAction(aConnect); cockatriceMenu->addAction(aDisconnect); + cockatriceMenu->addSeparator(); cockatriceMenu->addAction(aSinglePlayer); cockatriceMenu->addAction(aWatchReplay); cockatriceMenu->addSeparator(); diff --git a/cockatrice/src/zoneviewwidget.cpp b/cockatrice/src/zoneviewwidget.cpp index 13fb6962..dab5f862 100644 --- a/cockatrice/src/zoneviewwidget.cpp +++ b/cockatrice/src/zoneviewwidget.cpp @@ -101,7 +101,7 @@ ZoneViewWidget::ZoneViewWidget(Player *_player, CardZone *_origZone, int numberC } if (_origZone->getIsShufflable() && (numberCards == -1)) { - shuffleCheckBox.setChecked(settingsCache->getZoneViewShuffle()); + shuffleCheckBox.setChecked(true); QGraphicsProxyWidget *shuffleProxy = new QGraphicsProxyWidget; shuffleProxy->setWidget(&shuffleCheckBox); vbox->addItem(shuffleProxy); @@ -225,10 +225,8 @@ void ZoneViewWidget::closeEvent(QCloseEvent *event) cmd.set_zone_name(zone->getName().toStdString()); player->sendGameCommand(cmd); } - if (shuffleCheckBox.isChecked()) + if (shuffleCheckBox.isChecked()) player->sendGameCommand(Command_Shuffle()); - if (canBeShuffled) - settingsCache->setZoneViewShuffle(shuffleCheckBox.isChecked()); emit closePressed(this); deleteLater(); event->accept(); diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp index 24cca716..0b42b55e 100644 --- a/cockatrice/src/zoneviewzone.cpp +++ b/cockatrice/src/zoneviewzone.cpp @@ -106,9 +106,30 @@ void ZoneViewZone::reorganizeCards() int typeColumn = 0; int longestRow = 0; - if (pileView && sortByType) // we need sort by type enabled for the feature to work - setPileViewPositions(cardCount, cardsToDisplay, typeColumn, longestRow); - else { + if (pileView && sortByType) { // we need sort by type enabled for the feature to work + int typeRow = 0; + QString lastCardType; + for (int i = 0; i < cardCount; i++) { + CardItem *c = cardsToDisplay.at(i); + QString cardType = c->getInfo()->getMainCardType(); + + if (i){ // if not the first card + if (cardType == lastCardType) + typeRow++; // add below current card + else { // if no match then move card to next column + typeColumn++; + typeRow = 0; + } + } + + lastCardType = cardType; + qreal x = typeColumn * CARD_WIDTH; + qreal y = typeRow * CARD_HEIGHT / 3; + c->setPos(x + 5, y + 5); + c->setRealZValue(i); + longestRow = qMax(typeRow, longestRow); + } + } else { for (int i = 0; i < cardCount; i++) { CardItem *c = cardsToDisplay.at(i); qreal x = (i / rows) * CARD_WIDTH; @@ -128,31 +149,6 @@ void ZoneViewZone::reorganizeCards() emit optimumRectChanged(); } -void ZoneViewZone::setPileViewPositions(int cardCount, CardList &cardsToDisplay, int &typeColumn, int &longestRow){ - int typeRow = 0; - bool cardTypeMatch = true; - for (int i = 0; i < cardCount; i++) { - CardItem *c = cardsToDisplay.at(i); - QString cardType = c->getInfo()->getMainCardType(); - - if (i){ - // if not the first card. Last card and this card have a matching main type? - cardTypeMatch = cardType.compare(cardsToDisplay.at(i-1)->getInfo()->getMainCardType()) == 0 ? true : false; - if (!cardTypeMatch) { // if no match then move card to next column - typeColumn++; - longestRow = qMax(typeRow, longestRow); - typeRow = 0; - } else // add below current card - typeRow++; - } - - qreal x = typeColumn * CARD_WIDTH; - qreal y = typeRow * CARD_HEIGHT / 3; - c->setPos(x + 5, y + 5); - c->setRealZValue(i); - } -} - void ZoneViewZone::setSortByName(int _sortByName) { sortByName = _sortByName; diff --git a/cockatrice/src/zoneviewzone.h b/cockatrice/src/zoneviewzone.h index eff1ecfe..4c071589 100644 --- a/cockatrice/src/zoneviewzone.h +++ b/cockatrice/src/zoneviewzone.h @@ -26,10 +26,6 @@ public: QRectF boundingRect() const; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); void reorganizeCards(); - - void setPileViewPositions(int cardCount, CardList &cardsToDisplay, int &typeColumn, int &longestRow); - - void initializeCards(const QList &cardList = QList()); void removeCard(int position); int getNumberCards() const { return numberCards; } diff --git a/common/server_game.cpp b/common/server_game.cpp index 58725742..1a3e748f 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -56,7 +56,6 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const gameStarted(false), gameClosed(false), gameId(_gameId), - description(_description), password(_password), maxPlayers(_maxPlayers), gameTypes(_gameTypes), @@ -77,9 +76,10 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const { currentReplay = new GameReplay; currentReplay->set_replay_id(room->getServer()->getDatabaseInterface()->getNextReplayId()); - + description = _description.simplified(); + connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection); - + getInfo(*currentReplay->mutable_game_info()); if (room->getServer()->getGameShouldPing()) { @@ -93,36 +93,36 @@ Server_Game::~Server_Game() { room->gamesLock.lockForWrite(); gameMutex.lock(); - + gameClosed = true; sendGameEventContainer(prepareGameEvent(Event_GameClosed(), -1)); - + QMapIterator playerIterator(players); while (playerIterator.hasNext()) playerIterator.next().value()->prepareDestroy(); players.clear(); - + room->removeGame(this); delete creatorInfo; creatorInfo = 0; - + gameMutex.unlock(); room->gamesLock.unlock(); - + currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame); replayList.append(currentReplay); storeGameInformation(); - + for (int i = 0; i < replayList.size(); ++i) delete replayList[i]; - + qDebug() << "Server_Game destructor: gameId=" << gameId; } void Server_Game::storeGameInformation() { const ServerInfo_Game &gameInfo = replayList.first()->game_info(); - + Event_ReplayAdded replayEvent; ServerInfo_ReplayMatch *replayMatchInfo = replayEvent.mutable_match_info(); replayMatchInfo->set_game_id(gameInfo.game_id()); @@ -130,26 +130,26 @@ void Server_Game::storeGameInformation() replayMatchInfo->set_time_started(QDateTime::currentDateTime().addSecs(-secondsElapsed).toTime_t()); replayMatchInfo->set_length(secondsElapsed); replayMatchInfo->set_game_name(gameInfo.description()); - + const QStringList &allGameTypes = room->getGameTypes(); QStringList gameTypes; for (int i = gameInfo.game_types_size() - 1; i >= 0; --i) gameTypes.append(allGameTypes[gameInfo.game_types(i)]); - + QSetIterator playerIterator(allPlayersEver); while (playerIterator.hasNext()) replayMatchInfo->add_player_names(playerIterator.next().toStdString()); - + for (int i = 0; i < replayList.size(); ++i) { ServerInfo_Replay *replayInfo = replayMatchInfo->add_replay_list(); replayInfo->set_replay_id(replayList[i]->replay_id()); replayInfo->set_replay_name(gameInfo.description()); replayInfo->set_duration(replayList[i]->duration_seconds()); } - + QSet allUsersInGame = allPlayersEver + allSpectatorsEver; QSetIterator allUsersIterator(allUsersInGame); - + SessionEvent *sessionEvent = Server_ProtocolHandler::prepareSessionEvent(replayEvent); Server *server = room->getServer(); server->clientsLock.lockForRead(); @@ -160,7 +160,7 @@ void Server_Game::storeGameInformation() } server->clientsLock.unlock(); delete sessionEvent; - + server->getDatabaseInterface()->storeGameInformation(room->getName(), gameTypes, gameInfo, allPlayersEver, allSpectatorsEver, replayList); } @@ -168,10 +168,10 @@ void Server_Game::pingClockTimeout() { QMutexLocker locker(&gameMutex); ++secondsElapsed; - + GameEventStorage ges; ges.setGameEventContext(Context_PingChanged()); - + QList pingList; QMapIterator playerIterator(players); bool allPlayersInactive = true; @@ -180,7 +180,7 @@ void Server_Game::pingClockTimeout() Server_Player *player = playerIterator.next().value(); if (!player->getSpectator()) ++playerCount; - + const int oldPingTime = player->getPingTime(); player->playerMutex.lock(); int newPingTime; @@ -189,20 +189,20 @@ void Server_Game::pingClockTimeout() else newPingTime = -1; player->playerMutex.unlock(); - + if ((newPingTime != -1) && !player->getSpectator()) allPlayersInactive = false; - + if ((abs(oldPingTime - newPingTime) > 1) || ((newPingTime == -1) && (oldPingTime != -1)) || ((newPingTime != -1) && (oldPingTime == -1))) { player->setPingTime(newPingTime); - + Event_PlayerPropertiesChanged event; event.mutable_player_properties()->set_ping_seconds(newPingTime); ges.enqueueGameEvent(event, player->getPlayerId()); } } ges.sendToGame(this); - + const int maxTime = room->getServer()->getMaxGameInactivityTime(); if (allPlayersInactive) { if (((++inactivityCounter >= maxTime) && (maxTime > 0)) || (playerCount < maxPlayers)) @@ -214,7 +214,7 @@ void Server_Game::pingClockTimeout() int Server_Game::getPlayerCount() const { QMutexLocker locker(&gameMutex); - + QMapIterator playerIterator(players); int result = 0; while (playerIterator.hasNext()) @@ -226,7 +226,7 @@ int Server_Game::getPlayerCount() const int Server_Game::getSpectatorCount() const { QMutexLocker locker(&gameMutex); - + QMapIterator playerIterator(players); int result = 0; while (playerIterator.hasNext()) @@ -244,7 +244,7 @@ void Server_Game::createGameStateChangedEvent(Event_GameStateChanged *event, Ser event->set_active_phase(0); } else event->set_game_started(false); - + QMapIterator playerIterator(players); while (playerIterator.hasNext()) playerIterator.next().value()->getInfo(event->add_player_list(), playerWhosAsking, omniscient, withUserInfo); @@ -255,13 +255,13 @@ void Server_Game::sendGameStateToPlayers() // game state information for replay and omniscient spectators Event_GameStateChanged omniscientEvent; createGameStateChangedEvent(&omniscientEvent, 0, true, false); - + GameEventContainer *replayCont = prepareGameEvent(omniscientEvent, -1); replayCont->set_seconds_elapsed(secondsElapsed - startTimeOfThisGame); replayCont->clear_game_id(); currentReplay->add_event_list()->CopyFrom(*replayCont); delete replayCont; - + // If spectators are not omniscient, we need an additional createGameStateChangedEvent call, otherwise we can use the data we used for the replay. // All spectators are equal, so we don't need to make a createGameStateChangedEvent call for each one. Event_GameStateChanged spectatorEvent; @@ -269,7 +269,7 @@ void Server_Game::sendGameStateToPlayers() spectatorEvent = omniscientEvent; else createGameStateChangedEvent(&spectatorEvent, 0, false, false); - + // send game state info to clients according to their role in the game QMapIterator playerIterator(players); while (playerIterator.hasNext()) { @@ -280,7 +280,7 @@ void Server_Game::sendGameStateToPlayers() else { Event_GameStateChanged event; createGameStateChangedEvent(&event, player, false, false); - + gec = prepareGameEvent(event, -1); } player->sendGameEvent(*gec); @@ -292,7 +292,7 @@ void Server_Game::doStartGameIfReady() { Server_DatabaseInterface *databaseInterface = room->getServer()->getDatabaseInterface(); QMutexLocker locker(&gameMutex); - + if (getPlayerCount() < maxPlayers) return; QMapIterator playerIterator(players); @@ -315,7 +315,7 @@ void Server_Game::doStartGameIfReady() player->setConceded(false); player->setReadyStart(false); } - + if (firstGameStarted) { currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame); replayList.append(currentReplay); @@ -324,27 +324,27 @@ void Server_Game::doStartGameIfReady() ServerInfo_Game *gameInfo = currentReplay->mutable_game_info(); getInfo(*gameInfo); gameInfo->set_started(false); - + Event_GameStateChanged omniscientEvent; createGameStateChangedEvent(&omniscientEvent, 0, true, true); - + GameEventContainer *replayCont = prepareGameEvent(omniscientEvent, -1); replayCont->set_seconds_elapsed(0); replayCont->clear_game_id(); currentReplay->add_event_list()->CopyFrom(*replayCont); delete replayCont; - + startTimeOfThisGame = secondsElapsed; } else firstGameStarted = true; - + sendGameStateToPlayers(); - + activePlayer = -1; nextTurn(); - + locker.unlock(); - + ServerInfo_Game gameInfo; gameInfo.set_room_id(room->getId()); gameInfo.set_game_id(gameId); @@ -360,7 +360,7 @@ void Server_Game::startGameIfReady() void Server_Game::stopGameIfFinished() { QMutexLocker locker(&gameMutex); - + QMapIterator playerIterator(players); int playing = 0; while (playerIterator.hasNext()) { @@ -381,9 +381,9 @@ void Server_Game::stopGameIfFinished() } sendGameStateToPlayers(); - + locker.unlock(); - + ServerInfo_Game gameInfo; gameInfo.set_room_id(room->getId()); gameInfo.set_game_id(gameId); @@ -417,14 +417,14 @@ Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QStri } if (!spectator && (gameStarted || (getPlayerCount() >= getMaxPlayers()))) return Response::RespGameFull; - + return Response::RespOk; } bool Server_Game::containsUser(const QString &userName) const { QMutexLocker locker(&gameMutex); - + QMapIterator playerIterator(players); while (playerIterator.hasNext()) if (playerIterator.next().value()->getUserInfo()->name() == userName.toStdString()) @@ -435,14 +435,14 @@ bool Server_Game::containsUser(const QString &userName) const void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface, ResponseContainer &rc, bool spectator, bool broadcastUpdate) { QMutexLocker locker(&gameMutex); - + Server_Player *newPlayer = new Server_Player(this, nextPlayerId++, userInterface->copyUserInfo(true, true, true), spectator, userInterface); newPlayer->moveToThread(thread()); - + Event_Join joinEvent; newPlayer->getProperties(*joinEvent.mutable_player_properties(), true); sendGameEventContainer(prepareGameEvent(joinEvent, -1)); - + const QString playerName = QString::fromStdString(newPlayer->getUserInfo()->name()); if (spectator) allSpectatorsEver.insert(playerName); @@ -453,7 +453,7 @@ void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface, Respons hostId = newPlayer->getPlayerId(); sendGameEventContainer(prepareGameEvent(Event_GameHostChanged(), hostId)); } - + if (broadcastUpdate) { ServerInfo_Game gameInfo; gameInfo.set_room_id(room->getId()); @@ -462,12 +462,12 @@ void Server_Game::addPlayer(Server_AbstractUserInterface *userInterface, Respons gameInfo.set_spectators_count(getSpectatorCount()); emit gameInfoChanged(gameInfo); } - + if ((newPlayer->getUserInfo()->user_level() & ServerInfo_User::IsRegistered) && !spectator) room->getServer()->addPersistentPlayer(playerName, room->getId(), gameId, newPlayer->getPlayerId()); - + userInterface->playerAddedToGame(gameId, room->getId(), newPlayer->getPlayerId()); - + createGameJoinedEvent(newPlayer, rc, false); } @@ -475,18 +475,18 @@ void Server_Game::removePlayer(Server_Player *player) { room->getServer()->removePersistentPlayer(QString::fromStdString(player->getUserInfo()->name()), room->getId(), gameId, player->getPlayerId()); players.remove(player->getPlayerId()); - + GameEventStorage ges; removeArrowsRelatedToPlayer(ges, player); unattachCards(ges, player); ges.enqueueGameEvent(Event_Leave(), player->getPlayerId()); ges.sendToGame(this); - + bool playerActive = activePlayer == player->getPlayerId(); bool playerHost = hostId == player->getPlayerId(); bool spectator = player->getSpectator(); player->prepareDestroy(); - + if (!getPlayerCount()) { gameClosed = true; deleteLater(); @@ -511,7 +511,7 @@ void Server_Game::removePlayer(Server_Player *player) if (gameStarted && playerActive) nextTurn(); } - + ServerInfo_Game gameInfo; gameInfo.set_room_id(room->getId()); gameInfo.set_game_id(gameId); @@ -523,7 +523,7 @@ void Server_Game::removePlayer(Server_Player *player) void Server_Game::removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Player *player) { QMutexLocker locker(&gameMutex); - + // Remove all arrows of other players pointing to the player being removed or to one of his cards. // Also remove all arrows starting at one of his cards. This is necessary since players can create // arrows that start at another person's cards. @@ -540,7 +540,7 @@ void Server_Game::removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Play toDelete.append(a); } else if (static_cast(a->getTargetItem()) == player) toDelete.append(a); - + // Don't use else here! It has to happen regardless of whether targetCard == 0. if (a->getStartCard()->getZone()->getPlayer() == player) toDelete.append(a); @@ -549,7 +549,7 @@ void Server_Game::removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Play Event_DeleteArrow event; event.set_arrow_id(toDelete[i]->getId()); ges.enqueueGameEvent(event, p->getPlayerId()); - + p->deleteArrow(toDelete[i]->getId()); } } @@ -558,13 +558,13 @@ void Server_Game::removeArrowsRelatedToPlayer(GameEventStorage &ges, Server_Play void Server_Game::unattachCards(GameEventStorage &ges, Server_Player *player) { QMutexLocker locker(&gameMutex); - + QMapIterator zoneIterator(player->getZones()); while (zoneIterator.hasNext()) { Server_CardZone *zone = zoneIterator.next().value(); for (int i = 0; i < zone->getCards().size(); ++i) { Server_Card *card = zone->getCards().at(i); - + // Make a copy of the list because the original one gets modified during the loop QList attachedCards = card->getAttachedCards(); for (int i = 0; i < attachedCards.size(); ++i) @@ -576,54 +576,54 @@ void Server_Game::unattachCards(GameEventStorage &ges, Server_Player *player) bool Server_Game::kickPlayer(int playerId) { QMutexLocker locker(&gameMutex); - + Server_Player *playerToKick = players.value(playerId); if (!playerToKick) return false; - + GameEventContainer *gec = prepareGameEvent(Event_Kicked(), -1); playerToKick->sendGameEvent(*gec); delete gec; - + removePlayer(playerToKick); - + return true; } void Server_Game::setActivePlayer(int _activePlayer) { QMutexLocker locker(&gameMutex); - + activePlayer = _activePlayer; - + Event_SetActivePlayer event; event.set_active_player_id(activePlayer); sendGameEventContainer(prepareGameEvent(event, -1)); - + setActivePhase(0); } void Server_Game::setActivePhase(int _activePhase) { QMutexLocker locker(&gameMutex); - + QMapIterator playerIterator(players); while (playerIterator.hasNext()) { Server_Player *player = playerIterator.next().value(); QList toDelete = player->getArrows().values(); for (int i = 0; i < toDelete.size(); ++i) { Server_Arrow *a = toDelete[i]; - + Event_DeleteArrow event; event.set_arrow_id(a->getId()); sendGameEventContainer(prepareGameEvent(event, player->getPlayerId())); - + player->deleteArrow(a->getId()); } } - + activePhase = _activePhase; - + Event_SetActivePhase event; event.set_phase(activePhase); sendGameEventContainer(prepareGameEvent(event, -1)); @@ -632,7 +632,7 @@ void Server_Game::setActivePhase(int _activePhase) void Server_Game::nextTurn() { QMutexLocker locker(&gameMutex); - + const QList keys = players.keys(); int listPos = -1; if (activePlayer != -1) @@ -642,7 +642,7 @@ void Server_Game::nextTurn() if (listPos == keys.size()) listPos = 0; } while (players.value(keys[listPos])->getSpectator() || players.value(keys[listPos])->getConceded()); - + setActivePlayer(keys[listPos]); } @@ -663,13 +663,13 @@ void Server_Game::createGameJoinedEvent(Server_Player *player, ResponseContainer } } rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, Server_AbstractUserInterface::prepareSessionEvent(event1)); - + Event_GameStateChanged event2; event2.set_seconds_elapsed(secondsElapsed); event2.set_game_started(gameStarted); event2.set_active_player_id(activePlayer); event2.set_active_phase(activePhase); - + QMapIterator playerIterator(players); while (playerIterator.hasNext()) playerIterator.next().value()->getInfo(event2.add_player_list(), player, player->getSpectator() && spectatorsSeeEverything, true); @@ -680,7 +680,7 @@ void Server_Game::createGameJoinedEvent(Server_Player *player, ResponseContainer void Server_Game::sendGameEventContainer(GameEventContainer *cont, GameEventStorageItem::EventRecipients recipients, int privatePlayerId) { QMutexLocker locker(&gameMutex); - + cont->set_game_id(gameId); QMapIterator playerIterator(players); while (playerIterator.hasNext()) { @@ -694,7 +694,7 @@ void Server_Game::sendGameEventContainer(GameEventContainer *cont, GameEventStor cont->clear_game_id(); currentReplay->add_event_list()->CopyFrom(*cont); } - + delete cont; } @@ -714,7 +714,7 @@ GameEventContainer *Server_Game::prepareGameEvent(const ::google::protobuf::Mess void Server_Game::getInfo(ServerInfo_Game &result) const { QMutexLocker locker(&gameMutex); - + result.set_room_id(room->getId()); result.set_game_id(gameId); if (gameClosed) @@ -722,7 +722,7 @@ void Server_Game::getInfo(ServerInfo_Game &result) const else { for (int i = 0; i < gameTypes.size(); ++i) result.add_game_types(gameTypes[i]); - + result.set_max_players(getMaxPlayers()); result.set_description(getDescription().toStdString()); result.set_with_password(!getPassword().isEmpty()); diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 54ff9958..f792829b 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -65,6 +65,7 @@ CardInfo *OracleImporter::addCard(const QString &setName, bool isToken, int cardId, QString &cardCost, + QString &cmc, const QString &cardType, const QString &cardPT, int cardLoyalty, @@ -117,7 +118,7 @@ CardInfo *OracleImporter::addCard(const QString &setName, bool cipt = (cardText.contains(cardName + " enters the battlefield tapped.")); - card = new CardInfo(this, cardName, isToken, cardCost, cardType, cardPT, fullCardText, colors, cardLoyalty, cipt); + card = new CardInfo(this, cardName, isToken, cardCost, cmc, cardType, cardPT, fullCardText, colors, cardLoyalty, cipt); int tableRow = 1; QString mainCardType = card->getMainCardType(); if ((mainCardType == "Land") || mArtifact) @@ -143,6 +144,7 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data) QVariantMap map; QString cardName; QString cardCost; + QString cmc; QString cardType; QString cardPT; QString cardText; @@ -185,6 +187,7 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data) // add first card's data cardName = card1->contains("name") ? card1->value("name").toString() : QString(""); cardCost = card1->contains("manaCost") ? card1->value("manaCost").toString() : QString(""); + cmc = card1->contains("cmc") ? card1->value("cmc").toString() : QString(""); cardType = card1->contains("type") ? card1->value("type").toString() : QString(""); cardPT = card1->contains("power") || card1->contains("toughness") ? card1->value("power").toString() + QString('/') + card1->value("toughness").toString() : QString(""); cardText = card1->contains("text") ? card1->value("text").toString() : QString(""); @@ -192,18 +195,22 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data) // add second card's data cardName += card2->contains("name") ? QString(" // ") + card2->value("name").toString() : QString(""); cardCost += card2->contains("manaCost") ? QString(" // ") + card2->value("manaCost").toString() : QString(""); + cmc += card2->contains("cmc") ? QString(" // ") + card2->value("cmc").toString() : QString(""); cardType += card2->contains("type") ? QString(" // ") + card2->value("type").toString() : QString(""); cardPT += card2->contains("power") || card2->contains("toughness") ? QString(" // ") + card2->value("power").toString() + QString('/') + card2->value("toughness").toString() : QString(""); cardText += card2->contains("text") ? QString("\n\n---\n\n") + card2->value("text").toString() : QString(""); } else { - // first card od a pair; enqueue for later merging - splitCards.insert(cardId, map); + // first card of a pair; enqueue for later merging + // Conditional on cardId because promo prints have no muid - see #640 + if (cardId) + splitCards.insert(cardId, map); continue; } } else { // normal cards handling cardName = map.contains("name") ? map.value("name").toString() : QString(""); cardCost = map.contains("manaCost") ? map.value("manaCost").toString() : QString(""); + cmc = map.contains("cmc") ? map.value("cmc").toString() : QString(""); cardType = map.contains("type") ? map.value("type").toString() : QString(""); cardPT = map.contains("power") || map.contains("toughness") ? map.value("power").toString() + QString('/') + map.value("toughness").toString() : QString(""); cardText = map.contains("text") ? map.value("text").toString() : QString(""); @@ -218,7 +225,7 @@ int OracleImporter::importTextSpoiler(CardSet *set, const QVariant &data) } if (!cardIsToken) { - CardInfo *card = addCard(set->getShortName(), cardName, cardIsToken, cardId, cardCost, cardType, cardPT, cardLoyalty, cardText.split("\n")); + CardInfo *card = addCard(set->getShortName(), cardName, cardIsToken, cardId, cardCost, cmc, cardType, cardPT, cardLoyalty, cardText.split("\n")); if (!set->contains(card)) { card->addToSet(set); diff --git a/oracle/src/oracleimporter.h b/oracle/src/oracleimporter.h index 27d89085..7bbb5363 100644 --- a/oracle/src/oracleimporter.h +++ b/oracle/src/oracleimporter.h @@ -32,7 +32,7 @@ private: QVariantMap setsMap; QString dataDir; - CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, QString &cardCost, const QString &cardType, const QString &cardPT, int cardLoyalty, const QStringList &cardText); + CardInfo *addCard(const QString &setName, QString cardName, bool isToken, int cardId, QString &cardCost, QString &cmc, const QString &cardType, const QString &cardPT, int cardLoyalty, const QStringList &cardText); signals: void setIndexChanged(int cardsImported, int setIndex, const QString &setName); void dataReadProgress(int bytesRead, int totalBytes); diff --git a/travis-compile.sh b/travis-compile.sh index 21b30855..148169c6 100755 --- a/travis-compile.sh +++ b/travis-compile.sh @@ -9,4 +9,4 @@ if [[ $TRAVIS_OS_NAME == "osx" && $QT4 == 0 ]]; then prefix="-DCMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.0/" fi cmake .. -DWITH_SERVER=1 -DWITH_QT4=$QT4 $prefix -make +make -j2