mirror of
https://github.com/ddnet/ddnet.git
synced 2024-09-21 18:14:19 +00:00
49bc150afd
On the one hand variables called "Dummy" would tell us whether the current action refers to the currently inactive tee ("dummy"). On the other hand, these variables could tell us whether the current action refers to the main connection to the server, or the secondary one. The latter use case is now renamed to "Client", with the choices `CLIENT_MAIN`, `CLIENT_DUMMY` (and `CLIENT_CONTACT`). Perhaps better names could be found, especially since `Client` also refers to the engine client class in the game code. I tried to not fix bugs unless it would complicate the code.
256 lines
6.3 KiB
C++
256 lines
6.3 KiB
C++
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
|
|
|
#include <base/tl/array.h>
|
|
|
|
#include "sounds.h"
|
|
#include <engine/engine.h>
|
|
#include <engine/shared/config.h>
|
|
#include <engine/sound.h>
|
|
#include <game/client/components/camera.h>
|
|
#include <game/client/components/menus.h>
|
|
#include <game/client/gameclient.h>
|
|
#include <game/generated/client_data.h>
|
|
|
|
CSoundLoading::CSoundLoading(CGameClient *pGameClient, bool Render) :
|
|
m_pGameClient(pGameClient),
|
|
m_Render(Render)
|
|
{
|
|
}
|
|
|
|
void CSoundLoading::Run()
|
|
{
|
|
for(int s = 0; s < g_pData->m_NumSounds; s++)
|
|
{
|
|
for(int i = 0; i < g_pData->m_aSounds[s].m_NumSounds; i++)
|
|
{
|
|
int Id = m_pGameClient->Sound()->LoadWV(g_pData->m_aSounds[s].m_aSounds[i].m_pFilename);
|
|
g_pData->m_aSounds[s].m_aSounds[i].m_Id = Id;
|
|
}
|
|
|
|
if(m_Render)
|
|
m_pGameClient->m_Menus.RenderLoading();
|
|
}
|
|
}
|
|
|
|
int CSounds::GetSampleId(int SetId)
|
|
{
|
|
if(!g_Config.m_SndEnable || !Sound()->IsSoundEnabled() || m_WaitForSoundJob || SetId < 0 || SetId >= g_pData->m_NumSounds)
|
|
return -1;
|
|
|
|
CDataSoundset *pSet = &g_pData->m_aSounds[SetId];
|
|
if(!pSet->m_NumSounds)
|
|
return -1;
|
|
|
|
if(pSet->m_NumSounds == 1)
|
|
return pSet->m_aSounds[0].m_Id;
|
|
|
|
// return random one
|
|
int Id;
|
|
do
|
|
{
|
|
Id = rand() % pSet->m_NumSounds;
|
|
} while(Id == pSet->m_Last);
|
|
pSet->m_Last = Id;
|
|
return pSet->m_aSounds[Id].m_Id;
|
|
}
|
|
|
|
void CSounds::OnInit()
|
|
{
|
|
// setup sound channels
|
|
m_GuiSoundVolume = g_Config.m_SndChatSoundVolume / 100.0f;
|
|
m_GameSoundVolume = g_Config.m_SndGameSoundVolume / 100.0f;
|
|
m_MapSoundVolume = g_Config.m_SndMapSoundVolume / 100.0f;
|
|
m_BackgroundMusicVolume = g_Config.m_SndBackgroundMusicVolume / 100.0f;
|
|
|
|
Sound()->SetChannel(CSounds::CHN_GUI, m_GuiSoundVolume, 0.0f);
|
|
Sound()->SetChannel(CSounds::CHN_MUSIC, m_BackgroundMusicVolume, 1.0f);
|
|
Sound()->SetChannel(CSounds::CHN_WORLD, 0.9f * m_GameSoundVolume, 1.0f);
|
|
Sound()->SetChannel(CSounds::CHN_GLOBAL, m_GameSoundVolume, 0.0f);
|
|
Sound()->SetChannel(CSounds::CHN_MAPSOUND, m_MapSoundVolume, 1.0f);
|
|
|
|
Sound()->SetListenerPos(0.0f, 0.0f);
|
|
|
|
ClearQueue();
|
|
|
|
// load sounds
|
|
if(g_Config.m_ClThreadsoundloading)
|
|
{
|
|
m_pSoundJob = std::make_shared<CSoundLoading>(m_pClient, false);
|
|
m_pClient->Engine()->AddJob(m_pSoundJob);
|
|
m_WaitForSoundJob = true;
|
|
}
|
|
else
|
|
{
|
|
CSoundLoading(m_pClient, true).Run();
|
|
m_WaitForSoundJob = false;
|
|
}
|
|
}
|
|
|
|
void CSounds::OnReset()
|
|
{
|
|
if(Client()->State() >= IClient::STATE_ONLINE)
|
|
{
|
|
Sound()->StopAll();
|
|
ClearQueue();
|
|
}
|
|
}
|
|
|
|
void CSounds::OnStateChange(int NewState, int OldState)
|
|
{
|
|
if(NewState == IClient::STATE_ONLINE || NewState == IClient::STATE_DEMOPLAYBACK)
|
|
OnReset();
|
|
}
|
|
|
|
void CSounds::OnRender()
|
|
{
|
|
// check for sound initialisation
|
|
if(m_WaitForSoundJob)
|
|
{
|
|
if(m_pSoundJob->Status() == IJob::STATE_DONE)
|
|
m_WaitForSoundJob = false;
|
|
else
|
|
return;
|
|
}
|
|
|
|
// set listener pos
|
|
Sound()->SetListenerPos(m_pClient->m_Camera.m_Center.x, m_pClient->m_Camera.m_Center.y);
|
|
|
|
// update volume
|
|
float NewGuiSoundVol = g_Config.m_SndChatSoundVolume / 100.0f;
|
|
if(NewGuiSoundVol != m_GuiSoundVolume)
|
|
{
|
|
m_GuiSoundVolume = NewGuiSoundVol;
|
|
Sound()->SetChannel(CSounds::CHN_GUI, m_GuiSoundVolume, 1.0f);
|
|
}
|
|
|
|
float NewGameSoundVol = g_Config.m_SndGameSoundVolume / 100.0f;
|
|
if(NewGameSoundVol != m_GameSoundVolume)
|
|
{
|
|
m_GameSoundVolume = NewGameSoundVol;
|
|
Sound()->SetChannel(CSounds::CHN_WORLD, 0.9f * m_GameSoundVolume, 1.0f);
|
|
Sound()->SetChannel(CSounds::CHN_GLOBAL, m_GameSoundVolume, 1.0f);
|
|
}
|
|
|
|
float NewMapSoundVol = g_Config.m_SndMapSoundVolume / 100.0f;
|
|
if(NewMapSoundVol != m_MapSoundVolume)
|
|
{
|
|
m_MapSoundVolume = NewMapSoundVol;
|
|
Sound()->SetChannel(CSounds::CHN_MAPSOUND, m_MapSoundVolume, 1.0f);
|
|
}
|
|
|
|
float NewBackgroundMusicVol = g_Config.m_SndBackgroundMusicVolume / 100.0f;
|
|
if(NewBackgroundMusicVol != m_BackgroundMusicVolume)
|
|
{
|
|
m_BackgroundMusicVolume = NewBackgroundMusicVol;
|
|
Sound()->SetChannel(CSounds::CHN_MUSIC, m_BackgroundMusicVolume, 1.0f);
|
|
}
|
|
|
|
// play sound from queue
|
|
if(m_QueuePos > 0)
|
|
{
|
|
int64_t Now = time();
|
|
if(m_QueueWaitTime <= Now)
|
|
{
|
|
Play(m_aQueue[0].m_Channel, m_aQueue[0].m_SetId, 1.0f);
|
|
m_QueueWaitTime = Now + time_freq() * 3 / 10; // wait 300ms before playing the next one
|
|
if(--m_QueuePos > 0)
|
|
mem_move(m_aQueue, m_aQueue + 1, m_QueuePos * sizeof(QueueEntry));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSounds::ClearQueue()
|
|
{
|
|
mem_zero(m_aQueue, sizeof(m_aQueue));
|
|
m_QueuePos = 0;
|
|
m_QueueWaitTime = time();
|
|
}
|
|
|
|
void CSounds::Enqueue(int Channel, int SetId)
|
|
{
|
|
// add sound to the queue
|
|
if(m_QueuePos < QUEUE_SIZE)
|
|
{
|
|
if(Channel == CHN_MUSIC || !g_Config.m_ClEditor)
|
|
{
|
|
m_aQueue[m_QueuePos].m_Channel = Channel;
|
|
m_aQueue[m_QueuePos++].m_SetId = SetId;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSounds::PlayAndRecord(int Chn, int SetId, float Vol, vec2 Pos)
|
|
{
|
|
CNetMsg_Sv_SoundGlobal Msg;
|
|
Msg.m_SoundID = SetId;
|
|
Client()->SendPackMsgActive(&Msg, MSGFLAG_NOSEND | MSGFLAG_RECORD);
|
|
|
|
Play(Chn, SetId, Vol);
|
|
}
|
|
|
|
void CSounds::Play(int Chn, int SetId, float Vol)
|
|
{
|
|
if(Chn == CHN_MUSIC && !g_Config.m_SndMusic)
|
|
return;
|
|
|
|
int SampleId = GetSampleId(SetId);
|
|
if(SampleId == -1)
|
|
return;
|
|
|
|
int Flags = 0;
|
|
if(Chn == CHN_MUSIC)
|
|
Flags = ISound::FLAG_LOOP;
|
|
|
|
Sound()->Play(Chn, SampleId, Flags);
|
|
}
|
|
|
|
void CSounds::PlayAt(int Chn, int SetId, float Vol, vec2 Pos)
|
|
{
|
|
if(Chn == CHN_MUSIC && !g_Config.m_SndMusic)
|
|
return;
|
|
|
|
int SampleId = GetSampleId(SetId);
|
|
if(SampleId == -1)
|
|
return;
|
|
|
|
int Flags = 0;
|
|
if(Chn == CHN_MUSIC)
|
|
Flags = ISound::FLAG_LOOP;
|
|
|
|
Sound()->PlayAt(Chn, SampleId, Flags, Pos.x, Pos.y);
|
|
}
|
|
|
|
void CSounds::Stop(int SetId)
|
|
{
|
|
if(m_WaitForSoundJob || SetId < 0 || SetId >= g_pData->m_NumSounds)
|
|
return;
|
|
|
|
CDataSoundset *pSet = &g_pData->m_aSounds[SetId];
|
|
|
|
for(int i = 0; i < pSet->m_NumSounds; i++)
|
|
Sound()->Stop(pSet->m_aSounds[i].m_Id);
|
|
}
|
|
|
|
ISound::CVoiceHandle CSounds::PlaySample(int Chn, int SampleId, float Vol, int Flags)
|
|
{
|
|
if((Chn == CHN_MUSIC && !g_Config.m_SndMusic) || SampleId == -1)
|
|
return ISound::CVoiceHandle();
|
|
|
|
if(Chn == CHN_MUSIC)
|
|
Flags |= ISound::FLAG_LOOP;
|
|
|
|
return Sound()->Play(Chn, SampleId, Flags);
|
|
}
|
|
|
|
ISound::CVoiceHandle CSounds::PlaySampleAt(int Chn, int SampleId, float Vol, vec2 Pos, int Flags)
|
|
{
|
|
if((Chn == CHN_MUSIC && !g_Config.m_SndMusic) || SampleId == -1)
|
|
return ISound::CVoiceHandle();
|
|
|
|
if(Chn == CHN_MUSIC)
|
|
Flags |= ISound::FLAG_LOOP;
|
|
|
|
return Sound()->PlayAt(Chn, SampleId, Flags, Pos.x, Pos.y);
|
|
}
|