Преглед на файлове

Sound patches from Ubuntux #7 - #10:
* Some sound code cleanups
* Renamed soundBase::soundNames into soundBase::soundID
* Add a music handler destructor
* Add Archdevil and vampire pre and post movement sounds

I've applied minor change to fix CMusicHandler - GeniusAI conflict: moved sounds bimap to the .cpp file.

(vcmi_sounds_cleanup.diff
vcmi_sounds_cleanup2.diff
vcmi_sounds_cleanup3.diff
vcmi_add_sounds.diff)

Michał W. Urbańczyk преди 16 години
родител
ревизия
df25dd7efb

+ 1 - 1
AI/EmptyAI/CEmptyAI.h

@@ -15,7 +15,7 @@ public:
 	void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
 	void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
 	void tileRevealed(int3 pos){};
 	void tileRevealed(int3 pos){};
 	void tileHidden(int3 pos){};
 	void tileHidden(int3 pos){};
-	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel){};
+	void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel){};
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd){};
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd){};
 	void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
 	void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
 };
 };

+ 1 - 1
AI/GeniusAI/CGeniusAI.cpp

@@ -69,7 +69,7 @@ void GeniusAI::CGeniusAI::showGarrisonDialog( const CArmedInstance *up, const CG
 	onEnd();
 	onEnd();
 }
 }
 
 
-void CGeniusAI::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel )
+void CGeniusAI::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel )
 {
 {
 	m_cb->selectionMade(cancel ? 0 : 1, askID);
 	m_cb->selectionMade(cancel ? 0 : 1, askID);
 }
 }

+ 1 - 1
AI/GeniusAI/CGeniusAI.h

@@ -190,7 +190,7 @@ public:
 	virtual void heroMoved(const HeroMoveDetails &);
 	virtual void heroMoved(const HeroMoveDetails &);
 	virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) {};
 	virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, int val) {};
 	virtual void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
 	virtual void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
-	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel);
+	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel);
 	virtual void tileRevealed(int3 pos){};
 	virtual void tileRevealed(int3 pos){};
 	virtual void tileHidden(int3 pos){};
 	virtual void tileHidden(int3 pos){};
 	virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
 	virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);

+ 6 - 0
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(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);
 		handleStartMoving(number);
 	}
 	}
 	if(moveStarted)
 	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(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);
 			creAnims[number]->setType(21);
 
 
 			//for(int i=0; i<creAnims[number]->framesInGroup(21)*getAnimSpeedMultiplier()-1; ++i)
 			//for(int i=0; i<creAnims[number]->framesInGroup(21)*getAnimSpeedMultiplier()-1; ++i)

+ 2 - 2
CGameInterface.h

@@ -80,10 +80,10 @@ public:
 	virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){};
 	virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){};
 	virtual void init(ICallback * CB){};
 	virtual void init(ICallback * CB){};
 	virtual void receivedResource(int type, int val){};
 	virtual void receivedResource(int type, int val){};
-	virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, soundBase::soundNames soundID){};
+	virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, soundBase::soundID soundID){};
 	//virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
 	//virtual void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
 	//virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
 	//virtual void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID){};
-	virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &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<Component> &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<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done
 	virtual void tileHidden(const std::set<int3> &pos){};
 	virtual void tileHidden(const std::set<int3> &pos){};
 	virtual void tileRevealed(const std::set<int3> &pos){};
 	virtual void tileRevealed(const std::set<int3> &pos){};

+ 3 - 3
CPlayerInterface.cpp

@@ -2409,7 +2409,7 @@ void CPlayerInterface::showComp(SComponent comp)
 	adventureInt->infoBar.showComp(&comp,4000);
 	adventureInt->infoBar.showComp(&comp,4000);
 }
 }
 
 
-void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<Component*> &components, soundBase::soundNames soundID)
+void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<Component*> &components, soundBase::soundID soundID)
 {
 {
 	std::vector<SComponent*> intComps;
 	std::vector<SComponent*> intComps;
 	for(int i=0;i<components.size();i++)
 	for(int i=0;i<components.size();i++)
@@ -2417,7 +2417,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 	showInfoDialog(text,intComps,soundID);
 	showInfoDialog(text,intComps,soundID);
 }
 }
 
 
