2019-11-20 16:21:32 +00:00
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
/*
|
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
|
Copyright (C) 2019 Nuke.YKT, sirlemonhead
|
|
|
|
|
This file is part of PCExhumed.
|
|
|
|
|
PCExhumed is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*/
|
|
|
|
|
//-------------------------------------------------------------------------
|
2019-11-22 23:11:37 +00:00
|
|
|
|
#include "ns.h"
|
2019-09-18 16:11:06 +00:00
|
|
|
|
#include "compat.h"
|
|
|
|
|
#include "baselayer.h"
|
|
|
|
|
#include "build.h"
|
|
|
|
|
#include "engine.h"
|
|
|
|
|
#include "exhumed.h"
|
2019-08-26 03:59:14 +00:00
|
|
|
|
#include "sound.h"
|
|
|
|
|
#include "init.h"
|
2019-09-18 16:11:06 +00:00
|
|
|
|
#include "object.h"
|
|
|
|
|
#include "player.h"
|
|
|
|
|
#include "random.h"
|
|
|
|
|
#include "snake.h"
|
|
|
|
|
#include "trigdat.h"
|
|
|
|
|
#include "sequence.h"
|
2019-11-24 20:32:07 +00:00
|
|
|
|
#include "cd.h"
|
2019-12-25 22:37:16 +00:00
|
|
|
|
#include "sound/s_soundinternal.h"
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-11-22 23:11:37 +00:00
|
|
|
|
BEGIN_PS_NS
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
const char *SoundFiles[kMaxSoundFiles] =
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
|
|
|
|
"spl_big",
|
|
|
|
|
"spl_smal",
|
|
|
|
|
"bubble_l",
|
|
|
|
|
"grn_drop",
|
|
|
|
|
"p_click",
|
|
|
|
|
"grn_roll",
|
|
|
|
|
"cosprite",
|
|
|
|
|
"m_chant0",
|
|
|
|
|
"anu_icu",
|
|
|
|
|
"item_reg",
|
|
|
|
|
"item_spe", // 10
|
|
|
|
|
"item_key",
|
|
|
|
|
"torch_on", // 12
|
|
|
|
|
"jon_bnst",
|
|
|
|
|
"jon_gasp",
|
|
|
|
|
"jon_land",
|
|
|
|
|
"jon_gags",
|
|
|
|
|
"jon_fall",
|
|
|
|
|
"jon_drwn",
|
|
|
|
|
"jon_air1",
|
|
|
|
|
"jon_glp1", // 20
|
|
|
|
|
"jon_bbwl",
|
|
|
|
|
"jon_pois",
|
|
|
|
|
"amb_ston",
|
|
|
|
|
"cat_icu",
|
|
|
|
|
"bubble_h",
|
|
|
|
|
"set_land",
|
|
|
|
|
"jon_hlnd",
|
|
|
|
|
"jon_laf2",
|
|
|
|
|
"spi_jump",
|
|
|
|
|
"jon_scub", // 30
|
|
|
|
|
"item_use",
|
|
|
|
|
"tr_arrow",
|
|
|
|
|
"swi_foot",
|
|
|
|
|
"swi_ston",
|
|
|
|
|
"swi_wtr1",
|
|
|
|
|
"tr_fire",
|
|
|
|
|
"m_skull5",
|
|
|
|
|
"spi_atak",
|
|
|
|
|
"anu_hit",
|
|
|
|
|
"fishdies", // 40
|
|
|
|
|
"scrp_icu",
|
|
|
|
|
"jon_wade",
|
|
|
|
|
"amb_watr",
|
|
|
|
|
"tele_1",
|
|
|
|
|
"wasp_stg",
|
|
|
|
|
"res",
|
|
|
|
|
"drum4",
|
|
|
|
|
"rex_icu",
|
|
|
|
|
"m_hits_u",
|
|
|
|
|
"q_tail", // 50
|
|
|
|
|
"vatr_mov",
|
|
|
|
|
"jon_hit3",
|
|
|
|
|
"jon_t_2", // 53
|
|
|
|
|
"jon_t_1",
|
|
|
|
|
"jon_t_5",
|
|
|
|
|
"jon_t_6",
|
|
|
|
|
"jon_t_8",
|
|
|
|
|
"jon_t_4",
|
|
|
|
|
"rasprit1",
|
|
|
|
|
"jon_fdie", // 60
|
|
|
|
|
"wijaf1",
|
|
|
|
|
"ship_1",
|
|
|
|
|
"saw_on",
|
|
|
|
|
"ra_on",
|
|
|
|
|
"amb_ston", // 65
|
|
|
|
|
"vatr_stp", // 66
|
|
|
|
|
"mana1",
|
|
|
|
|
"mana2",
|
|
|
|
|
"ammo",
|
|
|
|
|
"pot_pc1", // 70?
|
|
|
|
|
"pot_pc2",
|
|
|
|
|
"weapon",
|
|
|
|
|
"alarm",
|
|
|
|
|
"tick1",
|
|
|
|
|
"scrp_zap", // 75
|
|
|
|
|
"jon_t_3",
|
|
|
|
|
"jon_laf1",
|
|
|
|
|
"blasted",
|
|
|
|
|
"jon_air2" // 79
|
|
|
|
|
};
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
short nAmbientChannel = -1;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
short nStopSound;
|
|
|
|
|
short nStoneSound;
|
|
|
|
|
short nSwitchSound;
|
|
|
|
|
short nLocalEyeSect;
|
|
|
|
|
short nElevSound;
|
|
|
|
|
short nCreepyTimer;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-27 21:17:36 +00:00
|
|
|
|
bool looped[kMaxSounds];
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
|
|
|
|
struct ActiveSound
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
short snd_sprite;
|
|
|
|
|
short snd_id;
|
|
|
|
|
short snd_volume;
|
|
|
|
|
short snd_angle;
|
|
|
|
|
short snd_ambientflag;
|
|
|
|
|
short snd_priority;
|
|
|
|
|
int snd_handle;
|
|
|
|
|
FSoundChan* snd_channel;
|
|
|
|
|
int snd_pitch;
|
|
|
|
|
int snd_time;
|
|
|
|
|
int snd_x;
|
|
|
|
|
int snd_y;
|
|
|
|
|
int snd_z;
|
|
|
|
|
short snd_sector;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
ActiveSound sActiveSound[kMaxSounds];
|
2019-12-27 21:17:36 +00:00
|
|
|
|
short StaticSound[kMaxSounds];
|
2019-12-25 22:37:16 +00:00
|
|
|
|
int fakesources[] = { 0, 1, 2, 3 };
|
|
|
|
|
int nLocalChan = 0;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
nSwirlyChan1 = 1,
|
|
|
|
|
nSwirlyChan2,
|
|
|
|
|
nSwirlyChan3,
|
|
|
|
|
nSwirlyChan4,
|
2019-09-19 02:12:24 +00:00
|
|
|
|
};
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
class EXSoundEngine : public SoundEngine
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
// client specific parts of the sound engine go in this class.
|
|
|
|
|
void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) override;
|
|
|
|
|
TArray<uint8_t> ReadSound(int lumpnum) override;
|
|
|
|
|
void ChannelEnded(FISoundChannel* chan) override
|
2019-08-31 07:47:15 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
for (auto& inf : sActiveSound)
|
2019-08-31 07:47:15 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (inf.snd_channel == chan) inf.snd_channel = nullptr;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
}
|
2019-12-27 19:05:58 +00:00
|
|
|
|
SoundEngine::ChannelEnded(chan);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
public:
|
|
|
|
|
EXSoundEngine()
|
2019-08-31 07:47:15 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
int eax = 260;
|
|
|
|
|
TArray<uint8_t> disttable(256, 1);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
|
|
|
{
|
|
|
|
|
if (eax > 65280)
|
|
|
|
|
{
|
|
|
|
|
disttable[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-28 17:20:47 +00:00
|
|
|
|
disttable[i] = 255 - (eax >> 8);
|
2019-09-19 02:12:24 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
eax = (eax * eax) >> 8;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
S_Rolloff.RolloffType = ROLLOFF_Custom;
|
|
|
|
|
S_Rolloff.MinDistance = 0;
|
|
|
|
|
S_Rolloff.MaxDistance = 4096; // It's really this big
|
|
|
|
|
Init(disttable, 255);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
}
|
2019-12-25 22:37:16 +00:00
|
|
|
|
};
|
2019-09-19 02:12:24 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
TArray<uint8_t> EXSoundEngine::ReadSound(int lumpnum)
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
auto wlump = fileSystem.OpenFileReader(lumpnum);
|
|
|
|
|
return wlump.Read();
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
2019-12-27 21:17:36 +00:00
|
|
|
|
int LoadSound(const char* name)
|
|
|
|
|
{
|
|
|
|
|
FString nname(name, 8);
|
|
|
|
|
int sndid = soundEngine->FindSoundNoHash(nname.GetChars());
|
|
|
|
|
if (sndid > 0) return sndid - 1;
|
|
|
|
|
|
|
|
|
|
FStringf filename("%s.voc", nname.GetChars());
|
2020-01-27 21:29:45 +00:00
|
|
|
|
auto lump = S_LookupSound(filename);
|
2019-12-27 21:17:36 +00:00
|
|
|
|
if (lump > 0)
|
|
|
|
|
{
|
|
|
|
|
auto &S_sfx = soundEngine->GetSounds();
|
|
|
|
|
S_sfx.Reserve(1);
|
|
|
|
|
int retval = S_sfx.Size() - 2;
|
|
|
|
|
auto check = fileSystem.GetFileData(lump);
|
|
|
|
|
if (check.Size() > 26 && check[26] == 6 && !memcmp("Creative Voice File", check.Data(), 19))
|
|
|
|
|
{
|
|
|
|
|
// This game uses the actual loop point information in the sound data as its only means to check if a sound is looped.
|
|
|
|
|
looped[retval] = true;
|
|
|
|
|
}
|
|
|
|
|
auto& newsfx = S_sfx.Last();
|
|
|
|
|
newsfx.Clear();
|
|
|
|
|
newsfx.name = nname;
|
|
|
|
|
newsfx.lumpnum = lump;
|
|
|
|
|
newsfx.NearLimit = 6;
|
|
|
|
|
newsfx.bTentative = false;
|
|
|
|
|
soundEngine->CacheSound(retval + 1);
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
else if (!ISDEMOVER) // demo tries to load sound files it doesn't have
|
|
|
|
|
{
|
|
|
|
|
Printf("Unable to open sound '%s'!\n", filename.GetChars());
|
|
|
|
|
}
|
2019-12-28 17:20:47 +00:00
|
|
|
|
return -1;
|
2019-12-27 21:17:36 +00:00
|
|
|
|
}
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
void InitFX(void)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (soundEngine) return; // just in case.
|
|
|
|
|
soundEngine = new EXSoundEngine;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
auto& S_sfx = soundEngine->GetSounds();
|
2019-12-27 21:17:36 +00:00
|
|
|
|
S_sfx.Resize(1);
|
|
|
|
|
S_sfx[0].Clear(); S_sfx[0].lumpnum = sfx_empty;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
for (size_t i = 0; i < kMaxSoundFiles; i++)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-27 21:17:36 +00:00
|
|
|
|
StaticSound[i] = LoadSound(SoundFiles[i]);
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
2019-12-25 22:37:16 +00:00
|
|
|
|
soundEngine->HashSounds();
|
|
|
|
|
|
|
|
|
|
memset(sActiveSound, 255, sizeof(sActiveSound));
|
|
|
|
|
for (int i = 0; i < kMaxSounds; i++)
|
2019-08-31 07:47:15 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
sActiveSound[i].snd_channel = nullptr;
|
|
|
|
|
sActiveSound[i].snd_handle = -1;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
nCreepyTimer = kCreepyCount;
|
|
|
|
|
}
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
void GetSpriteSoundPitch(short nSector, int* pVolume, int* pPitch, int nLocalSectFlags)
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-09-18 16:11:06 +00:00
|
|
|
|
if (nSector < 0)
|
|
|
|
|
return;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if ((SectFlag[nSector] ^ nLocalSectFlags) & kSectUnderwater)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
|
|
|
|
*pVolume >>= 1;
|
|
|
|
|
*pPitch -= 1200;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
void BendAmbientSound(void)
|
|
|
|
|
{
|
|
|
|
|
if (nAmbientChannel < 0)
|
|
|
|
|
return;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
ActiveSound* pASound = &sActiveSound[nAmbientChannel];
|
|
|
|
|
if (pASound->snd_channel)
|
|
|
|
|
{
|
|
|
|
|
soundEngine->SetPitch(pASound->snd_channel, (nDronePitch + 11800) / 11025.f);
|
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-27 22:09:05 +00:00
|
|
|
|
void PlayLocalSound(short nSound, short nRate, bool unattached)
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (nSound < 0 || nSound >= kMaxSounds || !soundEngine->isValidSoundId(nSound + 1))
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
initprintf("PlayLocalSound: Invalid sound nSound == %i, nRate == %i\n", nSound, nRate);
|
|
|
|
|
return;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
2019-12-27 22:09:05 +00:00
|
|
|
|
int bLoop = looped[nSound];
|
2019-12-25 22:37:16 +00:00
|
|
|
|
|
|
|
|
|
if (nLocalChan == nAmbientChannel)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
nAmbientChannel = -1;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
|
|
|
|
|
|
2019-12-27 22:09:05 +00:00
|
|
|
|
ActiveSound* pASound = nullptr;
|
|
|
|
|
|
|
|
|
|
if (!unattached)
|
|
|
|
|
{
|
|
|
|
|
pASound = &sActiveSound[nLocalChan];
|
|
|
|
|
if (pASound->snd_channel != nullptr)
|
|
|
|
|
soundEngine->StopChannel(pASound->snd_channel);
|
|
|
|
|
}
|
2019-12-25 22:37:16 +00:00
|
|
|
|
|
2019-12-27 22:09:05 +00:00
|
|
|
|
// There is exactly one occurence in the entire game which alters the pitch, and that's the laugh on the logo.
|
|
|
|
|
auto chan = soundEngine->StartSound(SOURCE_Unattached, nullptr, nullptr, CHAN_BODY, CHANF_OVERLAP, nSound + 1, 1.f, ATTN_NONE, nullptr);
|
2019-12-25 22:37:16 +00:00
|
|
|
|
|
2019-12-27 22:09:05 +00:00
|
|
|
|
if (nRate && chan)
|
2019-12-25 22:37:16 +00:00
|
|
|
|
{
|
|
|
|
|
float ratefac = (11025 + nRate) / 11025.f;
|
2019-12-27 22:09:05 +00:00
|
|
|
|
soundEngine->SetPitch(chan, ratefac);
|
|
|
|
|
}
|
|
|
|
|
if (pASound)
|
|
|
|
|
{
|
|
|
|
|
pASound->snd_id = nSound;
|
|
|
|
|
pASound->snd_channel = chan;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
int LocalSoundPlaying(void)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
return sActiveSound[nLocalChan].snd_channel != nullptr;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
int GetLocalSound(void)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (LocalSoundPlaying() == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
return sActiveSound[nLocalChan].snd_id & 0x1ff;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
void StopLocalSound(void)
|
|
|
|
|
{
|
|
|
|
|
if (nLocalChan == nAmbientChannel)
|
|
|
|
|
nAmbientChannel = -1;
|
|
|
|
|
|
|
|
|
|
if (LocalSoundPlaying())
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
soundEngine->StopChannel(sActiveSound[nLocalChan].snd_channel);
|
|
|
|
|
sActiveSound[nLocalChan].snd_channel = nullptr;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
int nNextFreq;
|
|
|
|
|
int nSwirlyFrames;
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
void StartSwirly(int nActiveSound)
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
ActiveSound* pASound = &sActiveSound[nActiveSound];
|
|
|
|
|
pASound->snd_angle = rand() & 0x7ff;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
short nPitch = nNextFreq - RandomSize(9);
|
|
|
|
|
pASound->snd_pitch = nPitch;
|
|
|
|
|
nNextFreq = 25000 - RandomSize(10) * 6;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
if (nNextFreq > 32000)
|
|
|
|
|
nNextFreq = 32000;
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
int nVolume = nSwirlyFrames + 1;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
if (nVolume >= 220)
|
|
|
|
|
nVolume = 220;
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
pASound->snd_volume = nVolume;
|
|
|
|
|
if (pASound->snd_channel) soundEngine->StopChannel(pASound->snd_channel);
|
2019-09-19 02:12:24 +00:00
|
|
|
|
|
2019-12-27 21:17:36 +00:00
|
|
|
|
pASound->snd_channel = soundEngine->StartSound(SOURCE_Swirly, &fakesources[nActiveSound-1], nullptr, CHAN_BODY, 0, StaticSound[kSound67]+1, nVolume / 255.f, ATTN_NONE, nullptr, nPitch / 11025.f);
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
void StartSwirlies()
|
|
|
|
|
{
|
|
|
|
|
StopAllSounds();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
nNextFreq = 19000;
|
|
|
|
|
nSwirlyFrames = 0;
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
for (int i = nSwirlyChan1; i <= nSwirlyChan4; i++)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
StartSwirly(i);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
void UpdateSwirlies()
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-09-18 16:11:06 +00:00
|
|
|
|
nSwirlyFrames++;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
for (int i = nSwirlyChan1; i <= nSwirlyChan4; i++)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
ActiveSound* pASound = &sActiveSound[i];
|
|
|
|
|
|
|
|
|
|
if (pASound->snd_channel == nullptr)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
StartSwirly(i);
|
2019-12-25 22:37:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
void SoundBigEntrance(void)
|
|
|
|
|
{
|
|
|
|
|
StopAllSounds();
|
|
|
|
|
ActiveSound* pASound = sActiveSound+1;
|
|
|
|
|
for (int i = 0; i < 4; i++, pASound++)
|
|
|
|
|
{
|
|
|
|
|
short nPitch = i * 512 - 1200;
|
|
|
|
|
pASound->snd_pitch = nPitch;
|
|
|
|
|
if (pASound->snd_channel) soundEngine->StopChannel(pASound->snd_channel);
|
2019-12-27 21:17:36 +00:00
|
|
|
|
pASound->snd_channel = soundEngine->StartSound(SOURCE_EXBoss, &fakesources[i], nullptr, CHAN_BODY, 0, StaticSound[kSoundTorchOn]+1, 200 / 255.f, ATTN_NONE, nullptr, nPitch / 11025.f);
|
2019-12-25 22:37:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
void EXSoundEngine::CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan)
|
|
|
|
|
{
|
|
|
|
|
if (pos != nullptr)
|
|
|
|
|
{
|
|
|
|
|
vec3_t campos;
|
|
|
|
|
if (nSnakeCam > -1)
|
2019-09-19 02:12:24 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
Snake* pSnake = &SnakeList[nSnakeCam];
|
|
|
|
|
spritetype* pSnakeSprite = &sprite[pSnake->nSprites[0]];
|
|
|
|
|
campos.x = pSnakeSprite->x;
|
|
|
|
|
campos.y = pSnakeSprite->y;
|
|
|
|
|
campos.z = pSnakeSprite->z;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
campos = { initx, inity, initz };
|
|
|
|
|
}
|
|
|
|
|
auto fcampos = GetSoundPos(&campos);
|
|
|
|
|
|
|
|
|
|
if (type == SOURCE_Unattached)
|
|
|
|
|
{
|
|
|
|
|
pos->X = pt[0];
|
|
|
|
|
pos->Y = pt[1];
|
|
|
|
|
pos->Z = pt[2];
|
|
|
|
|
}
|
|
|
|
|
// Do some angular magic. The original was just 2D panning which in a 3D sound field is not sufficient.
|
|
|
|
|
else if (type == SOURCE_Swirly)
|
|
|
|
|
{
|
|
|
|
|
int which = *(int*)source;
|
|
|
|
|
float phase = ((int)totalclock << (4 + which)) * (M_PI / 1024);
|
|
|
|
|
pos->X = fcampos.X + 256 * cos(phase);
|
|
|
|
|
pos->Y = fcampos.Y + 256 * sin(phase);
|
|
|
|
|
}
|
|
|
|
|
else if (type == SOURCE_EXBoss)
|
|
|
|
|
{
|
|
|
|
|
int which = *(int*)source;
|
|
|
|
|
*pos = fcampos;
|
|
|
|
|
// Should be positioned in 90<39> intervals.
|
|
|
|
|
switch (which)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
case 0: pos->X -= 256; break;
|
|
|
|
|
case 1: pos->Y -= 256; break;
|
|
|
|
|
case 2: pos->X += 256; break;
|
|
|
|
|
case 3: pos->Y += 256; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (type == SOURCE_Actor)
|
|
|
|
|
{
|
|
|
|
|
auto actor = (spritetype*)source;
|
|
|
|
|
assert(actor != nullptr);
|
|
|
|
|
if (actor != nullptr)
|
|
|
|
|
{
|
|
|
|
|
*pos = GetSoundPos(&actor->pos);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ((chanflags & CHANF_LISTENERZ) && type != SOURCE_None)
|
|
|
|
|
{
|
|
|
|
|
pos->Y = fcampos.Z;
|
2019-09-19 02:12:24 +00:00
|
|
|
|
}
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
int GetDistFromDXDY(int dx, int dy)
|
|
|
|
|
{
|
|
|
|
|
int nSqr = dx*dx+dy*dy;
|
|
|
|
|
return (nSqr>>3)-(nSqr>>5);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
void UpdateSounds()
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (nFreeze)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
int nLocalSectFlags = SectFlag[nPlayerViewSect[nLocalPlayer]];
|
2019-12-25 18:17:06 +00:00
|
|
|
|
|
2019-12-27 16:07:09 +00:00
|
|
|
|
vec3_t pos;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
short ang;
|
|
|
|
|
if (nSnakeCam > -1)
|
|
|
|
|
{
|
|
|
|
|
Snake *pSnake = &SnakeList[nSnakeCam];
|
|
|
|
|
spritetype *pSnakeSprite = &sprite[pSnake->nSprites[0]];
|
2019-12-27 16:07:09 +00:00
|
|
|
|
pos = pSnakeSprite->pos;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
ang = pSnakeSprite->ang;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-12-27 16:07:09 +00:00
|
|
|
|
pos = { initx, inity, initz };
|
2019-09-18 16:11:06 +00:00
|
|
|
|
ang = inita;
|
|
|
|
|
}
|
2019-12-27 16:07:09 +00:00
|
|
|
|
auto fv = GetSoundPos(&pos);
|
|
|
|
|
SoundListener listener;
|
|
|
|
|
listener.angle = -(float)ang * pi::pi() / 1024; // Build uses a period of 2048.
|
|
|
|
|
listener.velocity.Zero();
|
|
|
|
|
listener.position = GetSoundPos(&pos);
|
|
|
|
|
listener.underwater = false;
|
|
|
|
|
// This should probably use a real environment instead of the pitch hacking in S_PlaySound3D.
|
|
|
|
|
// listenactor->waterlevel == 3;
|
|
|
|
|
//assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber);
|
|
|
|
|
listener.Environment = 0;// primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment;
|
|
|
|
|
listener.valid = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
soundEngine->SetListener(listener);
|
|
|
|
|
soundEngine->UpdateSounds((int)totalclock);
|
2019-09-18 16:11:06 +00:00
|
|
|
|
ActiveSound* pASound = sActiveSound;
|
|
|
|
|
pASound++;
|
|
|
|
|
for (int i = 1; i < kMaxActiveSounds; i++, pASound++)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (pASound->snd_channel != nullptr)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-27 16:07:09 +00:00
|
|
|
|
if (pASound->snd_channel->ChanFlags & CHANF_FORGETTABLE)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-27 16:07:09 +00:00
|
|
|
|
// If the channel has become invalid, remove the reference.
|
|
|
|
|
// ChannelEnded may be called late so waiting for it is problematic.
|
|
|
|
|
pASound->snd_channel = nullptr;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2019-12-27 16:07:09 +00:00
|
|
|
|
{
|
|
|
|
|
short nSoundSprite = pASound->snd_sprite;
|
|
|
|
|
int nPitch = pASound->snd_pitch;
|
|
|
|
|
short nSoundSect;
|
|
|
|
|
if (nSoundSprite >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (nSoundSprite == nLocalSpr)
|
|
|
|
|
nSoundSect = nPlayerViewSect[nLocalPlayer];
|
|
|
|
|
else
|
|
|
|
|
nSoundSect = sprite[nSoundSprite].sectnum;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
nSoundSect = pASound->snd_sector;
|
2019-11-03 17:32:02 +00:00
|
|
|
|
|
2019-12-27 16:07:09 +00:00
|
|
|
|
int nVolume = pASound->snd_volume;
|
|
|
|
|
GetSpriteSoundPitch(nSoundSect, &nVolume, &nPitch, nLocalSectFlags);
|
|
|
|
|
soundEngine->SetPitch(pASound->snd_channel, (11025 + nPitch) / 11025.f);
|
|
|
|
|
soundEngine->SetVolume(pASound->snd_channel, nVolume / 255.f);
|
|
|
|
|
}
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
int soundx, soundy, soundz;
|
|
|
|
|
short soundsect;
|
|
|
|
|
|
|
|
|
|
short PlayFX2(unsigned short nSound, short nSprite)
|
|
|
|
|
{
|
2019-12-27 21:17:36 +00:00
|
|
|
|
if ((nSound&0x1ff) >= kMaxSounds || !soundEngine->isValidSoundId((nSound & 0x1ff)+1))
|
2019-11-13 19:28:17 +00:00
|
|
|
|
{
|
|
|
|
|
initprintf("PlayFX2: Invalid sound nSound == %i, nSprite == %i\n", nSound, nSprite);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
int nLocalSectFlags = SectFlag[nPlayerViewSect[nLocalPlayer]];
|
2019-09-18 16:11:06 +00:00
|
|
|
|
short v1c;
|
|
|
|
|
short vcx;
|
|
|
|
|
if (nSprite < 0)
|
|
|
|
|
{
|
|
|
|
|
vcx = 0;
|
|
|
|
|
v1c = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
v1c = nSprite&0x2000;
|
|
|
|
|
vcx = nSprite&0x4000;
|
|
|
|
|
nSprite &= 0xfff;
|
|
|
|
|
soundx = sprite[nSprite].x;
|
|
|
|
|
soundy = sprite[nSprite].y;
|
|
|
|
|
soundz = sprite[nSprite].z;
|
|
|
|
|
}
|
|
|
|
|
int dx, dy;
|
|
|
|
|
|
|
|
|
|
dx = initx-soundx;
|
|
|
|
|
dy = inity-soundy;
|
|
|
|
|
|
|
|
|
|
dx >>= 8; dy >>= 8;
|
|
|
|
|
|
|
|
|
|
short nSoundAng;
|
|
|
|
|
if ((dx|dy) == 0)
|
|
|
|
|
nSoundAng = 0;
|
|
|
|
|
else
|
|
|
|
|
nSoundAng = AngleDelta(GetMyAngle(dx, dy), inita, 1024);
|
|
|
|
|
|
|
|
|
|
int nDist = GetDistFromDXDY(dx, dy);
|
|
|
|
|
if (nDist >= 255)
|
|
|
|
|
{
|
2019-11-21 23:17:59 +00:00
|
|
|
|
if ((int16_t)nSound > -1)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
StopSpriteSound(nSound);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nVolume;
|
|
|
|
|
|
|
|
|
|
if (!v1c)
|
|
|
|
|
{
|
2019-12-13 17:28:58 +00:00
|
|
|
|
nVolume = snd_fxvolume+10-(Sin(nDist<<1)>>6)-10;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
if (nVolume <= 0)
|
|
|
|
|
{
|
2019-11-21 23:17:59 +00:00
|
|
|
|
if ((int16_t)nSound > -1)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
StopSpriteSound(nSound);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if (nVolume > 255)
|
|
|
|
|
nVolume = 255;
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-12-13 17:28:58 +00:00
|
|
|
|
nVolume = snd_fxvolume;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
|
|
|
|
short vc = nSound & (~0x1ff);
|
|
|
|
|
short v4 = nSound & 0x2000;
|
|
|
|
|
short v8 = nSound & 0x1000;
|
|
|
|
|
short v14 = nSound & 0x4000;
|
2019-09-21 17:03:53 +00:00
|
|
|
|
short v10 = (nSound&0xe00)>>9;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
int v2c = 0x7fffffff;
|
|
|
|
|
ActiveSound* v38 = NULL;
|
|
|
|
|
ActiveSound* v28 = NULL;
|
|
|
|
|
ActiveSound* vdi = NULL;
|
|
|
|
|
nSound &= 0x1ff;
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
short priority;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
|
|
|
|
if (v8 || v14)
|
2019-12-25 22:37:16 +00:00
|
|
|
|
priority = 1000;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
else if (nSprite != -1 && vcx)
|
2019-12-25 22:37:16 +00:00
|
|
|
|
priority = 2000;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
else
|
2019-12-25 22:37:16 +00:00
|
|
|
|
priority = 0;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
ActiveSound* pASound = sActiveSound;
|
|
|
|
|
pASound++;
|
|
|
|
|
for (int i = 1; i < kMaxActiveSounds; i++, pASound++)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (pASound->snd_channel == nullptr)
|
|
|
|
|
{
|
2019-09-18 16:11:06 +00:00
|
|
|
|
vdi = pASound;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
}
|
|
|
|
|
else if (priority >= pASound->snd_priority)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (v2c > pASound->snd_time && pASound->snd_priority <= priority)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
|
|
|
|
v28 = pASound;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
v2c = pASound->snd_time;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
if (!v8)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (nSound == pASound->snd_id)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (v4 == 0 && nSprite == pASound->snd_sprite)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
return -1;
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (priority >= pASound->snd_priority)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
v38 = pASound;
|
|
|
|
|
}
|
2019-12-25 22:37:16 +00:00
|
|
|
|
else if (nSprite == pASound->snd_sprite)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (v4 || nSound != pASound->snd_id)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
|
|
|
|
vdi = pASound;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!vdi)
|
|
|
|
|
{
|
|
|
|
|
if (v38)
|
|
|
|
|
vdi = v38;
|
|
|
|
|
else if (v28)
|
|
|
|
|
vdi = v28;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (vdi->snd_channel != nullptr)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
soundEngine->StopChannel(vdi->snd_channel);
|
|
|
|
|
vdi->snd_channel = nullptr;
|
|
|
|
|
if (short(vdi - sActiveSound) == nAmbientChannel) // f_2c was never set to anything other than 0.
|
2019-09-18 16:11:06 +00:00
|
|
|
|
nAmbientChannel = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int nPitch;
|
|
|
|
|
if (v10)
|
2019-09-21 17:03:53 +00:00
|
|
|
|
nPitch = -(totalmoves&((1<<v10)-1))*16;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
else
|
|
|
|
|
nPitch = 0;
|
|
|
|
|
|
|
|
|
|
if (vdi)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
vdi->snd_pitch = nPitch;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
if (nSprite < 0)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
vdi->snd_x = soundx;
|
|
|
|
|
vdi->snd_y = soundy;
|
|
|
|
|
vdi->snd_sector = soundsect;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
2019-12-25 22:37:16 +00:00
|
|
|
|
GetSpriteSoundPitch(soundsect, &nVolume, &nPitch, nLocalSectFlags);
|
|
|
|
|
vdi->snd_volume = nVolume;
|
|
|
|
|
vdi->snd_angle = nSoundAng;
|
|
|
|
|
vdi->snd_sprite = nSprite;
|
|
|
|
|
vdi->snd_id = nSound;
|
|
|
|
|
vdi->snd_time = (int)totalclock;
|
|
|
|
|
vdi->snd_priority = priority;
|
|
|
|
|
vdi->snd_ambientflag = vc;
|
|
|
|
|
|
|
|
|
|
int bLoop = looped[nSound];
|
|
|
|
|
|
|
|
|
|
if (nSprite)
|
2019-09-19 02:12:24 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
vdi->snd_channel = soundEngine->StartSound(SOURCE_Actor, &sprite[nSprite], nullptr, CHAN_BODY, CHANF_OVERLAP, nSound+1, nVolume / 255.f, ATTN_NORM, nullptr, (11025 + nPitch) / 11025.f);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
vec3_t v = { soundx, soundy, soundz };
|
|
|
|
|
FVector3 vv = GetSoundPos(&v);
|
|
|
|
|
vdi->snd_channel = soundEngine->StartSound(SOURCE_Unattached, nullptr, &vv, CHAN_BODY, CHANF_OVERLAP, nSound+1, nVolume / 255.f, ATTN_NORM, nullptr, (11025 + nPitch) / 11025.f);
|
2019-09-19 02:12:24 +00:00
|
|
|
|
}
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
|
|
|
|
if (v14)
|
|
|
|
|
nAmbientChannel = v14;
|
|
|
|
|
|
|
|
|
|
// Nuke: added nSprite >= 0 check
|
|
|
|
|
if (nSprite != nLocalSpr && nSprite >= 0 && (sprite[nSprite].cstat&257))
|
2019-11-03 17:32:02 +00:00
|
|
|
|
nCreepyTimer = kCreepyCount;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
|
|
|
|
return v14;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
short PlayFXAtXYZ(unsigned short ax, int x, int y, int z, int nSector)
|
2019-08-26 03:59:14 +00:00
|
|
|
|
{
|
2019-09-18 16:11:06 +00:00
|
|
|
|
soundx = x;
|
|
|
|
|
soundy = y;
|
|
|
|
|
soundz = z;
|
|
|
|
|
soundsect = nSector&0x3fff;
|
|
|
|
|
short nSnd = PlayFX2(ax, -1);
|
|
|
|
|
if (nSnd > -1 && (nSector&0x4000))
|
2019-12-25 22:37:16 +00:00
|
|
|
|
sActiveSound[nSnd].snd_priority = 2000;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
return nSnd;
|
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
void CheckAmbience(short nSector)
|
|
|
|
|
{
|
|
|
|
|
if (SectSound[nSector] != -1)
|
|
|
|
|
{
|
|
|
|
|
short nSector2 = SectSoundSect[nSector];
|
|
|
|
|
walltype* pWall = &wall[sector[nSector2].wallptr];
|
|
|
|
|
if (nAmbientChannel < 0)
|
|
|
|
|
{
|
|
|
|
|
PlayFXAtXYZ(SectSound[nSector] | 0x4000, pWall->x, pWall->y, sector[nSector2].floorz, nSector);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
ActiveSound* pASound = &sActiveSound[nAmbientChannel];
|
|
|
|
|
if (nSector == nSector2)
|
|
|
|
|
{
|
|
|
|
|
spritetype* pSprite = &sprite[PlayerList[0].nSprite];
|
|
|
|
|
pASound->snd_x = pSprite->x;
|
|
|
|
|
pASound->snd_y = pSprite->y;
|
|
|
|
|
pASound->snd_z = pSprite->z;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pASound->snd_x = pWall->x;
|
|
|
|
|
pASound->snd_y = pWall->y;
|
|
|
|
|
pASound->snd_z = sector[nSector2].floorz;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (nAmbientChannel != -1)
|
|
|
|
|
{
|
|
|
|
|
if (sActiveSound[nAmbientChannel].snd_channel)
|
|
|
|
|
soundEngine->StopChannel(sActiveSound[nAmbientChannel].snd_channel);
|
|
|
|
|
sActiveSound[nAmbientChannel].snd_channel = nullptr;
|
|
|
|
|
nAmbientChannel = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
void UpdateCreepySounds()
|
|
|
|
|
{
|
|
|
|
|
if (levelnum == 20 || nFreeze)
|
|
|
|
|
return;
|
|
|
|
|
spritetype* pSprite = &sprite[PlayerList[nLocalPlayer].nSprite];
|
|
|
|
|
nCreepyTimer--;
|
|
|
|
|
if (nCreepyTimer <= 0)
|
|
|
|
|
{
|
|
|
|
|
if (nCreaturesLeft > 0 && !(SectFlag[nPlayerViewSect[nLocalPlayer]] & 0x2000))
|
|
|
|
|
{
|
|
|
|
|
int vsi = seq_GetFrameSound(SeqOffsets[kSeqCreepy], totalmoves % SeqSize[SeqOffsets[kSeqCreepy]]);
|
|
|
|
|
if (vsi >= 0 && (vsi & 0x1ff) < kMaxSounds)
|
|
|
|
|
{
|
|
|
|
|
int vdx = (totalmoves + 32) & 31;
|
|
|
|
|
if (totalmoves & 1)
|
|
|
|
|
vdx = -vdx;
|
|
|
|
|
int vax = (totalmoves + 32) & 63;
|
|
|
|
|
if (totalmoves & 2)
|
|
|
|
|
vax = -vax;
|
|
|
|
|
|
|
|
|
|
PlayFXAtXYZ(vsi, pSprite->x + vdx, pSprite->y + vax, pSprite->z, pSprite->sectnum);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
nCreepyTimer = kCreepyCount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
2019-09-18 16:11:06 +00:00
|
|
|
|
short D3PlayFX(unsigned short nSound, short nVal)
|
|
|
|
|
{
|
|
|
|
|
return PlayFX2(nSound, nVal);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
}
|
2019-09-18 16:11:06 +00:00
|
|
|
|
|
|
|
|
|
void StopSpriteSound(short nSprite)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < kMaxActiveSounds; i++)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
if (sActiveSound[i].snd_channel != nullptr && nSprite == sActiveSound[i].snd_sprite)
|
2019-09-18 16:11:06 +00:00
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
soundEngine->StopChannel(sActiveSound[i].snd_channel);
|
|
|
|
|
sActiveSound[i].snd_channel = nullptr;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StopAllSounds(void)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
soundEngine->StopAllChannels();
|
2019-09-18 16:11:06 +00:00
|
|
|
|
for (int i = 0; i < kMaxActiveSounds; i++)
|
|
|
|
|
{
|
2019-12-25 22:37:16 +00:00
|
|
|
|
sActiveSound[i].snd_channel = nullptr;
|
2019-09-18 16:11:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nAmbientChannel = -1;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-25 22:37:16 +00:00
|
|
|
|
//==========================================================================
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//==========================================================================
|
|
|
|
|
|
|
|
|
|
void PlayTitleSound(void)
|
|
|
|
|
{
|
|
|
|
|
PlayLocalSound(StaticSound[kSound10], 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlayLogoSound(void)
|
|
|
|
|
{
|
|
|
|
|
PlayLocalSound(StaticSound[kSound28], 7000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PlayGameOverSound(void)
|
|
|
|
|
{
|
|
|
|
|
PlayLocalSound(StaticSound[kSound28], 0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-22 23:11:37 +00:00
|
|
|
|
END_PS_NS
|