diff --git a/AI/EmptyAI/CEmptyAI.h b/AI/EmptyAI/CEmptyAI.h index 400f755a7..e105a56e3 100644 --- a/AI/EmptyAI/CEmptyAI.h +++ b/AI/EmptyAI/CEmptyAI.h @@ -15,7 +15,7 @@ public: void showSelDialog(std::string text, std::vector & components, int askID){}; void tileRevealed(int3 pos){}; void tileHidden(int3 pos){}; - void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel){}; + void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel){}; void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function &onEnd){}; void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback); }; diff --git a/AI/GeniusAI/CGeniusAI.cpp b/AI/GeniusAI/CGeniusAI.cpp index 409d66a90..b68882404 100644 --- a/AI/GeniusAI/CGeniusAI.cpp +++ b/AI/GeniusAI/CGeniusAI.cpp @@ -69,7 +69,7 @@ void GeniusAI::CGeniusAI::showGarrisonDialog( const CArmedInstance *up, const CG onEnd(); } -void CGeniusAI::showBlockingDialog( const std::string &text, const std::vector &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel ) +void CGeniusAI::showBlockingDialog( const std::string &text, const std::vector &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel ) { m_cb->selectionMade(cancel ? 0 : 1, askID); } diff --git a/AI/GeniusAI/CGeniusAI.h b/AI/GeniusAI/CGeniusAI.h index 2d9fde33e..30f71decb 100644 --- a/AI/GeniusAI/CGeniusAI.h +++ b/AI/GeniusAI/CGeniusAI.h @@ -190,7 +190,7 @@ public: virtual void heroMoved(const HeroMoveDetails &); virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) {}; virtual void showSelDialog(std::string text, std::vector & components, int askID){}; - virtual void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel); + virtual void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel); virtual void tileRevealed(int3 pos){}; virtual void tileHidden(int3 pos){}; virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback); diff --git a/CBattleInterface.cpp b/CBattleInterface.cpp index 26c4e9c2c..e93412b19 100644 --- a/CBattleInterface.cpp +++ b/CBattleInterface.cpp @@ -1095,6 +1095,8 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving, int d if(startMoving) //animation of starting move; some units don't have this animation (ie. halberdier) { + if (movedStack->creature->sounds.startMoving) + CGI->mush->playSound(movedStack->creature->sounds.startMoving); handleStartMoving(number); } if(moveStarted) @@ -1194,6 +1196,10 @@ void CBattleInterface::stackMoved(int number, int destHex, bool endMoving, int d { if(creAnims[number]->framesInGroup(21)!=0) // some units don't have this animation (ie. halberdier) { + if (movedStack->creature->sounds.endMoving) { + CGI->mush->playSound(movedStack->creature->sounds.endMoving); + } + creAnims[number]->setType(21); //for(int i=0; iframesInGroup(21)*getAnimSpeedMultiplier()-1; ++i) diff --git a/CGameInterface.h b/CGameInterface.h index 2863446cf..a09108f5d 100644 --- a/CGameInterface.h +++ b/CGameInterface.h @@ -80,10 +80,10 @@ public: virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){}; virtual void init(ICallback * CB){}; virtual void receivedResource(int type, int val){}; - virtual void showInfoDialog(const std::string &text, const std::vector &components, soundBase::soundNames soundID){}; + virtual void showInfoDialog(const std::string &text, const std::vector &components, soundBase::soundID soundID){}; //virtual void showSelDialog(const std::string &text, const std::vector &components, ui32 askID){}; //virtual void showYesNoDialog(const std::string &text, const std::vector &components, ui32 askID){}; - virtual void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, const soundBase::soundNames soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. + virtual void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, const soundBase::soundID soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done virtual void tileHidden(const std::set &pos){}; virtual void tileRevealed(const std::set &pos){}; diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index f744d15b8..fcb015840 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -2409,7 +2409,7 @@ void CPlayerInterface::showComp(SComponent comp) adventureInt->infoBar.showComp(&comp,4000); } -void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector &components, soundBase::soundNames soundID) +void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector &components, soundBase::soundID soundID) { std::vector intComps; for(int i=0;i & components, soundBase::soundNames soundID) +void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector & components, soundBase::soundID soundID) { { boost::unique_lock un(showingDialog->mx); @@ -2463,7 +2463,7 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto LOCPLINT->pushInt(temp); } -void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel ) +void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel ) { boost::unique_lock un(*pim); diff --git a/CPlayerInterface.h b/CPlayerInterface.h index eb36db297..47d53534c 100644 --- a/CPlayerInterface.h +++ b/CPlayerInterface.h @@ -592,10 +592,10 @@ public: void heroMovePointsChanged(const CGHeroInstance * hero); void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town); void receivedResource(int type, int val); - void showInfoDialog(const std::string &text, const std::vector &components, soundBase::soundNames soundID); + void showInfoDialog(const std::string &text, const std::vector &components, soundBase::soundID soundID); //void showSelDialog(const std::string &text, const std::vector &components, ui32 askID); //void showYesNoDialog(const std::string &text, const std::vector &components, ui32 askID); - void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. + void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel); //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function &onEnd); void tileHidden(const std::set &pos); void tileRevealed(const std::set &pos); @@ -636,7 +636,7 @@ public: void handleMouseMotion(SDL_Event *sEvent); void init(ICallback * CB); int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on - void showInfoDialog(const std::string &text, const std::vector & components, soundBase::soundNames soundID); + void showInfoDialog(const std::string &text, const std::vector & components, soundBase::soundID soundID); void showYesNoDialog(const std::string &text, const std::vector & components, CFunctionList onYes, CFunctionList onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close bool moveHero(const CGHeroInstance *h, CPath path); diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 970bdbcea..e20daec70 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -266,7 +266,7 @@ void InfoWindow::applyCl( CClient *cl ) std::string str = toString(text); if(vstd::contains(cl->playerint,player)) - cl->playerint[player]->showInfoDialog(str,comps,(soundBase::soundNames)soundID); + cl->playerint[player]->showInfoDialog(str,comps,(soundBase::soundID)soundID); else tlog2 << "We received InfoWindow for not our player...\n"; } @@ -285,7 +285,7 @@ void BlockingDialog::applyCl( CClient *cl ) { std::string str = toString(text); if(vstd::contains(cl->playerint,player)) - cl->playerint[player]->showBlockingDialog(str,components,id,(soundBase::soundNames)soundID,selection(),cancel()); + cl->playerint[player]->showBlockingDialog(str,components,id,(soundBase::soundID)soundID,selection(),cancel()); else tlog2 << "We received YesNoDialog for not our player...\n"; } diff --git a/config/cr_sounds.txt b/config/cr_sounds.txt index a6cf3cff7..019fd5c6c 100644 --- a/config/cr_sounds.txt +++ b/config/cr_sounds.txt @@ -96,7 +96,7 @@ Monk MONKATTK.wav MONKDFND.wav MONKKILL.wav MONKMOVE.wav MONKSHOT.wav MONKWNCE.w Mummy MUMYATTK.wav MUMYDFND.wav MUMYKILL.wav MUMYMOVE.wav invalid MUMYWNCE.wav NagaGuardian NGRDATTK.wav NGRDDFND.wav NGRDKILL.wav NGRDMOVE.wav invalid NGRDWNCE.wav NagaSentinel NSENATTK.wav NSENDFND.wav NSENKILL.wav NSENMOVE.wav invalid NSENWNCE.wav -Nosferatu NOSFATTK.wav NOSFDFND.wav NOSFEXT1.wav NOSFEXT2.wav NOSFKILL.wav NOSFMOVE.wav NOSFSHOT.wav NOSFWNCE.wav +Nosferatu NOSFATTK.wav NOSFDFND.wav NOSFKILL.wav NOSFMOVE.wav NOSFSHOT.wav NOSFWNCE.wav NOSFEXT1.wav NOSFEXT2.wav ObsidianGargoyle OGRGATTK.wav OGRGDFND.wav OGRGKILL.wav OGRGMOVE.wav invalid OGRGWNCE.wav Ogre OGREATTK.wav OGREDFND.wav OGREKILL.wav OGREMOVE.wav invalid OGREWNCE.wav OgreMage OGRMATTK.wav OGRMDFND.wav OGRMKILL.wav OGRMMOVE.wav OGRMSHOT.wav OGRMWNCE.wav diff --git a/hch/CCreatureHandler.cpp b/hch/CCreatureHandler.cpp index d7f6d9901..30fee1f00 100644 --- a/hch/CCreatureHandler.cpp +++ b/hch/CCreatureHandler.cpp @@ -107,6 +107,8 @@ void CCreatureHandler::loadCreatures() ncre.sounds.wince = soundBase::invalid; ncre.sounds.ext1 = soundBase::invalid; ncre.sounds.ext2 = soundBase::invalid; + ncre.sounds.startMoving = soundBase::invalid; + ncre.sounds.endMoving = soundBase::invalid; int befi=i; for(i; i #include #include +#include #include @@ -23,19 +24,44 @@ using namespace boost::assign; +boost::bimap sounds; + +CMusicHandler::~CMusicHandler() +{ + if (!audioInit) + return; + + if (sndh) { + Mix_HaltChannel(-1); + delete sndh; + } + + std::map::iterator it; + for (it=soundChunks.begin(); it != soundChunks.end(); it++) { + if (it->second) + Mix_FreeChunk(it->second); + } + + Mix_CloseAudio(); +} + void CMusicHandler::initMusics() { + if (audioInit) + return; + if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)==-1) { printf("Mix_OpenAudio error: %s!!!\n", Mix_GetError()); return; } - atexit(Mix_CloseAudio); + + audioInit = true; // Map sound names #define VCMI_SOUND_NAME(x) ( soundBase::x, -#define VCMI_SOUND_FILE(y) cachedSounds(#y, 0) ) - sounds = boost::assign::map_list_of +#define VCMI_SOUND_FILE(y) #y ) + sounds = boost::assign::list_of::relation> VCMI_SOUND_LIST; #undef VCMI_SOUND_NAME #undef VCMI_SOUND_FILE @@ -49,11 +75,6 @@ void CMusicHandler::initMusics() soundBase::horseSubterranean, soundBase::horseLava, soundBase::horseWater, soundBase::horseRock; - // Create reverse map. It's used during game init to map names to internal IDs - std::map::iterator it; - for ( it=sounds.begin() ; it != sounds.end(); it++ ) - reverse_sounds[(*it).second.filename] = (*it).first; - //AITheme0 = Mix_LoadMUS(DATA_DIR "MP3" PATHSEPARATOR "AITheme0.mp3"); //AITheme1 = Mix_LoadMUS(DATA_DIR "MP3" PATHSEPARATOR "AITHEME1.mp3"); //AITheme2 = Mix_LoadMUS(DATA_DIR "MP3" PATHSEPARATOR "AITHEME2.mp3"); @@ -101,33 +122,42 @@ void CMusicHandler::initMusics() sndh = new CSndHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "Heroes3.snd")); } -// Return an SDL chunk. Allocate if it is not cached yet. -Mix_Chunk *CMusicHandler::GetSoundChunk(std::string srcName) +// Allocate an SDL chunk and cache it. +Mix_Chunk *CMusicHandler::GetSoundChunk(soundBase::soundID soundID) { - int size; - const char *data = sndh->extract(srcName, size); - SDL_RWops *ops; - Mix_Chunk *chunk; + // Find its name + boost::bimap::left_iterator it; + it = sounds.left.find(soundID); + if (it == sounds.left.end()) + return NULL; + // Load and insert + int size; + const char *data = sndh->extract(it->second, size); if (!data) return NULL; - ops = SDL_RWFromConstMem(data, size); + SDL_RWops *ops = SDL_RWFromConstMem(data, size); + Mix_Chunk *chunk; chunk = Mix_LoadWAV_RW(ops, 1); // will free ops - if (!chunk) - fprintf(stderr, "Unable to mix: %s\n", - Mix_GetError()); + if (!chunk) { + tlog1 << "Unable to mix sound" << it->second << "(" << Mix_GetError() << ")" << std::endl; + return NULL; + } + + soundChunks.insert(std::pair(soundID, chunk)); return chunk; } -soundBase::soundNames CMusicHandler::getSoundID(std::string &fileName) +// Get a soundID given a filename +soundBase::soundID CMusicHandler::getSoundID(std::string &fileName) { - std::map::iterator it; + boost::bimap::right_iterator it; - it = reverse_sounds.find(fileName); - if (it == reverse_sounds.end()) + it = sounds.right.find(fileName); + if (it == sounds.right.end()) return soundBase::invalid; else return it->second; @@ -167,6 +197,15 @@ void CMusicHandler::initCreaturesSounds(std::vector &creatures) c.sounds.wince = getSoundID(wince); c.sounds.ext1 = getSoundID(ext1); c.sounds.ext2 = getSoundID(ext2); + + // Special creatures + if (c.idNumber == 55 || // Archdevil + c.idNumber == 62 || // Vampire + c.idNumber == 62) // Vampire Lord + { + c.sounds.startMoving = c.sounds.ext1; + c.sounds.endMoving = c.sounds.ext2; + } } } ifs.close(); @@ -187,40 +226,32 @@ void CMusicHandler::initCreaturesSounds(std::vector &creatures) } // Plays a sound, and return its channel so we can fade it out later -int CMusicHandler::playSound(soundBase::soundNames soundID, int repeats) +int CMusicHandler::playSound(soundBase::soundID soundID, int repeats) { int channel; + Mix_Chunk *chunk; + std::map::iterator it; if (!sndh) return -1; - std::map::iterator it; + chunk = GetSoundChunk(soundID); - it = sounds.find(soundID); - if (it == sounds.end()) - return -1; - - class cachedSounds sound = it->second; - - if (!sound.chunk) { - sound.chunk = GetSoundChunk(sound.filename); - } - - if (sound.chunk) + if (chunk) { - channel = Mix_PlayChannel(-1, sound.chunk, repeats); - if(channel == -1) - { - fprintf(stderr, "Unable to play WAV file("DATA_DIR "Data" PATHSEPARATOR "Heroes3.wav::%s): %s\n", - sound.filename.c_str(),Mix_GetError()); - } + channel = Mix_PlayChannel(-1, chunk, repeats); + if (channel == -1) + tlog1 << "Unable to play sound file " << soundID << std::endl; + + } else { + channel = -1; } return channel; } // Helper. Randomly select a sound from an array and play it -int CMusicHandler::playSoundFromSet(std::vector &sound_vec) +int CMusicHandler::playSoundFromSet(std::vector &sound_vec) { return playSound(sound_vec[rand() % sound_vec.size()]); } diff --git a/hch/CMusicHandler.h b/hch/CMusicHandler.h index 47242b3d4..2486ed0de 100644 --- a/hch/CMusicHandler.h +++ b/hch/CMusicHandler.h @@ -20,38 +20,29 @@ class CMusicHandler { private: CSndHandler *sndh; - soundBase::soundNames getSoundID(std::string &fileName); + soundBase::soundID getSoundID(std::string &fileName); - class cachedSounds { - public: - std::string filename; - Mix_Chunk *chunk; + std::map soundChunks; - // This is some horrible C++ abuse. Isn't there any way to do - // something simplier to init sounds? - cachedSounds(std::string filename_in, Mix_Chunk *chunk_in): - filename(filename_in), chunk(chunk_in) {}; - }; + Mix_Chunk *GetSoundChunk(soundBase::soundID soundID); - std::map sounds; - std::map reverse_sounds; - - Mix_Chunk *GetSoundChunk(std::string srcName); + bool audioInit; public: - CMusicHandler(): sndh(NULL) {}; + CMusicHandler(): sndh(NULL), audioInit(false) {}; + ~CMusicHandler(); void initMusics(); void initCreaturesSounds(std::vector &creatures); // Sounds - int playSound(soundBase::soundNames soundID, int repeats=0); - int playSoundFromSet(std::vector &sound_vec); + int playSound(soundBase::soundID soundID, int repeats=0); + int playSoundFromSet(std::vector &sound_vec); void stopSound(int handler); // Sets - std::vector pickup_sounds; - std::vector horseSounds; + std::vector pickup_sounds; + std::vector horseSounds; }; #endif // __CMUSICHANDLER_H__ diff --git a/hch/CSoundBase.h b/hch/CSoundBase.h index 216c5b73b..b2046031e 100644 --- a/hch/CSoundBase.h +++ b/hch/CSoundBase.h @@ -1026,7 +1026,7 @@ public: // We must keep an entry 0 for an invalid or no sound. #define VCMI_SOUND_NAME(x) x, #define VCMI_SOUND_FILE(y) - enum soundNames { + enum soundID { invalid=0, sound_todo=1, // temp entry until code is fixed VCMI_SOUND_LIST