-void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, soundBase::soundNames soundID)
+void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, soundBase::soundID soundID)
 {
 {
 	{
 	{
 		boost::unique_lock<boost::mutex> un(showingDialog->mx);
 		boost::unique_lock<boost::mutex> un(showingDialog->mx);
@@ -2463,7 +2463,7 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto
 	LOCPLINT->pushInt(temp);
 	LOCPLINT->pushInt(temp);
 }
 }
 
 
-void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundNames soundID, bool selection, bool cancel )
+void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, soundBase::soundID soundID, bool selection, bool cancel )
 {
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
 
 

+ 3 - 3
CPlayerInterface.h

@@ -592,10 +592,10 @@ public:
 	void heroMovePointsChanged(const CGHeroInstance * hero);
 	void heroMovePointsChanged(const CGHeroInstance * hero);
 	void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town);
 	void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town);
 	void receivedResource(int type, int val);
 	void receivedResource(int type, int val);
-	void showInfoDialog(const std::string &text, const std::vector<Component*> &components, soundBase::soundNames soundID);
+	void showInfoDialog(const std::string &text, const std::vector<Component*> &components, soundBase::soundID soundID);
 	//void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
 	//void showSelDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
 	//void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
 	//void showYesNoDialog(const std::string &text, const std::vector<Component*> &components, ui32 askID);
-	void showBlockingDialog(const std::string &text, const std::vector<Component> &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<Component> &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<void()> &onEnd);
 	void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, boost::function<void()> &onEnd);
 	void tileHidden(const std::set<int3> &pos);
 	void tileHidden(const std::set<int3> &pos);
 	void tileRevealed(const std::set<int3> &pos);
 	void tileRevealed(const std::set<int3> &pos);
@@ -636,7 +636,7 @@ public:
 	void handleMouseMotion(SDL_Event *sEvent);
 	void handleMouseMotion(SDL_Event *sEvent);
 	void init(ICallback * CB);
 	void init(ICallback * CB);
 	int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
 	int3 repairScreenPos(int3 pos); //returns position closest to pos we can center screen on
-	void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, soundBase::soundNames soundID);
+	void showInfoDialog(const std::string &text, const std::vector<SComponent*> & components, soundBase::soundID soundID);
 	void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close
 	void showYesNoDialog(const std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> 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);
 	bool moveHero(const CGHeroInstance *h, CPath path);
 
 

+ 2 - 2
client/NetPacksClient.cpp

@@ -266,7 +266,7 @@ void InfoWindow::applyCl( CClient *cl )
 	std::string str = toString(text);
 	std::string str = toString(text);
 
 
 	if(vstd::contains(cl->playerint,player))
 	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
 	else
 		tlog2 << "We received InfoWindow for not our player...\n";
 		tlog2 << "We received InfoWindow for not our player...\n";
 }
 }
@@ -285,7 +285,7 @@ void BlockingDialog::applyCl( CClient *cl )
 {
 {
 	std::string str = toString(text);
 	std::string str = toString(text);
 	if(vstd::contains(cl->playerint,player))
 	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
 	else
 		tlog2 << "We received YesNoDialog for not our player...\n";
 		tlog2 << "We received YesNoDialog for not our player...\n";
 }
 }

+ 1 - 1
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
 Mummy MUMYATTK.wav MUMYDFND.wav MUMYKILL.wav MUMYMOVE.wav invalid MUMYWNCE.wav
 NagaGuardian NGRDATTK.wav NGRDDFND.wav NGRDKILL.wav NGRDMOVE.wav invalid NGRDWNCE.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
 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
 ObsidianGargoyle OGRGATTK.wav OGRGDFND.wav OGRGKILL.wav OGRGMOVE.wav invalid OGRGWNCE.wav
 Ogre OGREATTK.wav OGREDFND.wav OGREKILL.wav OGREMOVE.wav invalid OGREWNCE.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
 OgreMage OGRMATTK.wav OGRMDFND.wav OGRMKILL.wav OGRMMOVE.wav OGRMSHOT.wav OGRMWNCE.wav

+ 2 - 0
hch/CCreatureHandler.cpp

@@ -107,6 +107,8 @@ void CCreatureHandler::loadCreatures()
 		ncre.sounds.wince = soundBase::invalid;
 		ncre.sounds.wince = soundBase::invalid;
 		ncre.sounds.ext1 = soundBase::invalid;
 		ncre.sounds.ext1 = soundBase::invalid;
 		ncre.sounds.ext2 = soundBase::invalid;
 		ncre.sounds.ext2 = soundBase::invalid;
