ddnet/src/game/client/components/sounds.cpp
heinrich5991 49bc150afd Refactor: Distinguish between two concepts previously called "Dummy"
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.
2022-01-21 01:54:14 +01:00

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);
}