mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-06 09:09:40 +02:00
- some work on sound and music players:
-- Adventure map music will update with hero movement -- implemented battle intro sounds -- battle music tracks will be selected randomly each time - fixed #781
This commit is contained in:
@@ -1450,7 +1450,7 @@ void CAdvMapInt::select(const CArmedInstance *sel, bool centerView /*= true*/)
|
|||||||
assert(sel);
|
assert(sel);
|
||||||
LOCPLINT->cb->setSelection(sel);
|
LOCPLINT->cb->setSelection(sel);
|
||||||
selection = sel;
|
selection = sel;
|
||||||
CCS->musich->playMusic(CCS->musich->terrainMusics[LOCPLINT->cb->getTile(sel->visitablePos())->tertype]); //TODO: needs to be updated upon hero movement
|
CCS->musich->playMusic(CCS->musich->terrainMusics[LOCPLINT->cb->getTile(sel->visitablePos())->tertype]);
|
||||||
if(centerView)
|
if(centerView)
|
||||||
centerOn(sel);
|
centerOn(sel);
|
||||||
|
|
||||||
|
|||||||
@@ -1477,6 +1477,8 @@ CBattleInterface::~CBattleInterface()
|
|||||||
|
|
||||||
delete siegeH;
|
delete siegeH;
|
||||||
curInt->battleInt = NULL;
|
curInt->battleInt = NULL;
|
||||||
|
|
||||||
|
//TODO:restart music (can be AI or terrain). May be easier to backup and restore it instead of re-selecting
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBattleInterface::setPrintCellBorders(bool set)
|
void CBattleInterface::setPrintCellBorders(bool set)
|
||||||
@@ -2981,7 +2983,6 @@ void CBattleInterface::displayBattleFinished()
|
|||||||
CCS->curh->changeGraphic(0,0);
|
CCS->curh->changeGraphic(0,0);
|
||||||
|
|
||||||
SDL_Rect temp_rect = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
|
SDL_Rect temp_rect = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
|
||||||
CCS->musich->stopMusic();
|
|
||||||
resWindow = new CBattleResultWindow(*bresult, temp_rect, this);
|
resWindow = new CBattleResultWindow(*bresult, temp_rect, this);
|
||||||
GH.pushInt(resWindow);
|
GH.pushInt(resWindow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -951,7 +951,6 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos):
|
|||||||
CCastleInterface::~CCastleInterface()
|
CCastleInterface::~CCastleInterface()
|
||||||
{
|
{
|
||||||
LOCPLINT->castleInt = NULL;
|
LOCPLINT->castleInt = NULL;
|
||||||
CCS->musich->stopMusic(5000);
|
|
||||||
delete bicons;
|
delete bicons;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1420,10 +1419,12 @@ CHallInterface::CHallInterface(const CGTownInstance *Town):
|
|||||||
int buildingID = boxList[row][col][item];
|
int buildingID = boxList[row][col][item];
|
||||||
building = CGI->buildh->buildings[town->subID][buildingID];
|
building = CGI->buildh->buildings[town->subID][buildingID];
|
||||||
|
|
||||||
if (buildingID == 18 && vstd::contains(town->builtBuildings, town->town->hordeLvl[0]+37))
|
//Creature hordes - select unupgraded version if dwelling upgrade was not build yet
|
||||||
continue;
|
if (buildingID == 18 && !vstd::contains(town->builtBuildings, town->town->hordeLvl[0]+37))
|
||||||
if (buildingID == 24 && vstd::contains(town->builtBuildings, town->town->hordeLvl[1]+37))
|
break;
|
||||||
continue;
|
if (buildingID == 24 && !vstd::contains(town->builtBuildings, town->town->hordeLvl[1]+37))
|
||||||
|
break;
|
||||||
|
|
||||||
if(vstd::contains(town->builtBuildings,buildingID))
|
if(vstd::contains(town->builtBuildings,buildingID))
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -729,7 +729,6 @@ void startGame(StartInfo * options, CConnection *serv/* = NULL*/)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCS->musich->stopMusic();
|
|
||||||
client->connectionHandler = new boost::thread(&CClient::run, client);
|
client->connectionHandler = new boost::thread(&CClient::run, client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,13 @@ using namespace boost::assign;
|
|||||||
static boost::bimap<soundBase::soundID, std::string> sounds;
|
static boost::bimap<soundBase::soundID, std::string> sounds;
|
||||||
|
|
||||||
// Not pretty, but there's only one music handler object in the game.
|
// Not pretty, but there's only one music handler object in the game.
|
||||||
static void musicFinishedCallbackC(void) {
|
static void soundFinishedCallbackC(int channel)
|
||||||
|
{
|
||||||
|
CCS->soundh->soundFinishedCallback(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void musicFinishedCallbackC(void)
|
||||||
|
{
|
||||||
CCS->musich->musicFinishedCallback();
|
CCS->musich->musicFinishedCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +54,8 @@ void CAudioBase::init()
|
|||||||
|
|
||||||
void CAudioBase::release()
|
void CAudioBase::release()
|
||||||
{
|
{
|
||||||
if (initialized) {
|
if (initialized)
|
||||||
|
{
|
||||||
Mix_CloseAudio();
|
Mix_CloseAudio();
|
||||||
initialized = false;
|
initialized = false;
|
||||||
}
|
}
|
||||||
@@ -75,32 +82,41 @@ CSoundHandler::CSoundHandler()
|
|||||||
// Vectors for helper(s)
|
// Vectors for helper(s)
|
||||||
pickupSounds += soundBase::pickup01, soundBase::pickup02, soundBase::pickup03,
|
pickupSounds += soundBase::pickup01, soundBase::pickup02, soundBase::pickup03,
|
||||||
soundBase::pickup04, soundBase::pickup05, soundBase::pickup06, soundBase::pickup07;
|
soundBase::pickup04, soundBase::pickup05, soundBase::pickup06, soundBase::pickup07;
|
||||||
|
|
||||||
horseSounds += // must be the same order as terrains (see EterrainType);
|
horseSounds += // must be the same order as terrains (see EterrainType);
|
||||||
soundBase::horseDirt, soundBase::horseSand, soundBase::horseGrass,
|
soundBase::horseDirt, soundBase::horseSand, soundBase::horseGrass,
|
||||||
soundBase::horseSnow, soundBase::horseSwamp, soundBase::horseRough,
|
soundBase::horseSnow, soundBase::horseSwamp, soundBase::horseRough,
|
||||||
soundBase::horseSubterranean, soundBase::horseLava,
|
soundBase::horseSubterranean, soundBase::horseLava,
|
||||||
soundBase::horseWater, soundBase::horseRock;
|
soundBase::horseWater, soundBase::horseRock;
|
||||||
|
|
||||||
|
battleIntroSounds += soundBase::battle00, soundBase::battle01,
|
||||||
|
soundBase::battle02, soundBase::battle03, soundBase::battle04,
|
||||||
|
soundBase::battle05, soundBase::battle06, soundBase::battle07;
|
||||||
};
|
};
|
||||||
|
|
||||||
void CSoundHandler::init()
|
void CSoundHandler::init()
|
||||||
{
|
{
|
||||||
CAudioBase::init();
|
CAudioBase::init();
|
||||||
|
|
||||||
if (initialized) {
|
if (initialized)
|
||||||
|
{
|
||||||
// Load sounds
|
// Load sounds
|
||||||
sndh.add_file(std::string(DATA_DIR "/Data/Heroes3.snd"));
|
sndh.add_file(std::string(DATA_DIR "/Data/Heroes3.snd"));
|
||||||
sndh.add_file(std::string(DATA_DIR "/Data/Heroes3-cd2.snd"));
|
sndh.add_file(std::string(DATA_DIR "/Data/Heroes3-cd2.snd"));
|
||||||
sndh.add_file(std::string(DATA_DIR "/Data/H3ab_ahd.snd"));
|
sndh.add_file(std::string(DATA_DIR "/Data/H3ab_ahd.snd"));
|
||||||
|
Mix_ChannelFinished(soundFinishedCallbackC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSoundHandler::release()
|
void CSoundHandler::release()
|
||||||
{
|
{
|
||||||
if (initialized) {
|
if (initialized)
|
||||||
|
{
|
||||||
Mix_HaltChannel(-1);
|
Mix_HaltChannel(-1);
|
||||||
|
|
||||||
std::map<soundBase::soundID, Mix_Chunk *>::iterator it;
|
std::map<soundBase::soundID, Mix_Chunk *>::iterator it;
|
||||||
for (it=soundChunks.begin(); it != soundChunks.end(); it++) {
|
for (it=soundChunks.begin(); it != soundChunks.end(); it++)
|
||||||
|
{
|
||||||
if (it->second)
|
if (it->second)
|
||||||
Mix_FreeChunk(it->second);
|
Mix_FreeChunk(it->second);
|
||||||
}
|
}
|
||||||
@@ -128,7 +144,8 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(soundBase::soundID soundID)
|
|||||||
Mix_Chunk *chunk;
|
Mix_Chunk *chunk;
|
||||||
chunk = Mix_LoadWAV_RW(ops, 1); // will free ops
|
chunk = Mix_LoadWAV_RW(ops, 1); // will free ops
|
||||||
|
|
||||||
if (!chunk) {
|
if (!chunk)
|
||||||
|
{
|
||||||
tlog1 << "Unable to mix sound" << it->second << "(" << Mix_GetError() << ")" << std::endl;
|
tlog1 << "Unable to mix sound" << it->second << "(" << Mix_GetError() << ")" << std::endl;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -268,8 +285,11 @@ int CSoundHandler::playSound(soundBase::soundID soundID, int repeats)
|
|||||||
channel = Mix_PlayChannel(-1, chunk, repeats);
|
channel = Mix_PlayChannel(-1, chunk, repeats);
|
||||||
if (channel == -1)
|
if (channel == -1)
|
||||||
tlog1 << "Unable to play sound file " << soundID << " , error " << Mix_GetError() << std::endl;
|
tlog1 << "Unable to play sound file " << soundID << " , error " << Mix_GetError() << std::endl;
|
||||||
|
else
|
||||||
} else {
|
callbacks[channel];//insert empty callback
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
channel = -1;
|
channel = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,7 +317,32 @@ void CSoundHandler::setVolume(unsigned int percent)
|
|||||||
Mix_Volume(-1, (MIX_MAX_VOLUME * volume)/100);
|
Mix_Volume(-1, (MIX_MAX_VOLUME * volume)/100);
|
||||||
}
|
}
|
||||||
|
|
||||||
CMusicHandler::CMusicHandler(): currentMusic(NULL), nextMusic(NULL)
|
void CSoundHandler::setCallback(int channel, boost::function<void()> function)
|
||||||
|
{
|
||||||
|
std::map<int, boost::function<void()> >::iterator iter;
|
||||||
|
iter = callbacks.find(channel);
|
||||||
|
|
||||||
|
//channel not found. It may have finished so fire callback now
|
||||||
|
if(iter == callbacks.end())
|
||||||
|
function();
|
||||||
|
else
|
||||||
|
iter->second = function;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSoundHandler::soundFinishedCallback(int channel)
|
||||||
|
{
|
||||||
|
std::map<int, boost::function<void()> >::iterator iter;
|
||||||
|
iter = callbacks.find(channel);
|
||||||
|
|
||||||
|
assert(iter != callbacks.end());
|
||||||
|
|
||||||
|
if (iter->second)
|
||||||
|
iter->second();
|
||||||
|
|
||||||
|
callbacks.erase(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMusicHandler::CMusicHandler()
|
||||||
{
|
{
|
||||||
// Map music IDs
|
// Map music IDs
|
||||||
#define VCMI_MUSIC_ID(x) ( musicBase::x ,
|
#define VCMI_MUSIC_ID(x) ( musicBase::x ,
|
||||||
@@ -314,7 +359,7 @@ CMusicHandler::CMusicHandler(): currentMusic(NULL), nextMusic(NULL)
|
|||||||
townMusics += musicBase::castleTown, musicBase::rampartTown,
|
townMusics += musicBase::castleTown, musicBase::rampartTown,
|
||||||
musicBase::towerTown, musicBase::infernoTown,
|
musicBase::towerTown, musicBase::infernoTown,
|
||||||
musicBase::necroTown, musicBase::dungeonTown,
|
musicBase::necroTown, musicBase::dungeonTown,
|
||||||
musicBase::strongHoldTown, musicBase::fortressTown,
|
musicBase::strongHoldTown, musicBase::fortressTown,
|
||||||
musicBase::elemTown;
|
musicBase::elemTown;
|
||||||
|
|
||||||
terrainMusics += musicBase::dirt, musicBase::sand, musicBase::grass,
|
terrainMusics += musicBase::dirt, musicBase::sand, musicBase::grass,
|
||||||
@@ -332,21 +377,14 @@ void CMusicHandler::init()
|
|||||||
|
|
||||||
void CMusicHandler::release()
|
void CMusicHandler::release()
|
||||||
{
|
{
|
||||||
if (initialized) {
|
if (initialized)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock guard(musicMutex);
|
||||||
|
|
||||||
Mix_HookMusicFinished(NULL);
|
Mix_HookMusicFinished(NULL);
|
||||||
|
|
||||||
musicMutex.lock();
|
current.reset();
|
||||||
|
next.reset();
|
||||||
if (currentMusic)
|
|
||||||
{
|
|
||||||
Mix_HaltMusic();
|
|
||||||
Mix_FreeMusic(currentMusic);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextMusic)
|
|
||||||
Mix_FreeMusic(nextMusic);
|
|
||||||
|
|
||||||
musicMutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CAudioBase::release();
|
CAudioBase::release();
|
||||||
@@ -355,43 +393,40 @@ void CMusicHandler::release()
|
|||||||
// Plays a music
|
// Plays a music
|
||||||
// loop: -1 always repeats, 0=do not play, 1+=number of loops
|
// loop: -1 always repeats, 0=do not play, 1+=number of loops
|
||||||
void CMusicHandler::playMusic(musicBase::musicID musicID, int loop)
|
void CMusicHandler::playMusic(musicBase::musicID musicID, int loop)
|
||||||
|
{
|
||||||
|
if (current.get() != NULL && *current == musicID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
queueNext(new MusicEntry(this, musicID, loop));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper. Randomly plays tracks from music_vec
|
||||||
|
void CMusicHandler::playMusicFromSet(std::vector<musicBase::musicID> &music_vec, int loop)
|
||||||
|
{
|
||||||
|
if (current.get() != NULL && *current == music_vec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
queueNext(new MusicEntry(this, music_vec, loop));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMusicHandler::queueNext(MusicEntry *queued)
|
||||||
{
|
{
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string filename = DATA_DIR "/Mp3/";
|
boost::mutex::scoped_lock guard(musicMutex);
|
||||||
filename += musics[musicID];
|
|
||||||
|
|
||||||
musicMutex.lock();
|
next.reset(queued);
|
||||||
|
|
||||||
if (nextMusic)
|
if (current.get() != NULL)
|
||||||
{
|
{
|
||||||
// There's already a music queued, so remove it
|
current->stop(1000);
|
||||||
Mix_FreeMusic(nextMusic);
|
|
||||||
nextMusic = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentMusic)
|
|
||||||
{
|
|
||||||
// A music is already playing. Stop it and the callback will
|
|
||||||
// start the new one
|
|
||||||
nextMusic = LoadMUS(filename.c_str());
|
|
||||||
nextMusicLoop = loop;
|
|
||||||
Mix_FadeOutMusic(1000);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
currentMusic = LoadMUS(filename.c_str());
|
current = next;
|
||||||
PlayMusic(currentMusic,loop);
|
current->play();
|
||||||
}
|
}
|
||||||
|
|
||||||
musicMutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper. Randomly select a music from an array and play it
|
|
||||||
void CMusicHandler::playMusicFromSet(std::vector<musicBase::musicID> &music_vec, int loop)
|
|
||||||
{
|
|
||||||
playMusic(music_vec[rand() % music_vec.size()], loop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop and free the current music
|
// Stop and free the current music
|
||||||
@@ -400,14 +435,12 @@ void CMusicHandler::stopMusic(int fade_ms)
|
|||||||
if (!initialized)
|
if (!initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
musicMutex.lock();
|
boost::mutex::scoped_lock guard(musicMutex);
|
||||||
|
|
||||||
if (currentMusic)
|
if (current.get() != NULL)
|
||||||
{
|
current->stop(fade_ms);
|
||||||
Mix_FadeOutMusic(fade_ms);
|
next.reset();
|
||||||
}
|
|
||||||
|
|
||||||
musicMutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the music volume, from 0 (mute) to 100
|
// Sets the music volume, from 0 (mute) to 100
|
||||||
@@ -422,42 +455,100 @@ void CMusicHandler::setVolume(unsigned int percent)
|
|||||||
// Called by SDL when a music finished.
|
// Called by SDL when a music finished.
|
||||||
void CMusicHandler::musicFinishedCallback(void)
|
void CMusicHandler::musicFinishedCallback(void)
|
||||||
{
|
{
|
||||||
musicMutex.lock();
|
boost::mutex::scoped_lock guard(musicMutex);
|
||||||
|
|
||||||
if (currentMusic)
|
if (current.get() != NULL)
|
||||||
{
|
{
|
||||||
Mix_FreeMusic(currentMusic);
|
//return if current music still not finished
|
||||||
currentMusic = NULL;
|
if (current->play())
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
current.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextMusic)
|
if (current.get() == NULL && next.get() != NULL)
|
||||||
{
|
{
|
||||||
currentMusic = nextMusic;
|
current = next;
|
||||||
nextMusic = NULL;
|
current->play();
|
||||||
PlayMusic(currentMusic,nextMusicLoop);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
musicMutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mix_Music * CMusicHandler::LoadMUS(const char *file)
|
MusicEntry::MusicEntry(CMusicHandler *_owner, musicBase::musicID _musicID, int _loopCount):
|
||||||
|
owner(_owner),
|
||||||
|
music(NULL),
|
||||||
|
loopCount(_loopCount)
|
||||||
{
|
{
|
||||||
Mix_Music *ret = Mix_LoadMUS(file);
|
load(_musicID);
|
||||||
if(!ret) //load music and check for error
|
}
|
||||||
tlog1 << "Unable to load music file (" << file <<"). Error: " << Mix_GetError() << std::endl;
|
|
||||||
|
MusicEntry::MusicEntry(CMusicHandler *_owner, std::vector<musicBase::musicID> &_musicVec, int _loopCount):
|
||||||
|
currentID(musicBase::music_todo),
|
||||||
|
owner(_owner),
|
||||||
|
music(NULL),
|
||||||
|
loopCount(_loopCount),
|
||||||
|
musicVec(_musicVec)
|
||||||
|
{
|
||||||
|
//In this case music will be loaded only on playing - no need to call load() here
|
||||||
|
}
|
||||||
|
|
||||||
|
MusicEntry::~MusicEntry()
|
||||||
|
{
|
||||||
|
tlog5<<"Del-ing music file "<<filename<<"\n";
|
||||||
|
if (music)
|
||||||
|
Mix_FreeMusic(music);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicEntry::load(musicBase::musicID ID)
|
||||||
|
{
|
||||||
|
currentID = ID;
|
||||||
|
filename = DATA_DIR "/Mp3/";
|
||||||
|
filename += owner->musics[ID];
|
||||||
|
|
||||||
|
tlog5<<"Loading music file "<<filename<<"\n";
|
||||||
|
if (music)
|
||||||
|
Mix_FreeMusic(music);
|
||||||
|
|
||||||
|
music = Mix_LoadMUS(filename.c_str());
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
//The assertion will fail if old MSVC libraries pack .dll is used
|
//The assertion will fail if old MSVC libraries pack .dll is used
|
||||||
assert(Mix_GetMusicType(ret) == MUS_MP3_MAD);
|
assert(Mix_GetMusicType(music) == MUS_MP3_MAD);
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CMusicHandler::PlayMusic(Mix_Music *music, int loops)
|
bool MusicEntry::play()
|
||||||
{
|
{
|
||||||
int ret = Mix_PlayMusic(music, loops);
|
tlog5<<"Playing music file "<<filename<<"\n";
|
||||||
if(ret == -1)
|
if (loopCount == 0)
|
||||||
tlog1 << "Unable to play music (" << Mix_GetError() << ")" << std::endl;
|
return false;
|
||||||
|
|
||||||
return ret;
|
if (loopCount > 0)
|
||||||
|
loopCount--;
|
||||||
|
|
||||||
|
if (!musicVec.empty())
|
||||||
|
load(musicVec.at(rand() % musicVec.size()));
|
||||||
|
|
||||||
|
if(Mix_PlayMusic(music, 1) == -1)
|
||||||
|
{
|
||||||
|
tlog1 << "Unable to play music (" << Mix_GetError() << ")" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MusicEntry::stop(int fade_ms)
|
||||||
|
{
|
||||||
|
tlog5<<"Stoping music file "<<filename<<"\n";
|
||||||
|
loopCount = 0;
|
||||||
|
Mix_FadeOutMusic(fade_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicEntry::operator == (musicBase::musicID _musicID) const
|
||||||
|
{
|
||||||
|
return musicVec.empty() && currentID == _musicID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MusicEntry::operator == (std::vector<musicBase::musicID> &_musicVec) const
|
||||||
|
{
|
||||||
|
return musicVec == _musicVec;
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
#define __CMUSICHANDLER_H__
|
#define __CMUSICHANDLER_H__
|
||||||
|
|
||||||
#include <boost/thread/mutex.hpp>
|
#include <boost/thread/mutex.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "CSoundBase.h"
|
#include "CSoundBase.h"
|
||||||
#include "CMusicBase.h"
|
#include "CMusicBase.h"
|
||||||
@@ -73,6 +76,10 @@ private:
|
|||||||
|
|
||||||
Mix_Chunk *GetSoundChunk(soundBase::soundID soundID);
|
Mix_Chunk *GetSoundChunk(soundBase::soundID soundID);
|
||||||
|
|
||||||
|
//have entry for every currently active channel
|
||||||
|
//boost::function will be NULL if callback was not set
|
||||||
|
std::map<int, boost::function<void()> > callbacks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CSoundHandler();
|
CSoundHandler();
|
||||||
|
|
||||||
@@ -87,29 +94,60 @@ public:
|
|||||||
int playSound(soundBase::soundID soundID, int repeats=0);
|
int playSound(soundBase::soundID soundID, int repeats=0);
|
||||||
int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
|
int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
|
||||||
void stopSound(int handler);
|
void stopSound(int handler);
|
||||||
|
|
||||||
|
void setCallback(int channel, boost::function<void()> function);
|
||||||
|
void soundFinishedCallback(int channel);
|
||||||
|
|
||||||
std::vector <struct CreaturesBattleSounds> CBattleSounds;
|
std::vector <struct CreaturesBattleSounds> CBattleSounds;
|
||||||
std::map<const CSpell*, soundBase::soundID> spellSounds;
|
std::map<const CSpell*, soundBase::soundID> spellSounds;
|
||||||
|
|
||||||
// Sets
|
// Sets
|
||||||
std::vector<soundBase::soundID> pickupSounds;
|
std::vector<soundBase::soundID> pickupSounds;
|
||||||
std::vector<soundBase::soundID> horseSounds;
|
std::vector<soundBase::soundID> horseSounds;
|
||||||
|
std::vector<soundBase::soundID> battleIntroSounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper
|
// Helper
|
||||||
#define battle_sound(creature,what_sound) CCS->soundh->CBattleSounds[(creature)->idNumber].what_sound
|
#define battle_sound(creature,what_sound) CCS->soundh->CBattleSounds[(creature)->idNumber].what_sound
|
||||||
|
|
||||||
|
class CMusicHandler;
|
||||||
|
|
||||||
|
//Class for handling one music file
|
||||||
|
class MusicEntry
|
||||||
|
{
|
||||||
|
std::string filename; //used only for debugging and console messages
|
||||||
|
musicBase::musicID currentID;
|
||||||
|
CMusicHandler *owner;
|
||||||
|
Mix_Music *music;
|
||||||
|
int loopCount;
|
||||||
|
//if not empty - vector from which music will be randomly selected
|
||||||
|
std::vector<musicBase::musicID> musicVec;
|
||||||
|
|
||||||
|
void load(musicBase::musicID);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool operator == (musicBase::musicID musicID) const;
|
||||||
|
bool operator == (std::vector<musicBase::musicID> &_musicVec) const;
|
||||||
|
|
||||||
|
MusicEntry(CMusicHandler *owner, musicBase::musicID musicID, int _loopCount);
|
||||||
|
MusicEntry(CMusicHandler *owner, std::vector<musicBase::musicID> &_musicVec, int _loopCount);
|
||||||
|
~MusicEntry();
|
||||||
|
|
||||||
|
bool play();
|
||||||
|
void stop(int fade_ms=0);
|
||||||
|
};
|
||||||
|
|
||||||
class CMusicHandler: public CAudioBase
|
class CMusicHandler: public CAudioBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// Because we use the SDL music callback, our music variables must
|
// Because we use the SDL music callback, our music variables must
|
||||||
// be protected
|
// be protected
|
||||||
boost::mutex musicMutex;
|
boost::mutex musicMutex;
|
||||||
Mix_Music *currentMusic;
|
|
||||||
Mix_Music *nextMusic;
|
|
||||||
int nextMusicLoop;
|
|
||||||
|
|
||||||
Mix_Music * LoadMUS(const char *file); //calls Mix_LoadMUS and checks for errors
|
std::auto_ptr<MusicEntry> current;
|
||||||
int PlayMusic(Mix_Music *music, int loops); //calls Mix_PlayMusic and checks for errors
|
std::auto_ptr<MusicEntry> next;
|
||||||
|
|
||||||
|
void queueNext(MusicEntry *queued);
|
||||||
public:
|
public:
|
||||||
CMusicHandler();
|
CMusicHandler();
|
||||||
|
|
||||||
|
|||||||
@@ -257,6 +257,8 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
|||||||
|
|
||||||
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
|
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
|
||||||
{
|
{
|
||||||
|
//We may need to change music - select new track, music handler will change it if needed
|
||||||
|
CCS->musich->playMusic(CCS->musich->terrainMusics[LOCPLINT->cb->getTile(ho->visitablePos())->tertype]);
|
||||||
if(details.result == TryMoveHero::TELEPORTATION || details.start == details.end)
|
if(details.result == TryMoveHero::TELEPORTATION || details.start == details.end)
|
||||||
{
|
{
|
||||||
if(adventureInt->terrain.currentPath)
|
if(adventureInt->terrain.currentPath)
|
||||||
@@ -569,7 +571,11 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
|
|||||||
SDL_Delay(20);
|
SDL_Delay(20);
|
||||||
|
|
||||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||||
CCS->musich->playMusicFromSet(CCS->musich->battleMusics, -1);
|
CCS->musich->stopMusic();
|
||||||
|
|
||||||
|
int channel = CCS->soundh->playSoundFromSet(CCS->soundh->battleIntroSounds);
|
||||||
|
CCS->soundh->setCallback(channel, boost::bind(&CMusicHandler::playMusicFromSet, CCS->musich, CCS->musich->battleMusics, -1));
|
||||||
|
|
||||||
GH.pushInt(battleInt);
|
GH.pushInt(battleInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2051,13 +2057,19 @@ void CPlayerInterface::acceptTurn()
|
|||||||
|
|
||||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||||
|
|
||||||
/* TODO: This isn't quite right. First day in game should play
|
//Select sound for day start
|
||||||
* NEWDAY. And we don't play NEWMONTH. */
|
int totalDays = cb->getDate();
|
||||||
int day = cb->getDate(1);
|
int day = cb->getDate(1);
|
||||||
if (day != 1)
|
int week = cb->getDate(2);
|
||||||
|
|
||||||
|
if (totalDays == 1)
|
||||||
CCS->soundh->playSound(soundBase::newDay);
|
CCS->soundh->playSound(soundBase::newDay);
|
||||||
else
|
else if (day != 1)
|
||||||
|
CCS->soundh->playSound(soundBase::newDay);
|
||||||
|
else if (week != 1)
|
||||||
CCS->soundh->playSound(soundBase::newWeek);
|
CCS->soundh->playSound(soundBase::newWeek);
|
||||||
|
else
|
||||||
|
CCS->soundh->playSound(soundBase::newMonth);
|
||||||
|
|
||||||
adventureInt->infoBar.newDay(day);
|
adventureInt->infoBar.newDay(day);
|
||||||
|
|
||||||
|
|||||||
@@ -478,7 +478,7 @@ void CClient::serialize( Handler &h, const int version )
|
|||||||
{
|
{
|
||||||
if(pid == 255)
|
if(pid == 255)
|
||||||
{
|
{
|
||||||
CBattleCallback * cbc = new CBattleCallback(gs, pid, this);
|
//CBattleCallback * cbc = new CBattleCallback(gs, pid, this);//FIXME: unused?
|
||||||
CBattleGameInterface *cbgi = CDynLibHandler::getNewBattleAI(dllname);
|
CBattleGameInterface *cbgi = CDynLibHandler::getNewBattleAI(dllname);
|
||||||
battleints[pid] = cbgi;
|
battleints[pid] = cbgi;
|
||||||
cbgi->init(cb);
|
cbgi->init(cb);
|
||||||
|
|||||||
Reference in New Issue
Block a user