+		ncre.sounds.startMoving = soundBase::invalid;
+		ncre.sounds.endMoving = soundBase::invalid;
 
 
 		int befi=i;
 		int befi=i;
 		for(i; i<andame; ++i)
 		for(i; i<andame; ++i)

+ 10 - 8
hch/CCreatureHandler.h

@@ -46,14 +46,16 @@ public:
 
 
 	// Sound infos
 	// Sound infos
 	struct {
 	struct {
-		soundBase::soundNames attack;
-		soundBase::soundNames defend;
-		soundBase::soundNames killed; // was killed died
-		soundBase::soundNames move;
-		soundBase::soundNames shoot; // range attack
-		soundBase::soundNames wince; // attacked but did not die
-		soundBase::soundNames ext1;	 // creature specific extension
-		soundBase::soundNames ext2;	 // creature specific extension
+		soundBase::soundID attack;
+		soundBase::soundID defend;
+		soundBase::soundID killed; // was killed died
+		soundBase::soundID move;
+		soundBase::soundID shoot; // range attack
+		soundBase::soundID wince; // attacked but did not die
+		soundBase::soundID ext1;  // creature specific extension
+		soundBase::soundID ext2;  // creature specific extension
+		soundBase::soundID startMoving; // usually same as ext1
+		soundBase::soundID endMoving;	// usually same as ext2
 	} sounds;
 	} sounds;
 
 
 	bool isDoubleWide() const; //returns true if unit is double wide on battlefield
 	bool isDoubleWide() const; //returns true if unit is double wide on battlefield

+ 73 - 42
hch/CMusicHandler.cpp

@@ -3,6 +3,7 @@
 #include <sstream>
 #include <sstream>
 #include <boost/assign/std/vector.hpp> 
 #include <boost/assign/std/vector.hpp> 
 #include <boost/assign/list_of.hpp>
 #include <boost/assign/list_of.hpp>
+#include <boost/bimap.hpp>
 
 
 #include <SDL_mixer.h>
 #include <SDL_mixer.h>
 
 
@@ -23,19 +24,44 @@
 
 
 using namespace boost::assign;
 using namespace boost::assign;
 
 
+boost::bimap<soundBase::soundID, std::string> sounds;
+
+CMusicHandler::~CMusicHandler()
+{
+	if (!audioInit)
+		return;
+
+	if (sndh) {
+		Mix_HaltChannel(-1);
+		delete sndh;
+	}
+
+	std::map<soundBase::soundID, Mix_Chunk *>::iterator it;
+	for (it=soundChunks.begin(); it != soundChunks.end(); it++) {
+		if (it->second)
+			Mix_FreeChunk(it->second);
+	}
+
+	Mix_CloseAudio();
+}
+
 void CMusicHandler::initMusics()
 void CMusicHandler::initMusics()
 {
 {
+	if (audioInit)
+		return;
+
 	if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)==-1)
 	if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024)==-1)
 	{
 	{
 		printf("Mix_OpenAudio error: %s!!!\n", Mix_GetError());
 		printf("Mix_OpenAudio error: %s!!!\n", Mix_GetError());
 		return;
 		return;
 	}
 	}
-	atexit(Mix_CloseAudio);
+
+	audioInit = true;
 
 
 	// Map sound names
 	// Map sound names
 #define VCMI_SOUND_NAME(x) ( soundBase::x,
 #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<boost::bimap<soundBase::soundID, std::string>::relation>
 		VCMI_SOUND_LIST;
 		VCMI_SOUND_LIST;
 #undef VCMI_SOUND_NAME
 #undef VCMI_SOUND_NAME
 #undef VCMI_SOUND_FILE
 #undef VCMI_SOUND_FILE
@@ -49,11 +75,6 @@ void CMusicHandler::initMusics()
 		soundBase::horseSubterranean, soundBase::horseLava,
 		soundBase::horseSubterranean, soundBase::horseLava,
 		soundBase::horseWater, soundBase::horseRock;
 		soundBase::horseWater, soundBase::horseRock;
 
 
-	// Create reverse map. It's used during game init to map names to internal IDs
-	std::map<soundBase::soundNames, cachedSounds>::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");
 	//AITheme0 = Mix_LoadMUS(DATA_DIR "MP3" PATHSEPARATOR "AITheme0.mp3");
 	//AITheme1 = Mix_LoadMUS(DATA_DIR "MP3" PATHSEPARATOR "AITHEME1.mp3");
 	//AITheme1 = Mix_LoadMUS(DATA_DIR "MP3" PATHSEPARATOR "AITHEME1.mp3");
 	//AITheme2 = Mix_LoadMUS(DATA_DIR "MP3" PATHSEPARATOR "AITHEME2.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"));
 	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<soundBase::soundID, std::string>::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)
 	if (!data)
 		return NULL;
 		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
 	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<soundBase::soundID, Mix_Chunk *>(soundID, chunk));
 
 
 	return 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<std::string, soundBase::soundNames>::iterator it;
