diff --git a/cockatrice/cockatrice.pro b/cockatrice/cockatrice.pro index 4a0203f2..7d84a228 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 svg multimedia HEADERS += src/abstractcounter.h \ src/counter_general.h \ @@ -71,6 +71,7 @@ HEADERS += src/abstractcounter.h \ src/localserverinterface.h \ src/localclient.h \ src/translation.h \ + src/soundengine.h \ ../common/color.h \ ../common/serializable_item.h \ ../common/decklist.h \ @@ -153,6 +154,7 @@ SOURCES += src/abstractcounter.cpp \ src/localserver.cpp \ src/localserverinterface.cpp \ src/localclient.cpp \ + src/soundengine.cpp \ ../common/serializable_item.cpp \ ../common/decklist.cpp \ ../common/protocol.cpp \ diff --git a/cockatrice/cockatrice.qrc b/cockatrice/cockatrice.qrc index d57e461e..9e20650d 100644 --- a/cockatrice/cockatrice.qrc +++ b/cockatrice/cockatrice.qrc @@ -97,6 +97,13 @@ resources/counters/general.svg resources/counters/general_highlight.svg + resources/sounds/draw.raw + resources/sounds/notification.raw + resources/sounds/playcard.raw + resources/sounds/shuffle.raw + resources/sounds/tap.raw + resources/sounds/untap.raw + resources/userlevels/normal.svg resources/userlevels/registered.svg resources/userlevels/judge.svg diff --git a/cockatrice/src/carditem.cpp b/cockatrice/src/carditem.cpp index 21ae3bb6..57cef89f 100644 --- a/cockatrice/src/carditem.cpp +++ b/cockatrice/src/carditem.cpp @@ -360,7 +360,7 @@ void CardItem::resetState() annotation.clear(); attachedTo = 0; attachedCards.clear(); - setTapped(false); + setTapped(false, false); setDoesntUntap(false); update(); } diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index 88bdfd98..a07fff6c 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -377,6 +377,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 +393,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 +424,7 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage() QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(generalGroupBox); mainLayout->addWidget(animationGroupBox); + mainLayout->addWidget(soundGroupBox); setLayout(mainLayout); } @@ -410,6 +435,24 @@ 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); } MessagesSettingsPage::MessagesSettingsPage() diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index 70e231f2..54648482 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -76,10 +76,18 @@ 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(); diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index 5b872b69..8ce2581b 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 b1f30bdb..f8e5a147 100644 --- a/cockatrice/src/main.h +++ b/cockatrice/src/main.h @@ -3,6 +3,7 @@ class CardDatabase; class QTranslator; +class SoundEngine; extern CardDatabase *db; diff --git a/cockatrice/src/messagelogwidget.cpp b/cockatrice/src/messagelogwidget.cpp index b2907e8c..15928aa8 100644 --- a/cockatrice/src/messagelogwidget.cpp +++ b/cockatrice/src/messagelogwidget.cpp @@ -3,6 +3,7 @@ #include "cardzone.h" #include "cardinfowidget.h" #include "protocol_items.h" +#include "soundengine.h" #include #include #include @@ -60,6 +61,7 @@ void MessageLogWidget::logGameJoined(int gameId) void MessageLogWidget::logJoin(Player *player) { + soundEngine->notification(); append(tr("%1 has joined the game.").arg(sanitizeHtml(player->getName()))); } @@ -123,6 +125,7 @@ void MessageLogWidget::logSpectatorSay(QString spectatorName, QString message) void MessageLogWidget::logShuffle(Player *player) { + soundEngine->shuffle(); append(tr("%1 shuffles his library.").arg(sanitizeHtml(player->getName()))); } @@ -133,6 +136,7 @@ void MessageLogWidget::logRollDie(Player *player, int sides, int roll) void MessageLogWidget::logDrawCards(Player *player, int number) { + soundEngine->draw(); append(tr("%1 draws %n card(s).", "", number).arg(sanitizeHtml(player->getName()))); } @@ -212,6 +216,7 @@ void MessageLogWidget::doMoveCard(LogMoveCard &attributes) QString finalStr; if (targetName == "table") { + soundEngine->playCard(); if (moveCardTapped.value(attributes.card)) finalStr = tr("%1 puts %2 into play tapped%3."); else @@ -233,8 +238,10 @@ void MessageLogWidget::doMoveCard(LogMoveCard &attributes) finalStr = 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)); } @@ -317,6 +324,11 @@ void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int c 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 { @@ -409,6 +421,7 @@ void MessageLogWidget::logRevealCards(Player *player, CardZone *zone, int cardId void MessageLogWidget::logSetActivePlayer(Player *player) { + soundEngine->notification(); append(QString()); append("" + tr("It is now %1's turn.").arg(player->getName()) + ""); append(QString()); @@ -416,6 +429,7 @@ void MessageLogWidget::logSetActivePlayer(Player *player) void MessageLogWidget::logSetActivePhase(int phase) { + soundEngine->notification(); QString phaseName; switch (phase) { case 0: phaseName = tr("untap step"); break; diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 4d621a8a..bb0ecdae 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -27,6 +27,9 @@ SettingsCache::SettingsCache() 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(); } void SettingsCache::setLang(const QString &_lang) @@ -148,3 +151,16 @@ 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(); +} diff --git a/cockatrice/src/settingscache.h b/cockatrice/src/settingscache.h index 8960dc56..6a8f1a99 100644 --- a/cockatrice/src/settingscache.h +++ b/cockatrice/src/settingscache.h @@ -20,6 +20,7 @@ signals: void displayCardNamesChanged(); void horizontalHandChanged(); void invertVerticalCoordinateChanged(); + void soundPathChanged(); private: QSettings *settings; @@ -34,6 +35,8 @@ private: bool invertVerticalCoordinate; bool tapAnimation; bool zoneViewSortByName, zoneViewSortByType; + bool soundEnabled; + QString soundPath; public: SettingsCache(); QString getLang() const { return lang; } @@ -54,6 +57,8 @@ public: 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; } public slots: void setLang(const QString &_lang); void setDeckPath(const QString &_deckPath); @@ -73,6 +78,8 @@ public slots: void setTapAnimation(int _tapAnimation); void setZoneViewSortByName(int _zoneViewSortByName); void setZoneViewSortByType(int _zoneViewSortByType); + void setSoundEnabled(int _soundEnabled); + void setSoundPath(const QString &_soundPath); }; extern SettingsCache *settingsCache; diff --git a/sounds/draw.raw b/sounds/draw.raw new file mode 100644 index 00000000..3732125f 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 00000000..19906b48 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 00000000..c9fb802d 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 00000000..f092e567 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 00000000..db5290a8 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 00000000..938efe26 Binary files /dev/null and b/sounds/untap.raw differ