فهرست منبع

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

Creature parser is complete (untested).
DjWarmonger 13 سال پیش
والد
کامیت
9438cfc7e2
5فایلهای تغییر یافته به همراه153 افزوده شده و 81 حذف شده
  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;