+	boost::bimap<soundBase::soundID, std::string>::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;
 		return soundBase::invalid;
 	else
 	else
 		return it->second;
 		return it->second;
@@ -167,6 +197,15 @@ void CMusicHandler::initCreaturesSounds(std::vector<CCreature> &creatures)
 			c.sounds.wince = getSoundID(wince);
 			c.sounds.wince = getSoundID(wince);
 			c.sounds.ext1 = getSoundID(ext1);
 			c.sounds.ext1 = getSoundID(ext1);
 			c.sounds.ext2 = getSoundID(ext2);
 			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();
 	ifs.close();
@@ -187,40 +226,32 @@ void CMusicHandler::initCreaturesSounds(std::vector<CCreature> &creatures)
 }
 }
 
 
 // Plays a sound, and return its channel so we can fade it out later
 // 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;
 	int channel;
+	Mix_Chunk *chunk;
+	std::map<soundBase::soundID, Mix_Chunk *>::iterator it;
 
 
 	if (!sndh)
 	if (!sndh)
 		return -1;
 		return -1;
 
 
-	std::map<soundBase::soundNames, cachedSounds>::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;
 	return channel;
 }
 }
 
 
 // Helper. Randomly select a sound from an array and play it
 // Helper. Randomly select a sound from an array and play it
-int CMusicHandler::playSoundFromSet(std::vector<soundBase::soundNames> &sound_vec)
+int CMusicHandler::playSoundFromSet(std::vector<soundBase::soundID> &sound_vec)
 {
 {
 	return playSound(sound_vec[rand() % sound_vec.size()]);
 	return playSound(sound_vec[rand() % sound_vec.size()]);
 }
 }

+ 10 - 19
hch/CMusicHandler.h

@@ -20,38 +20,29 @@ class CMusicHandler
 {
 {
 private:
 private:
 	CSndHandler *sndh;
 	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<soundBase::soundID, Mix_Chunk *> 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<soundBase::soundNames, cachedSounds> sounds;
-	std::map<std::string, soundBase::soundNames> reverse_sounds;
-
-	Mix_Chunk *GetSoundChunk(std::string srcName);
+	bool audioInit;
 
 
 public:
 public:
-	CMusicHandler(): sndh(NULL) {};
+	CMusicHandler(): sndh(NULL), audioInit(false) {};
+	~CMusicHandler();
 
 
 	void initMusics();
 	void initMusics();
 	void initCreaturesSounds(std::vector<CCreature> &creatures);
 	void initCreaturesSounds(std::vector<CCreature> &creatures);
 
 
 	// Sounds
 	// Sounds
-	int playSound(soundBase::soundNames soundID, int repeats=0);
-	int playSoundFromSet(std::vector<soundBase::soundNames> &sound_vec);
+	int playSound(soundBase::soundID soundID, int repeats=0);
+	int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
 	void stopSound(int handler);
 	void stopSound(int handler);
 
 
 	// Sets
 	// Sets
-	std::vector<soundBase::soundNames> pickup_sounds;
-	std::vector<soundBase::soundNames> horseSounds;
+	std::vector<soundBase::soundID> pickup_sounds;
+	std::vector<soundBase::soundID> horseSounds;
 };
 };
 
 
 #endif // __CMUSICHANDLER_H__
 #endif // __CMUSICHANDLER_H__

+ 1 - 1
hch/CSoundBase.h

@@ -1026,7 +1026,7 @@ public:
 	// We must keep an entry 0 for an invalid or no sound.
 	// We must keep an entry 0 for an invalid or no sound.
 #define VCMI_SOUND_NAME(x) x,
 #define VCMI_SOUND_NAME(x) x,
 #define VCMI_SOUND_FILE(y)
 #define VCMI_SOUND_FILE(y)
-	enum soundNames {
+	enum soundID {
 		invalid=0,
 		invalid=0,
 		sound_todo=1,			// temp entry until code is fixed
 		sound_todo=1,			// temp entry until code is fixed
 		VCMI_SOUND_LIST
 		VCMI_SOUND_LIST