mirror of
https://github.com/galaxyhaxz/devilution
synced 2025-02-23 12:44:54 +00:00
432 lines
7.1 KiB
C++
432 lines
7.1 KiB
C++
|
#include "diablo.h"
|
||
|
#include "../3rdParty/Storm/Source/storm.h"
|
||
|
|
||
|
int sfxdelay; // weak
|
||
|
int sfxdnum;
|
||
|
HANDLE sghStream;
|
||
|
TSFX *sgpStreamSFX;
|
||
|
|
||
|
const char monster_action_sounds[] = { 'a', 'h', 'd', 's' }; // idb
|
||
|
|
||
|
/* data */
|
||
|
|
||
|
TSFX sgSFX[NUM_SFX] =
|
||
|
{
|
||
|
#include "Data/xl_sfx.cpp"
|
||
|
};
|
||
|
|
||
|
BOOL effect_is_playing(int nSFX)
|
||
|
{
|
||
|
TSFX *pSFX;
|
||
|
|
||
|
/// ASSERT: assert(nSFX < NUM_SFX);
|
||
|
pSFX = &sgSFX[nSFX];
|
||
|
|
||
|
if(pSFX->pSnd != NULL) {
|
||
|
return snd_playing(pSFX->pSnd);
|
||
|
}
|
||
|
if(pSFX->bFlags & 1) {
|
||
|
return pSFX == sgpStreamSFX;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void stream_stop()
|
||
|
{
|
||
|
if(sghStream != NULL) {
|
||
|
SFileDdaEnd(sghStream);
|
||
|
SFileCloseFile(sghStream);
|
||
|
sghStream = NULL;
|
||
|
sgpStreamSFX = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void stream_play(TSFX *pSFX, long lVolume, long lPan)
|
||
|
{
|
||
|
BOOL bSuccess;
|
||
|
|
||
|
/// ASSERT: assert(pSFX);
|
||
|
/// ASSERT: assert(pSFX->bFlags & sfx_STREAM);
|
||
|
|
||
|
stream_stop();
|
||
|
|
||
|
lVolume += sound_get_or_set_sound_volume(1);
|
||
|
if(lVolume < VOLUME_MIN) {
|
||
|
return;
|
||
|
}
|
||
|
if(lVolume > VOLUME_MAX) {
|
||
|
lVolume = VOLUME_MAX;
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
SFileEnableDirectAccess(FALSE);
|
||
|
#endif
|
||
|
bSuccess = SFileOpenFile(pSFX->pszName, &sghStream);
|
||
|
#ifdef _DEBUG
|
||
|
SFileEnableDirectAccess(TRUE);
|
||
|
#endif
|
||
|
|
||
|
if(!bSuccess) {
|
||
|
sghStream = NULL;
|
||
|
return;
|
||
|
}
|
||
|
if(!SFileDdaBeginEx(sghStream, 0x40000, 0, 0, lVolume, lPan, 0)) {
|
||
|
stream_stop();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
sgpStreamSFX = pSFX;
|
||
|
}
|
||
|
|
||
|
static void stream_update()
|
||
|
{
|
||
|
DWORD dwStart, dwEnd;
|
||
|
|
||
|
if(sghStream == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
if(!SFileDdaGetPos(sghStream, &dwStart, &dwEnd)) {
|
||
|
return;
|
||
|
}
|
||
|
if(dwStart < dwEnd) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
stream_stop();
|
||
|
}
|
||
|
|
||
|
static void sfx_stop()
|
||
|
{
|
||
|
int i;
|
||
|
TSFX *pSFX;
|
||
|
|
||
|
pSFX = sgSFX;
|
||
|
i = NUM_SFX;
|
||
|
while(i--) {
|
||
|
if(pSFX->pSnd != NULL) {
|
||
|
snd_stop_snd(pSFX->pSnd);
|
||
|
}
|
||
|
pSFX++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void InitMonsterSND(int monst)
|
||
|
{
|
||
|
int mtype, mode, nr;
|
||
|
TSnd *pSnd;
|
||
|
char *pszFile;
|
||
|
char szName[MAX_PATH];
|
||
|
|
||
|
if(!gbSndInited) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mtype = Monsters[monst].mtype;
|
||
|
|
||
|
for(mode = 0; mode < 4; mode++) {
|
||
|
if(monster_action_sounds[mode] == 's' && !monsterdata[mtype].snd_special) {
|
||
|
continue;
|
||
|
}
|
||
|
for(nr = 0; nr < 2; nr++) {
|
||
|
sprintf(szName, monsterdata[mtype].sndfile, monster_action_sounds[mode], nr + 1);
|
||
|
pszFile = (char *)DiabloAllocPtr(strlen(szName) + 1);
|
||
|
strcpy(pszFile, szName);
|
||
|
pSnd = sound_file_load(pszFile);
|
||
|
Monsters[monst].Snds[mode][nr] = pSnd;
|
||
|
if(pSnd == NULL) {
|
||
|
MemFreeDbg(pszFile);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void FreeMonsterSnd()
|
||
|
{
|
||
|
int mi, mode, nr;
|
||
|
TSnd *pSnd;
|
||
|
char *pszFile;
|
||
|
|
||
|
for(mi = 0; mi < nummtypes; mi++) {
|
||
|
for(mode = 0; mode < 4; mode++) {
|
||
|
for(nr = 0; nr < 2; nr++) {
|
||
|
pSnd = Monsters[mi].Snds[mode][nr];
|
||
|
if(pSnd == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
Monsters[mi].Snds[mode][nr] = NULL;
|
||
|
pszFile = pSnd->sound_path;
|
||
|
pSnd->sound_path = NULL;
|
||
|
sound_file_cleanup(pSnd);
|
||
|
MemFreeDbg(pszFile);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static BOOL calc_snd_position(int x, int y, long *plVolume, long *plPan)
|
||
|
{
|
||
|
long volume, pan;
|
||
|
|
||
|
x -= plr[myplr].WorldX;
|
||
|
y -= plr[myplr].WorldY;
|
||
|
|
||
|
pan = x - y;
|
||
|
*plPan = pan << 8;
|
||
|
if(abs(*plPan) > 6400) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
volume = abs(x) > abs(y) ? abs(x) : abs(y);
|
||
|
*plVolume = volume << 6;
|
||
|
if(*plVolume >= 6400) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*plVolume = -*plVolume;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void PlaySFX_priv(TSFX *pSFX, BOOL loc, int x, int y)
|
||
|
{
|
||
|
long lPan, lVolume;
|
||
|
|
||
|
if(plr[myplr].pLvlLoad != 0 && gbMaxPlayers != 1) {
|
||
|
return;
|
||
|
}
|
||
|
if(!gbSndInited || !gbSoundOn) {
|
||
|
return;
|
||
|
}
|
||
|
if(gbBufferMsgs != 0) {
|
||
|
return;
|
||
|
}
|
||
|
if(!(pSFX->bFlags & 3) && pSFX->pSnd != NULL && snd_playing(pSFX->pSnd)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
lPan = 0;
|
||
|
lVolume = 0;
|
||
|
if(loc && !calc_snd_position(x, y, &lVolume, &lPan)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(pSFX->bFlags & 1) {
|
||
|
stream_play(pSFX, lVolume, lPan);
|
||
|
} else {
|
||
|
if(pSFX->pSnd == NULL) {
|
||
|
pSFX->pSnd = sound_file_load(pSFX->pszName);
|
||
|
}
|
||
|
if(pSFX->pSnd != NULL) {
|
||
|
snd_play_snd(pSFX->pSnd, lVolume, lPan);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void PlayEffect(int i, int mode)
|
||
|
{
|
||
|
int mi, nr;
|
||
|
long lPan, lVolume;
|
||
|
TSnd *pSnd;
|
||
|
|
||
|
if(plr[myplr].pLvlLoad != 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
nr = random(164, 2);
|
||
|
|
||
|
if(!gbSndInited || !gbSoundOn) {
|
||
|
return;
|
||
|
}
|
||
|
if(gbBufferMsgs != 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mi = monster[i]._mMTidx;
|
||
|
pSnd = Monsters[mi].Snds[mode][nr];
|
||
|
if(pSnd == NULL) {
|
||
|
#ifdef _DEBUG
|
||
|
app_fatal("Monster sound problem\n:%s playing %i", Monsters[mi].MData->mName, mode);
|
||
|
#endif
|
||
|
return;
|
||
|
}
|
||
|
if(snd_playing(pSnd)) {
|
||
|
return;
|
||
|
}
|
||
|
if(!calc_snd_position(monster[i]._mx, monster[i]._my, &lVolume, &lPan)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
snd_play_snd(pSnd, lVolume, lPan);
|
||
|
}
|
||
|
|
||
|
static int RndSFX(int psfx)
|
||
|
{
|
||
|
int nRand;
|
||
|
|
||
|
if(psfx == PS_WARR69) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == PS_WARR14) {
|
||
|
nRand = 3;
|
||
|
} else if(psfx == PS_WARR15) {
|
||
|
nRand = 3;
|
||
|
} else if(psfx == PS_WARR16) {
|
||
|
nRand = 3;
|
||
|
} else if(psfx == PS_MAGE69) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == PS_ROGUE69) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == PS_SWING) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == LS_ACID) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == IS_FMAG) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == IS_MAGIC) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == IS_BHIT) {
|
||
|
nRand = 2;
|
||
|
} else if(psfx == PS_WARR2) {
|
||
|
nRand = 3;
|
||
|
} else {
|
||
|
return psfx;
|
||
|
}
|
||
|
|
||
|
return random(165, nRand) + psfx;
|
||
|
}
|
||
|
|
||
|
void PlaySFX(int psfx)
|
||
|
{
|
||
|
psfx = RndSFX(psfx);
|
||
|
/// ASSERT: assert(psfx < NUM_SFX);
|
||
|
PlaySFX_priv(&sgSFX[psfx], FALSE, 0, 0);
|
||
|
}
|
||
|
|
||
|
void PlaySfxLoc(int psfx, int x, int y)
|
||
|
{
|
||
|
psfx = RndSFX(psfx);
|
||
|
/// ASSERT: assert(psfx < NUM_SFX);
|
||
|
|
||
|
if(psfx >= PS_WALK1 && psfx <= PS_WALK4 && sgSFX[psfx].pSnd != NULL) {
|
||
|
sgSFX[psfx].pSnd->start_tc = 0;
|
||
|
}
|
||
|
|
||
|
PlaySFX_priv(&sgSFX[psfx], TRUE, x, y);
|
||
|
}
|
||
|
|
||
|
void sound_stop()
|
||
|
{
|
||
|
int mi, mode, nr;
|
||
|
|
||
|
snd_update(TRUE);
|
||
|
stream_stop();
|
||
|
sfx_stop();
|
||
|
|
||
|
for(mi = 0; mi < nummtypes; mi++) {
|
||
|
for(mode = 0; mode < 4; mode++) {
|
||
|
for(nr = 0; nr < 2; nr++) {
|
||
|
snd_stop_snd(Monsters[mi].Snds[mode][nr]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void sound_update()
|
||
|
{
|
||
|
if(!gbSndInited) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
snd_update(FALSE);
|
||
|
stream_update();
|
||
|
}
|
||
|
|
||
|
void effects_cleanup_sfx()
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
sound_stop();
|
||
|
|
||
|
for(i = 0; (DWORD)i < NUM_SFX; i++) {
|
||
|
if(sgSFX[i].pSnd == NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
sound_file_cleanup(sgSFX[i].pSnd);
|
||
|
sgSFX[i].pSnd = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void priv_sound_init(BYTE bLoadMask)
|
||
|
{
|
||
|
BYTE pc;
|
||
|
int i;
|
||
|
|
||
|
if(!gbSndInited) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pc = bLoadMask & (0x20 | 0x10 | 0x40);
|
||
|
bLoadMask ^= pc;
|
||
|
|
||
|
for(i = 0; (DWORD)i < NUM_SFX; i++) {
|
||
|
if(sgSFX[i].pSnd != NULL) {
|
||
|
continue;
|
||
|
}
|
||
|
if(sgSFX[i].bFlags & 1) {
|
||
|
continue;
|
||
|
}
|
||
|
if(bLoadMask != 0 && !(sgSFX[i].bFlags & bLoadMask)) {
|
||
|
continue;
|
||
|
}
|
||
|
if(sgSFX[i].bFlags & (0x20 | 0x10 | 0x40) && !(sgSFX[i].bFlags & pc)) {
|
||
|
continue;
|
||
|
}
|
||
|
sgSFX[i].pSnd = sound_file_load(sgSFX[i].pszName);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void sound_init()
|
||
|
{
|
||
|
BYTE bLoadMask;
|
||
|
|
||
|
bLoadMask = 0;
|
||
|
|
||
|
if(gbMaxPlayers > 1) {
|
||
|
bLoadMask = 0x20 | 0x10 | 0x40;
|
||
|
} else {
|
||
|
if(plr[myplr]._pClass == PC_WARRIOR) {
|
||
|
bLoadMask = 0x20;
|
||
|
} else if(plr[myplr]._pClass == PC_ROGUE) {
|
||
|
bLoadMask = 0x10;
|
||
|
} else if(plr[myplr]._pClass == PC_SORCERER) {
|
||
|
bLoadMask = 0x40;
|
||
|
} else {
|
||
|
app_fatal("effects:1");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
priv_sound_init(bLoadMask);
|
||
|
}
|
||
|
|
||
|
void ui_sound_init()
|
||
|
{
|
||
|
priv_sound_init(4);
|
||
|
}
|
||
|
|
||
|
void __stdcall effects_play_sound(const char *pszFile)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if(!gbSndInited || !gbSoundOn) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for(i = 0; (DWORD)i < NUM_SFX; i++) {
|
||
|
if(_strcmpi(sgSFX[i].pszName, pszFile) == 0 && sgSFX[i].pSnd != NULL) {
|
||
|
if(!snd_playing(sgSFX[i].pSnd)) {
|
||
|
snd_play_snd(sgSFX[i].pSnd, 0, 0);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|