1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

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)
This commit is contained in:
Michał W. Urbańczyk 2009-04-30 10:53:06 +00:00
parent 6ccd9c2701
commit df25dd7efb
14 changed files with 116 additions and 84 deletions

View File

@ -15,7 +15,7 @@ public:
void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID){};
void tileRevealed(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 heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);
};

View File

@ -69,7 +69,7 @@ void GeniusAI::CGeniusAI::showGarrisonDialog( const CArmedInstance *up, const CG
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);
}

View File

@ -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<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 tileHidden(int3 pos){};
virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector<ui16> &skills, boost::function<void(ui32)> &callback);

View File

@ -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; i<creAnims[number]->framesInGroup(21)*getAnimSpeedMultiplier()-1; ++i)

View File

@ -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<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 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 tileHidden(const std::set<int3> &pos){};
virtual void tileRevealed(const std::set<int3> &pos){};

View File

@ -2409,7 +2409,7 @@ void CPlayerInterface::showComp(SComponent comp)
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;
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);
}
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);
@ -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<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);

View File

@ -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<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 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 tileHidden(const std::set<int3> &pos);
void tileRevealed(const std::set<int3> &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<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
bool moveHero(const CGHeroInstance *h, CPath path);

View File

@ -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";
}

View File

@ -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

View File

@ -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<andame; ++i)

View File

@ -46,14 +46,16 @@ public:
// Sound infos
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;
bool isDoubleWide() const; //returns true if unit is double wide on battlefield

View File

@ -3,6 +3,7 @@
#include <sstream>
#include <boost/assign/std/vector.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/bimap.hpp>
#include <SDL_mixer.h>
@ -23,19 +24,44 @@
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()
{
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<boost::bimap<soundBase::soundID, std::string>::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<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");
//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<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)
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<soundBase::soundID, Mix_Chunk *>(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<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;
else
return it->second;
@ -167,6 +197,15 @@ void CMusicHandler::initCreaturesSounds(std::vector<CCreature> &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<CCreature> &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<soundBase::soundID, Mix_Chunk *>::iterator it;
if (!sndh)
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;
}
// 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()]);
}

View File

@ -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<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:
CMusicHandler(): sndh(NULL) {};
CMusicHandler(): sndh(NULL), audioInit(false) {};
~CMusicHandler();
void initMusics();
void initCreaturesSounds(std::vector<CCreature> &creatures);
// 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);
// 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__

View File

@ -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