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