Browse Source

Moved creature sounds to CCreature. Sound IDs are now stored as strings.

Creature parser is complete (untested).
DjWarmonger 13 years ago
parent
commit
9438cfc7e2
5 changed files with 153 additions and 81 deletions
  1. 43 40
      client/CMusicHandler.cpp
  2. 28 27
      client/CMusicHandler.h
  3. 45 0
      lib/CCreatureHandler.cpp
  4. 24 0
      lib/CCreatureHandler.h
  5. 13 14
      lib/CModHandler.cpp

+ 43 - 40
client/CMusicHandler.cpp

@@ -153,6 +153,25 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(soundBase::soundID soundID)
 	}
 }
 
+Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound)
+{
+	// Load and insert
+	try
+	{
+		auto data = CResourceHandler::get()->loadData(ResourceID(std::string("SOUNDS/") + sound, EResType::SOUND)); //TODO: allow other sound folders?
+
+		SDL_RWops *ops = SDL_RWFromMem(data.first.release(), data.second);
+		Mix_Chunk *chunk;
+		chunk = Mix_LoadWAV_RW(ops, 1);	// will free ops
+		return chunk;
+	}
+	catch(std::exception &e)
+	{
+		tlog3 << "Cannot get sound " << sound << " chunk: " << e.what() << "\n";
+		return nullptr;
+	}
+}
+
 // Get a soundID given a filename
 soundBase::soundID CSoundHandler::getSoundID(const std::string &fileName)
 {
@@ -167,46 +186,6 @@ soundBase::soundID CSoundHandler::getSoundID(const std::string &fileName)
 
 void CSoundHandler::initCreaturesSounds(const std::vector<ConstTransitivePtr< CCreature> > &creatures)
 {
-	tlog5 << "\t\tReading config/cr_sounds.json" << std::endl;
-	const JsonNode config(ResourceID("config/cr_sounds.json"));
-
-	CBattleSounds.resize(creatures.size());
-
-	if (!config["creature_sounds"].isNull()) {
-
-		BOOST_FOREACH(const JsonNode &node, config["creature_sounds"].Vector()) {
-			const JsonNode *value;
-			int id;
-
-			value = &node["name"];
-
-			bmap<std::string,int>::const_iterator i = CGI->creh->nameToID.find(value->String());
-			if (i != CGI->creh->nameToID.end())
-				id = i->second;
-			else
-			{
-				tlog1 << "Sound info for an unknown creature: " << value->String() << std::endl;
-				continue;
-			}
-
-			/* This is a bit ugly. Maybe we should use an array for
-			 * sound ids instead of separate variables and define
-			 * attack/defend/killed/... as indexes. */
-#define GET_SOUND_VALUE(value_name) do { value = &node[#value_name]; if (!value->isNull()) CBattleSounds[id].value_name = getSoundID(value->String()); } while(0)
-
-			GET_SOUND_VALUE(attack);
-			GET_SOUND_VALUE(defend);
-			GET_SOUND_VALUE(killed);
-			GET_SOUND_VALUE(move);
-			GET_SOUND_VALUE(shoot);
-			GET_SOUND_VALUE(wince);
-			GET_SOUND_VALUE(ext1);
-			GET_SOUND_VALUE(ext2);
-			GET_SOUND_VALUE(startMoving);
-			GET_SOUND_VALUE(endMoving);
-#undef GET_SOUND_VALUE
-		}
-	}
 
 	//commented to avoid spurious warnings
 	/*
@@ -269,6 +248,30 @@ int CSoundHandler::playSound(soundBase::soundID soundID, int repeats)
 	return channel;
 }
 
+int CSoundHandler::playSound(std::string sound, int repeats)
+{
+	if (!initialized)
+		return -1;
+
+	int channel;
+	Mix_Chunk *chunk = GetSoundChunk(sound);
+
+	if (chunk)
+	{
+		channel = Mix_PlayChannel(-1, chunk, repeats);
+		if (channel == -1)
+			tlog1 << "Unable to play sound file " << sound << " , error " << Mix_GetError() << std::endl;
+		else
+			callbacks[channel];//insert empty callback
+	}
+	else
+	{
+		channel = -1;
+	}
+
+	return channel;
+}
+
 // Helper. Randomly select a sound from an array and play it
 int CSoundHandler::playSoundFromSet(std::vector<soundBase::soundID> &sound_vec)
 {

+ 28 - 27
client/CMusicHandler.h

@@ -20,30 +20,30 @@ typedef struct _Mix_Music Mix_Music;
 struct Mix_Chunk;
 
 
-// Sound infos for creatures in combat
-struct CreaturesBattleSounds {
-	soundBase::soundID attack;
-	soundBase::soundID defend;
-	soundBase::soundID killed; // was killed or 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
-
-	CreaturesBattleSounds(): attack(soundBase::invalid),
-							 defend(soundBase::invalid),
-							 killed(soundBase::invalid),
-							 move(soundBase::invalid),
-							 shoot(soundBase::invalid),
-							 wince(soundBase::invalid),
-							 ext1(soundBase::invalid),
-							 ext2(soundBase::invalid),
-							 startMoving(soundBase::invalid),
-							 endMoving(soundBase::invalid) {};
-};
+//// Sound infos for creatures in combat
+//struct CreaturesBattleSounds {
+//	soundBase::soundID attack;
+//	soundBase::soundID defend;
+//	soundBase::soundID killed; // was killed or 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
+//
+//	CreaturesBattleSounds(): attack(soundBase::invalid),
+//							 defend(soundBase::invalid),
+//							 killed(soundBase::invalid),
+//							 move(soundBase::invalid),
+//							 shoot(soundBase::invalid),
+//							 wince(soundBase::invalid),
+//							 ext1(soundBase::invalid),
+//							 ext2(soundBase::invalid),
+//							 startMoving(soundBase::invalid),
+//							 endMoving(soundBase::invalid) {};
+//};
 
 class CAudioBase {
 protected:
@@ -70,6 +70,7 @@ private:
 	std::map<soundBase::soundID, Mix_Chunk *> soundChunks;
 
 	Mix_Chunk *GetSoundChunk(soundBase::soundID soundID);
+	Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound);
 
 	//have entry for every currently active channel
 	//boost::function will be NULL if callback was not set
@@ -87,13 +88,13 @@ public:
 
 	// Sounds
 	int playSound(soundBase::soundID soundID, int repeats=0);
+	int playSound(std::string sound, int repeats=0);
 	int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
 	void stopSound(int handler);
 
 	void setCallback(int channel, boost::function<void()> function);
 	void soundFinishedCallback(int channel);
 
-	std::vector <struct CreaturesBattleSounds> CBattleSounds;
 	std::map<const CSpell*, soundBase::soundID> spellSounds;
 
 	// Sets
@@ -102,8 +103,8 @@ public:
 	std::vector<soundBase::soundID> battleIntroSounds;
 };
 
-// Helper
-#define battle_sound(creature,what_sound) CCS->soundh->CBattleSounds[(creature)->idNumber].what_sound
+// Helper //now it looks somewhat useless
+#define battle_sound(creature,what_sound) creature->sounds.what_sound
 
 class CMusicHandler;
 

+ 45 - 0
lib/CCreatureHandler.cpp

@@ -466,6 +466,8 @@ void CCreatureHandler::loadCreatures()
 
 	buildBonusTreeForTiers();
 	loadAnimationInfo();
+	loadSoundsInfo();
+
 
 	//reading creature ability names
 	const JsonNode config2(ResourceID("config/bonusnames.json"));
@@ -691,6 +693,49 @@ void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, std::string & src, int
 	i+=2;
 }
 
+void CCreatureHandler::loadSoundsInfo()
+{
+	tlog5 << "\t\tReading config/cr_sounds.json" << std::endl;
+	const JsonNode config(ResourceID("config/cr_sounds.json"));
+
+	if (!config["creature_sounds"].isNull())
+	{
+
+		BOOST_FOREACH(const JsonNode &node, config["creature_sounds"].Vector())
+		{
+			const JsonNode *value;
+			int id;
+
+			value = &node["name"];
+
+			bmap<std::string,int>::const_iterator i = nameToID.find(value->String());
+			if (i != nameToID.end())
+				id = i->second;
+			else
+			{
+				tlog1 << "Sound info for an unknown creature: " << value->String() << std::endl;
+				continue;
+			}
+
+			/* This is a bit ugly. Maybe we should use an array for
+			 * sound ids instead of separate variables and define
+			 * attack/defend/killed/... as indexes. */
+#define GET_SOUND_VALUE(value_name) do { value = &node[#value_name]; if (!value->isNull()) creatures[id]->sounds.value_name = value->String(); } while(0)
+			GET_SOUND_VALUE(attack);
+			GET_SOUND_VALUE(defend);
+			GET_SOUND_VALUE(killed);
+			GET_SOUND_VALUE(move);
+			GET_SOUND_VALUE(shoot);
+			GET_SOUND_VALUE(wince);
+			GET_SOUND_VALUE(ext1);
+			GET_SOUND_VALUE(ext2);
+			GET_SOUND_VALUE(startMoving);
+			GET_SOUND_VALUE(endMoving);
+#undef GET_SOUND_VALUE
+		}
+	}
+}
+
 void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser & parser) //help function for parsing CREXPBON.txt
 {
 	bool enable = false; //some bonuses are activated with values 2 or 1

+ 24 - 0
lib/CCreatureHandler.h

@@ -6,6 +6,7 @@
 #include "ResourceSet.h"
 #include "GameConstants.h"
 #include "JsonNode.h"
+#include "../client/CMusicHandler.h"
 
 /*
  * CCreatureHandler.h, part of VCMI engine
@@ -20,6 +21,7 @@
 class CLegacyConfigParser;
 class CCreatureHandler;
 class CCreature;
+struct CreaturesBattleSounds;
 
 class DLL_LINKAGE CCreature : public CBonusSystemNode
 {
@@ -45,6 +47,26 @@ public:
 	int troopCountLocationOffset, attackClimaxFrame;
 	///end of anim info
 
+	//sound info
+	struct CreaturesBattleSounds
+	{
+		std::string attack;
+		std::string defend;
+		std::string killed; // was killed or died
+		std::string move;
+		std::string shoot; // range attack
+		std::string wince; // attacked but did not die
+		std::string ext1;  // creature specific extension
+		std::string ext2;  // creature specific extension
+		std::string startMoving; // usually same as ext1
+		std::string endMoving;	// usually same as ext2
+
+		template <typename Handler> void serialize(Handler &h, const int version)
+		{
+			h & attack & defend & killed & move & shoot & wince & ext1 & ext2 & startMoving & endMoving;
+		}
+	} sounds;
+
 	bool isItNativeTerrain(int terrain) const;
 	bool isDoubleWide() const; //returns true if unit is double wide on battlefield
 	bool isFlying() const; //returns true if it is a flying unit
@@ -85,6 +107,7 @@ public:
 			& timeBetweenFidgets & walkAnimationTime & attackAnimationTime & flightAnimationDistance
 			& upperRightMissleOffsetX & rightMissleOffsetX & lowerRightMissleOffsetX & upperRightMissleOffsetY & rightMissleOffsetY & lowerRightMissleOffsetY
 			& missleFrameAngles & troopCountLocationOffset & attackClimaxFrame;
+		h & sounds;
 
 		h & doubleWide;
 	}
@@ -126,6 +149,7 @@ public:
 	void buildBonusTreeForTiers();
 	void loadAnimationInfo();
 	void loadUnitAnimInfo(CCreature & unit, std::string & src, int & i);
+	void loadSoundsInfo();
 	void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser);
 	int stringToNumber(std::string & s);//help function for parsing CREXPBON.txt
 

+ 13 - 14
lib/CModHandler.cpp

@@ -165,21 +165,20 @@ CCreature * CModHandler::loadCreature (const JsonNode &node)
 	//we need to know creature id to add it
 	VLC->creh->idToProjectile[cre->idNumber] = value->String();
 
-	//TODO: sounds
-	//how to pass info to Client?
 	auto sounds = node["sound"];
-	//CreaturesBattleSounds cbs;
-	//cbs.attack = sounds["attack"].String();
-	//cbs.defend = sounds["defend"].String();
-	//cbs.killed = sounds["killed"].String(); // was killed or died
-	//cbs.move = sounds["move"].String();
-	//cbs.shoot = sounds["shoot"].String(); // range attack
-	//cbs.wince = sounds["wince"].String(); // attacked but did not die
-	//cbs.ext1 = "";  // creature specific extension
-	//cbs.ext2 = "";  // creature specific extension
-	//cbs.startMoving = sounds["moveStart"].String(); // usually same as ext1
-	//cbs.endMoving = sounds["moveEnd"].String();	// usually same as ext2
-	//CCS->soundh->CBattleSounds.push_back(cbs);
+
+#define GET_SOUND_VALUE(value_name) do { value = &node[#value_name]; if (!value->isNull()) cre->sounds.value_name = sounds[#value_name].String(); } while(0)
+	GET_SOUND_VALUE(attack);
+	GET_SOUND_VALUE(defend);
+	GET_SOUND_VALUE(killed);
+	GET_SOUND_VALUE(move);
+	GET_SOUND_VALUE(shoot);
+	GET_SOUND_VALUE(wince);
+	GET_SOUND_VALUE(ext1);
+	GET_SOUND_VALUE(ext2);
+	GET_SOUND_VALUE(startMoving);
+	GET_SOUND_VALUE(endMoving);
+#undef GET_SOUND_VALUE
 
 	creatures.push_back(cre);
 	return cre;