Programming/vgui soundscape maker.cpp: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
m (made text for button on random sound panel show everything after the last / instead of the whole text and made sound panel combo box select the sound name that is in the 'sound text' text entry for the main panel when being opened)
(Added options panel for soundscape maker)
Line 29: Line 29:
#include <vgui/ISurface.h>
#include <vgui/ISurface.h>
#include <filesystem.h>
#include <filesystem.h>
#include <usermessages.h>
#include <fmtstr.h>
#include <fmtstr.h>


Line 174: Line 175:
}
}


//button
 
class CSoundscapeButton : public vgui::Button
//vector positions
Vector g_SoundscapePositions[] = {
vec3_origin,
vec3_origin,
vec3_origin,
vec3_origin,
vec3_origin,
vec3_origin,
vec3_origin,
};
 
#define SETTINGS_PANEL_WIDTH 350
#define SETTINGS_PANEL_HEIGHT 250
 
#define SETTINGS_PANEL_COMMAND_POS1 "GetPos0"
#define SETTINGS_PANEL_COMMAND_POS2 "GetPos1"
#define SETTINGS_PANEL_COMMAND_POS3 "GetPos2"
#define SETTINGS_PANEL_COMMAND_POS4 "GetPos3"
#define SETTINGS_PANEL_COMMAND_POS5 "GetPos4"
#define SETTINGS_PANEL_COMMAND_POS6 "GetPos5"
#define SETTINGS_PANEL_COMMAND_POS7 "GetPos6"
#define SETTINGS_PANEL_COMMAND_POS8 "GetPos7"
#define SETTINGS_PANEL_COMMAND_SHOW "ShowPositions"
 
#define MAX_SOUNDSCAPES 8
 
//soundscape maker settings panel
class CSoundscapeSettingsPanel : public vgui::Frame
{
{
public:
public:
DECLARE_CLASS_SIMPLE(CSoundscapeButton, vgui::Button)
DECLARE_CLASS_SIMPLE(CSoundscapeSettingsPanel, vgui::Frame);
 
CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name);


CSoundscapeButton(vgui::Panel* parent, const char* name, const char* text, vgui::Panel* target = nullptr, const char* command = nullptr)
//other
: BaseClass(parent, name, text, target, command), m_bIsSelected(false)
void OnCommand(const char* pszCommand);
{
m_ColorSelected = Color(200, 200, 200, 200);
m_FgColorSelected = Color(0, 0, 0, 255);
}


//apply scheme settings
//sets the text
void ApplySchemeSettings(vgui::IScheme* scheme)
void SetItem(int index, const Vector& value);
{
BaseClass::ApplySchemeSettings(scheme);


m_ColorNotSelected = GetButtonArmedBgColor();
//message funcs
m_FgColorNotSelectedd = GetButtonArmedFgColor();
MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);
}


//paints the background
private:
void PaintBackground()
//position text entries
{
vgui::TextEntry* m_TextEntryPos0;
if (m_bIsSelected)
vgui::TextEntry* m_TextEntryPos1;
SetBgColor(m_ColorSelected);
vgui::TextEntry* m_TextEntryPos2;
else
vgui::TextEntry* m_TextEntryPos3;
SetBgColor(m_ColorNotSelected);
vgui::TextEntry* m_TextEntryPos4;
vgui::TextEntry* m_TextEntryPos5;
vgui::TextEntry* m_TextEntryPos6;
vgui::TextEntry* m_TextEntryPos7;
vgui::CheckButton* m_ShowSoundscapePositions;


BaseClass::PaintBackground();
friend class CSoundscapeMaker;
}
//paints
void Paint()
{
if (m_bIsSelected)
SetFgColor(m_FgColorSelected);
else
SetFgColor(m_FgColorNotSelectedd);
BaseClass::Paint();
}
 
//is this selected or not
bool m_bIsSelected;
static Color m_ColorSelected;
static Color m_ColorNotSelected;
static Color m_FgColorSelected;
static Color m_FgColorNotSelectedd;
};
};


Color CSoundscapeButton::m_ColorSelected = Color();
Color CSoundscapeButton::m_ColorNotSelected = Color();
Color CSoundscapeButton::m_FgColorSelected = Color();
Color CSoundscapeButton::m_FgColorNotSelectedd = Color();


//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSoundscapeSettingsPanel::CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name)
: BaseClass(nullptr, name)
{
SetParent(parent);


//soundscape combo box
SetKeyBoardInputEnabled(true);
SetMouseInputEnabled(true);


class CSoundListComboBox : public vgui::ComboBox
SetProportional(false);
{
SetTitleBarVisible(true);
public:
SetMinimizeButtonVisible(false);
DECLARE_CLASS_SIMPLE(CSoundListComboBox, vgui::ComboBox);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(true);
SetSizeable(false);
SetMoveable(true);
SetVisible(false);


CSoundListComboBox(Panel* parent, const char* panelName, int numLines, bool allowEdit) :
//set the size and pos
BaseClass(parent, panelName, numLines, allowEdit) {}
int ScreenWide, ScreenTall;
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);


//on key typed. check for menu item with text inside it and if found then
SetTitle("Soundscape Maker Settings", true);
//select that item.
SetSize(SETTINGS_PANEL_WIDTH, SETTINGS_PANEL_HEIGHT);
void OnKeyTyped(wchar_t unichar)
SetPos((ScreenWide - SETTINGS_PANEL_WIDTH) / 2, (ScreenTall - SETTINGS_PANEL_HEIGHT) / 2);
{
//check for ctrl or shift down
if (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LCONTROL) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RCONTROL) || unichar == '`')
return;


//open up this combo box
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
if (unichar == 13)
{
ShowMenu();
return;
}


BaseClass::OnKeyTyped(unichar);
//create position text 1
m_TextEntryPos0 = new vgui::TextEntry(this, "PosTextEntry0");
m_TextEntryPos0->SetEnabled(true);
m_TextEntryPos0->SetText("0 0 0");
m_TextEntryPos0->SetBounds(5, 30, 230, 20);
m_TextEntryPos0->SetMaximumCharCount(32);


//check for backspace
//create position 1 button
if (unichar == 8 || unichar == '_')
vgui::Button* m_ButtonPos0 = new vgui::Button(this, "PosButton0", "Find Position 0", this, SETTINGS_PANEL_COMMAND_POS1);
return;
m_ButtonPos0->SetBounds(240, 30, 100, 20);
//create position text 1
m_TextEntryPos1 = new vgui::TextEntry(this, "PosTextEntry1");
m_TextEntryPos1->SetEnabled(true);
m_TextEntryPos1->SetText("0 0 0");
m_TextEntryPos1->SetBounds(5, 55, 230, 20);
m_TextEntryPos1->SetMaximumCharCount(32);


//get text
//create position 2 button
char buf[512];
vgui::Button* m_ButtonPos1 = new vgui::Button(this, "PosButton1", "Find Position 1", this, SETTINGS_PANEL_COMMAND_POS2);
GetText(buf, sizeof(buf));
m_ButtonPos1->SetBounds(240, 55, 100, 20);
//create position text 3
m_TextEntryPos2 = new vgui::TextEntry(this, "PosTextEntry0");
m_TextEntryPos2->SetEnabled(true);
m_TextEntryPos2->SetText("0 0 0");
m_TextEntryPos2->SetBounds(5, 80, 230, 20);
m_TextEntryPos2->SetMaximumCharCount(32);


//start from current index + 1
//create position 1 button
int start = GetMenu()->GetActiveItem() + 1;
vgui::Button* m_ButtonPos2 = new vgui::Button(this, "PosButton2", "Find Position 2", this, SETTINGS_PANEL_COMMAND_POS3);
m_ButtonPos2->SetBounds(240, 80, 100, 20);


//look for sound with same name starting from the start first
// create position text 4
for (int i = start; i < g_SoundDirectories.Count(); i++)
m_TextEntryPos3 = new vgui::TextEntry(this, "PosTextEntry3");
{
m_TextEntryPos3->SetEnabled(true);
if (Q_stristr(g_SoundDirectories[i], buf))
m_TextEntryPos3->SetText("0 0 0");
{
m_TextEntryPos3->SetBounds(5, 105, 230, 20);
GetMenu()->SetCurrentlyHighlightedItem(i);
m_TextEntryPos3->SetMaximumCharCount(32);
return;
}
}
//now cheeck from 0 to the start
for (int i = 0; i < start; i++)
{
if (Q_stristr(g_SoundDirectories[i], buf))
{
GetMenu()->SetCurrentlyHighlightedItem(i);
return;
}
}
}
};


// create position 4 button
vgui::Button* m_ButtonPos3 = new vgui::Button(this, "PosButton3", "Find Position 3", this, SETTINGS_PANEL_COMMAND_POS4);
m_ButtonPos3->SetBounds(240, 105, 100, 20);


//sounds list panel
// create position text 5
m_TextEntryPos4 = new vgui::TextEntry(this, "PosTextEntry4");
m_TextEntryPos4->SetEnabled(true);
m_TextEntryPos4->SetText("0 0 0");
m_TextEntryPos4->SetBounds(5, 130, 230, 20);
m_TextEntryPos4->SetMaximumCharCount(32);


#define SOUND_LIST_PANEL_WIDTH 375
// create position 5 button
#define SOUND_LIST_PANEL_HEIGHT 255
vgui::Button* m_ButtonPos4 = new vgui::Button(this, "PosButton4", "Find Position 4", this, SETTINGS_PANEL_COMMAND_POS5);
#define SOUND_LIST_PLAY_COMMAND "PlaySound"
m_ButtonPos4->SetBounds(240, 130, 100, 20);
#define SOUND_LIST_STOP_COMMAND "StopSound"
#define SOUND_LIST_INSERT_COMMAND "Insert"
#define SOUND_LIST_RELOAD_COMMAND "Reload"
#define SOUND_LIST_SEARCH_COMMAND "Search"


class CSoundListPanel : public vgui::Frame
// create position text 6
{
m_TextEntryPos5 = new vgui::TextEntry(this, "PosTextEntry5");
public:
m_TextEntryPos5->SetEnabled(true);
DECLARE_CLASS_SIMPLE(CSoundListPanel, vgui::Frame);
m_TextEntryPos5->SetText("0 0 0");
m_TextEntryPos5->SetBounds(5, 155, 230, 20);
m_TextEntryPos5->SetMaximumCharCount(32);


CSoundListPanel(vgui::VPANEL parent, const char* name);
// create position 6 button
vgui::Button* m_ButtonPos5 = new vgui::Button(this, "PosButton5", "Find Position 5", this, SETTINGS_PANEL_COMMAND_POS6);
m_ButtonPos5->SetBounds(240, 155, 100, 20);


//initalizes sound combo box
// create position text 7
void InitalizeSounds();
m_TextEntryPos6 = new vgui::TextEntry(this, "PosTextEntry6");
m_TextEntryPos6->SetEnabled(true);
m_TextEntryPos6->SetText("0 0 0");
m_TextEntryPos6->SetBounds(5, 180, 230, 20);
m_TextEntryPos6->SetMaximumCharCount(32);


//other
// create position 7 button
void OnCommand(const char* pszCommand);
vgui::Button* m_ButtonPos6 = new vgui::Button(this, "PosButton6", "Find Position 6", this, SETTINGS_PANEL_COMMAND_POS7);
void OnClose();
m_ButtonPos6->SetBounds(240, 180, 100, 20);
// create position text 8
m_TextEntryPos7 = new vgui::TextEntry(this, "PosTextEntry7");
m_TextEntryPos7->SetEnabled(true);
m_TextEntryPos7->SetText("0 0 0");
m_TextEntryPos7->SetBounds(5, 205, 230, 20);
m_TextEntryPos7->SetMaximumCharCount(32);


private:
// create position 8 button
friend class CSoundscapeMaker;
vgui::Button* m_ButtonPos7 = new vgui::Button(this, "PosButton7", "Find Position 7", this, SETTINGS_PANEL_COMMAND_POS8);
m_ButtonPos7->SetBounds(240, 205, 100, 20);


CSoundListComboBox* m_SoundsList;
// create show soundscape positions checkbox
vgui::TextEntry* m_SearchText;
m_ShowSoundscapePositions = new vgui::CheckButton(this, "ShowCheckox", "Show Soundscape Positions");
vgui::Button* m_SearchButton;
m_ShowSoundscapePositions->SetBounds(75, 225, 200, 20);
vgui::Button* m_PlayButton;
m_ShowSoundscapePositions->SetCommand(SETTINGS_PANEL_COMMAND_SHOW);
vgui::Button* m_StopSoundButton;
}
vgui::Button* m_InsertButton;
vgui::Button* m_ReloadSounds;
 
//current sound guid
int m_iSongGuid = -1;
};


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
// Purpose: Called on command
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CSoundListPanel::CSoundListPanel(vgui::VPANEL parent, const char* name)
void CSoundscapeSettingsPanel::OnCommand(const char* pszCommand)
: BaseClass(nullptr, name)
{
{
SetParent(parent);
if (Q_strstr(pszCommand, "GetPos") == pszCommand)
{
//search for number
pszCommand = pszCommand + 6;


SetKeyBoardInputEnabled(true);
//execute command
SetMouseInputEnabled(true);
static ConCommand* cc = cvar->FindCommand("__ss_maker_start");
if (cc)
{
//hide everything first
g_SoundscapeMaker->SetAllVisible(false);


SetProportional(false);
CCommand args;
SetTitleBarVisible(true);
args.Tokenize(CFmtStr("ssmaker %d", atoi(pszCommand)));
SetMinimizeButtonVisible(false);
cc->Dispatch(args);
SetMaximizeButtonVisible(false);
}
SetCloseButtonVisible(true);
SetSizeable(false);
SetMoveable(true);
SetVisible(false);


//set the size and pos
return;
int ScreenWide, ScreenTall;
}
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);
 
else if (!Q_strcmp(pszCommand, SETTINGS_PANEL_COMMAND_SHOW))
{
static ConVar* cv = cvar->FindVar("__ss_draw");
if (cv)
cv->SetValue(m_ShowSoundscapePositions->IsSelected());
 
return;
}


SetTitle("Sounds List", true);
BaseClass::OnCommand(pszCommand);
SetSize(SOUND_LIST_PANEL_WIDTH, SOUND_LIST_PANEL_HEIGHT);
}
SetPos((ScreenWide - SOUND_LIST_PANEL_WIDTH) / 2, (ScreenTall - SOUND_LIST_PANEL_HEIGHT) / 2);


SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
void CSoundscapeSettingsPanel::SetItem(int index, const Vector& value)
{
const char* text = CFmtStr("%.3f %.3f %.3f", value.x, value.y, value.z);


//create combo box
//check index
m_SoundsList = new CSoundListComboBox(this, "SoundsList", 20, true);
switch (index)
m_SoundsList->SetBounds(5, 25, SOUND_LIST_PANEL_WIDTH - 15, 20);
{
m_SoundsList->AddActionSignalTarget(this);
case 0:
m_TextEntryPos0->RequestFocus();
m_TextEntryPos0->SetText(text);
g_SoundscapePositions[0] = value;
break;
case 1:
m_TextEntryPos1->RequestFocus();
m_TextEntryPos1->SetText(text);
g_SoundscapePositions[1] = value;
break;
case 2:
m_TextEntryPos2->RequestFocus();
m_TextEntryPos2->SetText(text);
g_SoundscapePositions[2] = value;
break;
case 3:
m_TextEntryPos3->RequestFocus();
m_TextEntryPos3->SetText(text);
g_SoundscapePositions[3] = value;
break;
case 4:
m_TextEntryPos4->RequestFocus();
m_TextEntryPos4->SetText(text);
g_SoundscapePositions[4] = value;
break;
//make divider
case 5:
vgui::Divider* divider1 = new vgui::Divider(this, "Divider");
m_TextEntryPos5->RequestFocus();
divider1->SetBounds(-5, 48, SOUND_LIST_PANEL_WIDTH + 10, 2);
m_TextEntryPos5->SetText(text);
g_SoundscapePositions[5] = value;
break;


//create text
case 6:
vgui::Label* label1 = new vgui::Label(this, "FindSound", "Find Sound");
m_TextEntryPos6->RequestFocus();
label1->SetBounds(147, 51, 120, 20);
m_TextEntryPos6->SetText(text);
g_SoundscapePositions[6] = value;
break;


//create text entry
case 7:
m_SearchText = new vgui::TextEntry(this, "SearchTextEntry");
m_TextEntryPos7->RequestFocus();
m_SearchText->SetBounds(5, 75, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_TextEntryPos7->SetText(text);
m_SearchText->SetEnabled(true);
g_SoundscapePositions[7] = value;
m_SearchText->SetText("");
break;
}
}


//create search for button
//-----------------------------------------------------------------------------
m_SearchButton = new vgui::Button(this, "SearchButton", "Search For");
// Purpose: Called on text changed
m_SearchButton->SetBounds(5, 100, SOUND_LIST_PANEL_WIDTH - 15, 20);;
//-----------------------------------------------------------------------------
m_SearchButton->SetEnabled(true);
void CSoundscapeSettingsPanel::OnTextChanged(KeyValues* kv)
m_SearchButton->SetCommand(SOUND_LIST_SEARCH_COMMAND);
{
static ConCommand* cc = cvar->FindCommand("__ss_maker_set");


//make divider
//check focus
vgui::Divider* divider2 = new vgui::Divider(this, "Divider");
if (m_TextEntryPos0->HasFocus())
divider2->SetBounds(-5, 124, SOUND_LIST_PANEL_WIDTH + 10, 2);
{
//get text
char buf[512];
m_TextEntryPos0->GetText(buf, sizeof(buf));


//create text
//convert to vector
vgui::Label* label2 = new vgui::Label(this, "SoundButtons", "Sound Buttons");
UTIL_StringToVector(g_SoundscapePositions[0].Base(), buf);
label2->SetBounds(140, 127, 120, 20);


//create play button
//do command
m_PlayButton = new vgui::Button(this, "PlayButton", "Play Sound", this);
if (cc)
m_PlayButton ->SetBounds(5, 150, SOUND_LIST_PANEL_WIDTH - 15, 20);
{
m_PlayButton->SetCommand(SOUND_LIST_PLAY_COMMAND);
CCommand args;
args.Tokenize(CFmtStr("ssmaker 0 %s", buf));
cc->Dispatch(args);
}


//create stop sound button
return;
m_StopSoundButton = new vgui::Button(this, "StopSound", "Stop Sound", this);
}
m_StopSoundButton ->SetBounds(5, 175, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_StopSoundButton->SetCommand(SOUND_LIST_STOP_COMMAND);


//create sound insert button
//check focus
m_InsertButton = new vgui::Button(this, "InsertSound", "Insert Sound", this);
if (m_TextEntryPos1->HasFocus())
m_InsertButton ->SetBounds(5, 200, SOUND_LIST_PANEL_WIDTH - 15, 20);
{
m_InsertButton->SetCommand(SOUND_LIST_INSERT_COMMAND);
//get text
char buf[512];
m_TextEntryPos1->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[1].Base(), buf);
 
//do command
if (cc)
{
CCommand args;
args.Tokenize(CFmtStr("ssmaker 1 %s", buf));
cc->Dispatch(args);
}


//create reload sounds button
return;
m_ReloadSounds = new vgui::Button(this, "ReloadSounds", "Reload Sounds", this);
}
m_ReloadSounds ->SetBounds(5, 225, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_ReloadSounds->SetCommand(SOUND_LIST_RELOAD_COMMAND);
}


//-----------------------------------------------------------------------------
//check focus
// Purpose: Called on command
if (m_TextEntryPos2->HasFocus())
//-----------------------------------------------------------------------------
void CSoundListPanel::OnCommand(const char* pszCommand)
{
if (!Q_strcmp(pszCommand, SOUND_LIST_SEARCH_COMMAND))
{
{
//get text
//get text
char buf[512];
char buf[512];
m_SearchText->GetText(buf, sizeof(buf));
m_TextEntryPos2->GetText(buf, sizeof(buf));


//start from current index + 1
//convert to vector
int start = m_SoundsList->GetMenu()->GetActiveItem() + 1;
UTIL_StringToVector(g_SoundscapePositions[2].Base(), buf);


//look for sound with same name starting from the start first
//do command
for (int i = start; i < g_SoundDirectories.Count(); i++)
if (cc)
{
{
if (Q_stristr(g_SoundDirectories[i], buf))
CCommand args;
{
args.Tokenize(CFmtStr("ssmaker 2 %s", buf));
//select item
cc->Dispatch(args);
m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
m_SoundsList->ActivateItem(i);
 
//set text
m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
return;
}
}
}


return;
}


//now cheeck from 0 to the start
//check focus
for (int i = 0; i < start; i++)
if (m_TextEntryPos3->HasFocus())
{
//get text
char buf[512];
m_TextEntryPos3->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[3].Base(), buf);
 
//do command
if (cc)
{
{
if (Q_stristr(g_SoundDirectories[i], buf))
CCommand args;
{
args.Tokenize(CFmtStr("ssmaker 3 %s", buf));
//select item
cc->Dispatch(args);
m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
m_SoundsList->ActivateItem(i);
//set text
m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
return;
}
}
}


return;
return;
}
}
else if (!Q_strcmp(pszCommand, SOUND_LIST_PLAY_COMMAND))  
 
//check focus
if (m_TextEntryPos4->HasFocus())
{
{
//get the sound
//get text
char buf[512];
char buf[512];
m_SoundsList->GetText(buf, sizeof(buf));
m_TextEntryPos4->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[4].Base(), buf);


//stop the sound
//do command
if (enginesound->IsSoundStillPlaying(m_iSongGuid))
if (cc)
{
{
enginesound->StopSoundByGuid(m_iSongGuid);
CCommand args;
m_iSongGuid = -1;
args.Tokenize(CFmtStr("ssmaker 4 %s", buf));
cc->Dispatch(args);
}
}


//precache and play the sound
if (!enginesound->IsSoundPrecached(buf))
enginesound->PrecacheSound(buf);
enginesound->EmitAmbientSound(buf, 1, 100);
m_iSongGuid = enginesound->GetGuidForLastSoundEmitted();
return;
return;
}
}
else if (!Q_strcmp(pszCommand, SOUND_LIST_STOP_COMMAND))  
 
//check focus
if (m_TextEntryPos5->HasFocus())
{
{
//stop the sound
//get text
if (m_iSongGuid != -1 && enginesound->IsSoundStillPlaying(m_iSongGuid))
char buf[512];
m_TextEntryPos5->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[5].Base(), buf);
 
//do command
if (cc)
{
{
enginesound->StopSoundByGuid(m_iSongGuid);
CCommand args;
m_iSongGuid = -1;
args.Tokenize(CFmtStr("ssmaker 5 %s", buf));
cc->Dispatch(args);
}
}


return;
return;
}
}
else if (!Q_strcmp(pszCommand, SOUND_LIST_INSERT_COMMAND))
 
//check focus
if (m_TextEntryPos6->HasFocus())
{
{
//make not visible
//get text
SetVisible(false);
char buf[512];
m_TextEntryPos6->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[6].Base(), buf);


//stop the sound
//do command
if (enginesound->IsSoundStillPlaying(m_iSongGuid))
if (cc)
{
{
enginesound->StopSoundByGuid(m_iSongGuid);
CCommand args;
m_iSongGuid = -1;
args.Tokenize(CFmtStr("ssmaker 6 %s", buf));
cc->Dispatch(args);
}
}


//get the sound
char buf[512];
m_SoundsList->GetText(buf, sizeof(buf));
//set the sound text
g_SoundscapeMaker->SetSoundText(buf);
return;
return;
}
}
else if (!Q_strcmp(pszCommand, SOUND_LIST_RELOAD_COMMAND))
 
//check focus
if (m_TextEntryPos7->HasFocus())
{
{
//clear everything for the combo box and reload it
//get text
m_SoundsList->RemoveAll();
char buf[512];
m_TextEntryPos7->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[7].Base(), buf);
 
//do command
if (cc)
{
CCommand args;
args.Tokenize(CFmtStr("ssmaker 7 %s", buf));
cc->Dispatch(args);
}


InitalizeSounds();
return;
return;
}
}


BaseClass::OnCommand(pszCommand);
}
}


//-----------------------------------------------------------------------------
//static soundscape settings panel
// Purpose: Called on panel close
static CSoundscapeSettingsPanel* g_SettingsPanel = nullptr;
//-----------------------------------------------------------------------------
 
void CSoundListPanel::OnClose()
 
//button
class CSoundscapeButton : public vgui::Button
{
{
OnCommand(SOUND_LIST_STOP_COMMAND);
public:
BaseClass::OnClose();
DECLARE_CLASS_SIMPLE(CSoundscapeButton, vgui::Button)
}


//-----------------------------------------------------------------------------
CSoundscapeButton(vgui::Panel* parent, const char* name, const char* text, vgui::Panel* target = nullptr, const char* command = nullptr)
// Purpose: Initalizes the sounds list
: BaseClass(parent, name, text, target, command), m_bIsSelected(false)  
//-----------------------------------------------------------------------------
{
void CSoundListPanel::InitalizeSounds()
m_ColorSelected = Color(200, 200, 200, 200);
{
m_FgColorSelected = Color(0, 0, 0, 255);
//get the sound array
}
GetSoundNames();


//add all the sounds
//apply scheme settings
for (int i = 0; i < g_SoundDirectories.Size(); i++)
void ApplySchemeSettings(vgui::IScheme* scheme)
m_SoundsList->AddItem(g_SoundDirectories[i], nullptr);
{
BaseClass::ApplySchemeSettings(scheme);


m_SoundsList->ActivateItem(0);
m_ColorNotSelected = GetButtonArmedBgColor();
}
m_FgColorNotSelectedd = GetButtonArmedFgColor();
}


//static sound list instance
//paints the background
static CSoundListPanel* g_SoundPanel = nullptr;
void PaintBackground()
static bool g_SoundPanelInitalized = false;
{
if (m_bIsSelected)
SetBgColor(m_ColorSelected);
else
SetBgColor(m_ColorNotSelected);


BaseClass::PaintBackground();
}
//paints
void Paint()
{
if (m_bIsSelected)
SetFgColor(m_FgColorSelected);
else
SetFgColor(m_FgColorNotSelectedd);
BaseClass::Paint();
}


//soundscape list
//is this selected or not
bool m_bIsSelected;
static Color m_ColorSelected;
static Color m_ColorNotSelected;
static Color m_FgColorSelected;
static Color m_FgColorNotSelectedd;
};


Color CSoundscapeButton::m_ColorSelected = Color();
Color CSoundscapeButton::m_ColorNotSelected = Color();
Color CSoundscapeButton::m_FgColorSelected = Color();
Color CSoundscapeButton::m_FgColorNotSelectedd = Color();


#define ADD_SOUNDSCAPE_COMMAND "AddSoundscape"


//soundscape combo box


//soundscape list class
class CSoundListComboBox : public vgui::ComboBox
class CSoundscapeList : public vgui::Divider
{
{
public:
public:
DECLARE_CLASS_SIMPLE(CSoundscapeList, vgui::Divider);
DECLARE_CLASS_SIMPLE(CSoundListComboBox, vgui::ComboBox);


//constructor
CSoundListComboBox(Panel* parent, const char* panelName, int numLines, bool allowEdit) :
CSoundscapeList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height);
BaseClass(parent, panelName, numLines, allowEdit) {}


//menu item stuff
//on key typed. check for menu item with text inside it and if found then
virtual void AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent);
//select that item.
virtual void Clear();
void OnKeyTyped(wchar_t unichar)
{
//check for ctrl or shift down
if (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LCONTROL) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RCONTROL) || unichar == '`')
return;


//other
//open up this combo box
virtual void OnMouseWheeled(int delta);
if (unichar == 13)
virtual void OnMouseReleased(vgui::MouseCode code);
{
ShowMenu();
return;
}


virtual void OnCommand(const char* pszCommand);
BaseClass::OnKeyTyped(unichar);
virtual void PaintBackground();


//message funcs
//check for backspace
MESSAGE_FUNC_INT(ScrollBarMoved, "ScrollBarSliderMoved", position);
if (unichar == 8 || unichar == '_')
return;


protected:
//get text
friend class CSoundscapeMaker;
char buf[512];
GetText(buf, sizeof(buf));


//keyvalue list.
//start from current index + 1
KeyValues* m_Keyvalues;
int start = GetMenu()->GetActiveItem() + 1;
 
//look for sound with same name starting from the start first
for (int i = start; i < g_SoundDirectories.Count(); i++)
{
if (Q_stristr(g_SoundDirectories[i], buf))
{
GetMenu()->SetCurrentlyHighlightedItem(i);
return;
}
}
//now cheeck from 0 to the start
for (int i = 0; i < start; i++)
{
if (Q_stristr(g_SoundDirectories[i], buf))
{
GetMenu()->SetCurrentlyHighlightedItem(i);
return;
}
}
}
};


//says "Soundscapes List"
vgui::Label* m_pLabel;
vgui::ScrollBar* m_pSideSlider;


//menu
//sounds list panel
vgui::Menu* menu;


//menu button stuff
#define SOUND_LIST_PANEL_WIDTH 375
CUtlVector<CSoundscapeButton*> m_MenuButtons;
#define SOUND_LIST_PANEL_HEIGHT 255
int m_iCurrentY;
#define SOUND_LIST_PLAY_COMMAND "PlaySound"
int m_iMax;
#define SOUND_LIST_STOP_COMMAND "StopSound"
int m_AmtAdded;
#define SOUND_LIST_INSERT_COMMAND "Insert"
};
#define SOUND_LIST_RELOAD_COMMAND "Reload"
#define SOUND_LIST_SEARCH_COMMAND "Search"


//-----------------------------------------------------------------------------
class CSoundListPanel : public vgui::Frame
// Purpose: Constructor for soundscape list panel
//-----------------------------------------------------------------------------
CSoundscapeList::CSoundscapeList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
: BaseClass(parent, name)
{
{
//create the text
public:
m_pLabel = new vgui::Label(this, "ListsText", text);
DECLARE_CLASS_SIMPLE(CSoundListPanel, vgui::Frame);
m_pLabel->SetVisible(true);
m_pLabel->SetBounds(text_x_pos, 2, 150, 20);


//create the side slider
CSoundListPanel(vgui::VPANEL parent, const char* name);
m_pSideSlider = new vgui::ScrollBar(this, "ListsSlider", true);
m_pSideSlider->SetBounds(width - 20, 0, 20, height - 2);
m_pSideSlider->SetValue(0);
m_pSideSlider->SetEnabled(false);
m_pSideSlider->SetRange(0, 0);
m_pSideSlider->SetButtonPressedScrollValue(1);
m_pSideSlider->SetRangeWindow(0);
m_pSideSlider->AddActionSignalTarget(this);


m_iCurrentY = 22;
//initalizes sound combo box
m_iMax = max;
void InitalizeSounds();
m_Keyvalues = nullptr;
 
}
//other
void OnCommand(const char* pszCommand);
void OnClose();
 
private:
friend class CSoundscapeMaker;
 
CSoundListComboBox* m_SoundsList;
vgui::TextEntry* m_SearchText;
vgui::Button* m_SearchButton;
vgui::Button* m_PlayButton;
vgui::Button* m_StopSoundButton;
vgui::Button* m_InsertButton;
vgui::Button* m_ReloadSounds;
 
//current sound guid
int m_iSongGuid = -1;
};


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: adds a button to the soundscape list
// Purpose: Constructor
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeList::AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent)
CSoundListPanel::CSoundListPanel(vgui::VPANEL parent, const char* name)
: BaseClass(nullptr, name)
{
{
//create a new button
SetParent(parent);
CSoundscapeButton* button = new CSoundscapeButton(this, name, text, parent, command);
button->SetBounds(5, m_iCurrentY, GetWide() - 30, 20);


//increment current y
SetKeyBoardInputEnabled(true);
m_iCurrentY = m_iCurrentY + 22;
SetMouseInputEnabled(true);


//add button to array
SetProportional(false);
m_MenuButtons.AddToTail(button);
SetTitleBarVisible(true);
SetMinimizeButtonVisible(false);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(true);
SetSizeable(false);
SetMoveable(true);
SetVisible(false);


//if the count is more then m_iMax then set slider value
//set the size and pos
if (m_MenuButtons.Count() > m_iMax)
int ScreenWide, ScreenTall;
{
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);
int max = m_MenuButtons.Count() - m_iMax;


m_pSideSlider->SetRange(0, max);
SetTitle("Sounds List", true);
m_pSideSlider->SetRangeWindow(1);
SetSize(SOUND_LIST_PANEL_WIDTH, SOUND_LIST_PANEL_HEIGHT);
m_pSideSlider->SetEnabled(true);
SetPos((ScreenWide - SOUND_LIST_PANEL_WIDTH) / 2, (ScreenTall - SOUND_LIST_PANEL_HEIGHT) / 2);
}


m_AmtAdded++;
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));


//check to see if we need to scroll down
//create combo box
if (m_MenuButtons.Count() >= m_iMax)
m_SoundsList = new CSoundListComboBox(this, "SoundsList", 20, true);
OnMouseWheeled(-1);
m_SoundsList->SetBounds(5, 25, SOUND_LIST_PANEL_WIDTH - 15, 20);
}
m_SoundsList->AddActionSignalTarget(this);
//make divider
vgui::Divider* divider1 = new vgui::Divider(this, "Divider");
divider1->SetBounds(-5, 48, SOUND_LIST_PANEL_WIDTH + 10, 2);


//-----------------------------------------------------------------------------
//create text
// Purpose: Clears everything for this list
vgui::Label* label1 = new vgui::Label(this, "FindSound", "Find Sound");
//-----------------------------------------------------------------------------
label1->SetBounds(147, 51, 120, 20);
void CSoundscapeList::Clear()
{
//reset the slider
m_pSideSlider->SetValue(0);
m_pSideSlider->SetEnabled(false);
m_pSideSlider->SetRange(0, 0);
m_pSideSlider->SetButtonPressedScrollValue(1);
m_pSideSlider->SetRangeWindow(0);


//delete and clear the buttons
//create text entry
for (int i = 0; i < m_MenuButtons.Count(); i++)
m_SearchText = new vgui::TextEntry(this, "SearchTextEntry");
m_MenuButtons[i]->DeletePanel();
m_SearchText->SetBounds(5, 75, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_SearchText->SetEnabled(true);
m_SearchText->SetText("");


m_MenuButtons.RemoveAll();
//create search for button
m_SearchButton = new vgui::Button(this, "SearchButton", "Search For");
m_SearchButton->SetBounds(5, 100, SOUND_LIST_PANEL_WIDTH - 15, 20);;
m_SearchButton->SetEnabled(true);
m_SearchButton->SetCommand(SOUND_LIST_SEARCH_COMMAND);


//reset current y
//make divider
m_iCurrentY = 22;
vgui::Divider* divider2 = new vgui::Divider(this, "Divider");
divider2->SetBounds(-5, 124, SOUND_LIST_PANEL_WIDTH + 10, 2);


m_AmtAdded = 0;
//create text
}
vgui::Label* label2 = new vgui::Label(this, "SoundButtons", "Sound Buttons");
label2->SetBounds(140, 127, 120, 20);


//-----------------------------------------------------------------------------
//create play button
// Purpose: Called when a mouse is wheeled
m_PlayButton = new vgui::Button(this, "PlayButton", "Play Sound", this);
//-----------------------------------------------------------------------------
m_PlayButton ->SetBounds(5, 150, SOUND_LIST_PANEL_WIDTH - 15, 20);
void CSoundscapeList::OnMouseWheeled(int delta)
m_PlayButton->SetCommand(SOUND_LIST_PLAY_COMMAND);
{
 
//check for scroll down
//create stop sound button
if (delta == -1)
m_StopSoundButton = new vgui::Button(this, "StopSound", "Stop Sound", this);
m_pSideSlider->SetValue(m_pSideSlider->GetValue() + 1);
m_StopSoundButton ->SetBounds(5, 175, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_StopSoundButton->SetCommand(SOUND_LIST_STOP_COMMAND);
 
//create sound insert button
m_InsertButton = new vgui::Button(this, "InsertSound", "Insert Sound", this);
m_InsertButton ->SetBounds(5, 200, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_InsertButton->SetCommand(SOUND_LIST_INSERT_COMMAND);


//check for scroll up
//create reload sounds button
else if (delta == 1)
m_ReloadSounds = new vgui::Button(this, "ReloadSounds", "Reload Sounds", this);
m_pSideSlider->SetValue(m_pSideSlider->GetValue() - 1);
m_ReloadSounds ->SetBounds(5, 225, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_ReloadSounds->SetCommand(SOUND_LIST_RELOAD_COMMAND);
}
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Called when a mouse code is released
// Purpose: Called on command
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeList::OnMouseReleased(vgui::MouseCode code)
void CSoundListPanel::OnCommand(const char* pszCommand)
{
{
if (code != vgui::MouseCode::MOUSE_RIGHT)
if (!Q_strcmp(pszCommand, SOUND_LIST_SEARCH_COMMAND))
return;
{
//get text
char buf[512];
m_SearchText->GetText(buf, sizeof(buf));


//get cursor pos
//start from current index + 1
int x, y;
int start = m_SoundsList->GetMenu()->GetActiveItem() + 1;
vgui::surface()->SurfaceGetCursorPos(x, y);


//create menu
//look for sound with same name starting from the start first
menu = new vgui::Menu(this, "Menu");
for (int i = start; i < g_SoundDirectories.Count(); i++)
menu->AddMenuItem("AddSoundscape", "Add Soundscape", ADD_SOUNDSCAPE_COMMAND, this);
{
menu->SetBounds(x, y, 200, 50);
if (Q_stristr(g_SoundDirectories[i], buf))
menu->SetVisible(true);
{
}
//select item
m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
m_SoundsList->ActivateItem(i);


//-----------------------------------------------------------------------------
//set text
// Purpose: Called on command
m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
//-----------------------------------------------------------------------------
return;
void CSoundscapeList::OnCommand(const char* pszCommand)
}
{
}
if (!Q_strcmp(pszCommand, ADD_SOUNDSCAPE_COMMAND))
{
const char* name = CFmtStr("New Soundscape %d", m_AmtAdded);
AddButton(name, name, name, GetParent());


//add to keyvalues file
KeyValues* kv = new KeyValues(name);
KeyValues* tmp = m_Keyvalues;
KeyValues* tmp2 = tmp;


//get last subkey
//now cheeck from 0 to the start
while (tmp != nullptr)
for (int i = 0; i < start; i++)
{
{
tmp2 = tmp;
if (Q_stristr(g_SoundDirectories[i], buf))
tmp = tmp->GetNextTrueSubKey();
{
//select item
m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
m_SoundsList->ActivateItem(i);
//set text
m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
return;
}
}
}


//add to last subkey
tmp2->SetNextKey(kv);
GetParent()->OnCommand(name);
return;
return;
}
}
else if (!Q_strcmp(pszCommand, SOUND_LIST_PLAY_COMMAND))
{
//get the sound
char buf[512];
m_SoundsList->GetText(buf, sizeof(buf));


BaseClass::OnCommand(pszCommand);
//stop the sound
}
if (enginesound->IsSoundStillPlaying(m_iSongGuid))
{
enginesound->StopSoundByGuid(m_iSongGuid);
m_iSongGuid = -1;
}


//-----------------------------------------------------------------------------
//precache and play the sound
// Purpose: Paints the background
if (!enginesound->IsSoundPrecached(buf))
//-----------------------------------------------------------------------------
enginesound->PrecacheSound(buf);
void CSoundscapeList::PaintBackground()
{
enginesound->EmitAmbientSound(buf, 1, 100);
//colors
m_iSongGuid = enginesound->GetGuidForLastSoundEmitted();
static Color EnabledColor = Color(100, 100, 100, 200);
return;
static Color DisabledColor = Color(60, 60, 60, 200);
}
else if (!Q_strcmp(pszCommand, SOUND_LIST_STOP_COMMAND))
{
//stop the sound
if (m_iSongGuid != -1 && enginesound->IsSoundStillPlaying(m_iSongGuid))
{
enginesound->StopSoundByGuid(m_iSongGuid);
m_iSongGuid = -1;
}


//if m_KeyValues then paint the default color
return;
if (m_Keyvalues)
}
SetBgColor(EnabledColor);
else if (!Q_strcmp(pszCommand, SOUND_LIST_INSERT_COMMAND))
else
{
SetBgColor(DisabledColor);
//make not visible
SetVisible(false);


BaseClass::PaintBackground();
//stop the sound
}
if (enginesound->IsSoundStillPlaying(m_iSongGuid))
 
//-----------------------------------------------------------------------------
// Purpose: Called on scroll bar moved
//-----------------------------------------------------------------------------
void CSoundscapeList::ScrollBarMoved(int delta)
{
int position = m_pSideSlider->GetValue();
 
//move everything down (if needed)
for (int i = 0; i < m_MenuButtons.Count(); i++)
{
//make not visible if i < position
if (i < position)
{
{
m_MenuButtons[i]->SetVisible(false);
enginesound->StopSoundByGuid(m_iSongGuid);
continue;
m_iSongGuid = -1;
}
}


m_MenuButtons[i]->SetPos(5, 22 * ((i - position) + 1));
//get the sound
m_MenuButtons[i]->SetVisible(true);
char buf[512];
m_SoundsList->GetText(buf, sizeof(buf));
 
//set the sound text
g_SoundscapeMaker->SetSoundText(buf);
return;
}
}
}
else if (!Q_strcmp(pszCommand, SOUND_LIST_RELOAD_COMMAND))
{
//clear everything for the combo box and reload it
m_SoundsList->RemoveAll();


InitalizeSounds();
return;
}


BaseClass::OnCommand(pszCommand);
}


//-----------------------------------------------------------------------------
// Purpose: Called on panel close
//-----------------------------------------------------------------------------
void CSoundListPanel::OnClose()
{
OnCommand(SOUND_LIST_STOP_COMMAND);
BaseClass::OnClose();
}


//soundscape data list
//-----------------------------------------------------------------------------
 
// Purpose: Initalizes the sounds list
//-----------------------------------------------------------------------------
void CSoundListPanel::InitalizeSounds()
{
//get the sound array
GetSoundNames();


#define NEW_PLAYLOOPING_COMMAND "NewLooping"
//add all the sounds
#define NEW_SOUNDSCAPE_COMMAND "NewSoundscape"
for (int i = 0; i < g_SoundDirectories.Size(); i++)
#define NEW_RANDOM_COMMAND "NewRandom"
m_SoundsList->AddItem(g_SoundDirectories[i], nullptr);


m_SoundsList->ActivateItem(0);
}


class CSoundscapeDataList : public CSoundscapeList
//static sound list instance
{
static CSoundListPanel* g_SoundPanel = nullptr;
public:
static bool g_SoundPanelInitalized = false;
DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
CSoundscapeDataList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
: CSoundscapeList(parent, name, text, text_x_pos, max, width, height)
{}


//override right click functionality
virtual void OnMouseReleased(vgui::MouseCode code);


void OnCommand(const char* pszCommand);
//soundscape list


private:
 
friend class CSoundscapeMaker;
#define ADD_SOUNDSCAPE_COMMAND "AddSoundscape"
};




//-----------------------------------------------------------------------------
//soundscape list class
// Purpose: Called when a mouse code is released
class CSoundscapeList : public vgui::Divider
//-----------------------------------------------------------------------------
void CSoundscapeDataList::OnMouseReleased(vgui::MouseCode code)
{
{
//if no soundscape is selected or mouse code != right then return
public:
if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
DECLARE_CLASS_SIMPLE(CSoundscapeList, vgui::Divider);
return;


//get cursor pos
//constructor
int x, y;
CSoundscapeList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height);
vgui::surface()->SurfaceGetCursorPos(x, y);


//create menu
//menu item stuff
menu = new vgui::Menu(this, "Menu");
virtual void AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent);
menu->AddMenuItem("AddLooping", "Add Looping Sound", NEW_PLAYLOOPING_COMMAND, this);
virtual void Clear();
menu->AddMenuItem("AddSoundscape", "Add Soundscape", NEW_SOUNDSCAPE_COMMAND, this);
menu->AddMenuItem("AddSoundscape", "Add Random Sounds", NEW_RANDOM_COMMAND, this);
menu->SetBounds(x, y, 200, 50);
menu->SetVisible(true);
}


//other
virtual void OnMouseWheeled(int delta);
virtual void OnMouseReleased(vgui::MouseCode code);


//-----------------------------------------------------------------------------
virtual void OnCommand(const char* pszCommand);
// Purpose: Called on command
virtual void PaintBackground();
//-----------------------------------------------------------------------------
void CSoundscapeDataList::OnCommand(const char* pszCommand)
{
if (!Q_strcmp(pszCommand, NEW_PLAYLOOPING_COMMAND))
{
int LoopingNum = 0;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
{
//store data name
const char* name = data->GetName();


//increment variables based on name
//message funcs
if (!Q_strcasecmp(name, "playlooping"))
MESSAGE_FUNC_INT(ScrollBarMoved, "ScrollBarSliderMoved", position);
LoopingNum++;
}


//add the keyvalue to both this and the keyvalues
protected:
AddButton("playlooping", "playlooping", CFmtStr("$playlooping%d", LoopingNum + 1), GetParent());
friend class CSoundscapeMaker;


//add the keyvalues
//keyvalue list.
KeyValues* kv = new KeyValues("playlooping");
KeyValues* m_Keyvalues;
kv->SetFloat("volume", 1);
kv->SetInt("pitch", 100);


m_Keyvalues->AddSubKey(kv);
//says "Soundscapes List"
vgui::Label* m_pLabel;
vgui::ScrollBar* m_pSideSlider;


GetParent()->OnCommand(CFmtStr("$playlooping%d", LoopingNum + 1));
//menu
vgui::Menu* menu;


return;
//menu button stuff
}
CUtlVector<CSoundscapeButton*> m_MenuButtons;
else if (!Q_strcmp(pszCommand, NEW_SOUNDSCAPE_COMMAND))
int m_iCurrentY;
{
int m_iMax;
int SoundscapeNum = 0;
int m_AmtAdded;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
};
{
//store data name
const char* name = data->GetName();


//increment variables based on name
//-----------------------------------------------------------------------------
if (!Q_strcasecmp(name, "playsoundscape"))
// Purpose: Constructor for soundscape list panel
SoundscapeNum++;
//-----------------------------------------------------------------------------
}
CSoundscapeList::CSoundscapeList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
: BaseClass(parent, name)
{
//create the text
m_pLabel = new vgui::Label(this, "ListsText", text);
m_pLabel->SetVisible(true);
m_pLabel->SetBounds(text_x_pos, 2, 150, 20);


AddButton("playsoundscape", "playsoundscape", CFmtStr("$playsoundscape%d", SoundscapeNum + 1), GetParent());
//create the side slider
m_pSideSlider = new vgui::ScrollBar(this, "ListsSlider", true);
m_pSideSlider->SetBounds(width - 20, 0, 20, height - 2);
m_pSideSlider->SetValue(0);
m_pSideSlider->SetEnabled(false);
m_pSideSlider->SetRange(0, 0);
m_pSideSlider->SetButtonPressedScrollValue(1);
m_pSideSlider->SetRangeWindow(0);
m_pSideSlider->AddActionSignalTarget(this);


//add the keyvalues
m_iCurrentY = 22;
KeyValues* kv = new KeyValues("playsoundscape");
m_iMax = max;
kv->SetFloat("volume", 1);
m_Keyvalues = nullptr;
}
 
//-----------------------------------------------------------------------------
// Purpose: adds a button to the soundscape list
//-----------------------------------------------------------------------------
void CSoundscapeList::AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent)
{
//create a new button
CSoundscapeButton* button = new CSoundscapeButton(this, name, text, parent, command);
button->SetBounds(5, m_iCurrentY, GetWide() - 30, 20);


//add the keyvalue to both this and the keyvalues
//increment current y
m_Keyvalues->AddSubKey(kv);
m_iCurrentY = m_iCurrentY + 22;


GetParent()->OnCommand(CFmtStr("$playsoundscape%d", SoundscapeNum + 1));
//add button to array
m_MenuButtons.AddToTail(button);


return;
//if the count is more then m_iMax then set slider value
}
if (m_MenuButtons.Count() > m_iMax)
else if (!Q_strcmp(pszCommand, NEW_RANDOM_COMMAND))
{
{
int RandomNum = 0;
int max = m_MenuButtons.Count() - m_iMax;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
{
//store data name
const char* name = data->GetName();


//increment variables based on name
m_pSideSlider->SetRange(0, max);
if (!Q_strcasecmp(name, "playrandom"))
m_pSideSlider->SetRangeWindow(1);
RandomNum++;
m_pSideSlider->SetEnabled(true);
}
}


AddButton("playrandom", "playrandom", CFmtStr("$playrandom%d", RandomNum + 1), GetParent());
m_AmtAdded++;


//add the keyvalues
//check to see if we need to scroll down
KeyValues* kv = new KeyValues("playrandom");
if (m_MenuButtons.Count() >= m_iMax)
kv->SetString("volume", "0.5,0.8");
OnMouseWheeled(-1);
kv->SetInt("pitch", 100);
kv->SetString("time", "10,20");
//make rndwave subkey
KeyValues* rndwave = new KeyValues("rndwave");
kv->AddSubKey(rndwave);
 
//add the keyvalue to both this and the keyvalues
m_Keyvalues->AddSubKey(kv);
 
//make the parent show the new item
GetParent()->OnCommand(CFmtStr("$playrandom%d", RandomNum + 1));
 
return;
}
 
BaseClass::OnCommand(pszCommand);
}
}


//-----------------------------------------------------------------------------
// Purpose: Clears everything for this list
//-----------------------------------------------------------------------------
void CSoundscapeList::Clear()
{
//reset the slider
m_pSideSlider->SetValue(0);
m_pSideSlider->SetEnabled(false);
m_pSideSlider->SetRange(0, 0);
m_pSideSlider->SetButtonPressedScrollValue(1);
m_pSideSlider->SetRangeWindow(0);


//soundscape rndwave data list
//delete and clear the buttons
 
for (int i = 0; i < m_MenuButtons.Count(); i++)
m_MenuButtons[i]->DeletePanel();


#define NEW_RNDWAVE_WAVE_COMMAND "NewRNDWave"
m_MenuButtons.RemoveAll();


//reset current y
m_iCurrentY = 22;


class CSoundscapeRndwaveList : public CSoundscapeList
m_AmtAdded = 0;
{
}
public:
DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
CSoundscapeRndwaveList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
: CSoundscapeList(parent, name, text, text_x_pos, max, width, height)
{}
 
//override right click functionality
virtual void OnMouseReleased(vgui::MouseCode code);
 
void OnCommand(const char* pszCommand);
 
private:
friend class CSoundscapeMaker;
};
 


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Called when a mouse code is released
// Purpose: Called when a mouse is wheeled
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeRndwaveList::OnMouseReleased(vgui::MouseCode code)
void CSoundscapeList::OnMouseWheeled(int delta)
{
{
//if no soundscape is selected or mouse code != right then return
//check for scroll down
if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
if (delta == -1)
m_pSideSlider->SetValue(m_pSideSlider->GetValue() + 1);
 
//check for scroll up
else if (delta == 1)
m_pSideSlider->SetValue(m_pSideSlider->GetValue() - 1);
}
 
//-----------------------------------------------------------------------------
// Purpose: Called when a mouse code is released
//-----------------------------------------------------------------------------
void CSoundscapeList::OnMouseReleased(vgui::MouseCode code)
{
if (code != vgui::MouseCode::MOUSE_RIGHT)
return;
return;


Line 981: Line 1,177:
//create menu
//create menu
menu = new vgui::Menu(this, "Menu");
menu = new vgui::Menu(this, "Menu");
menu->AddMenuItem("AddRandom", "Add Random Wave", NEW_RNDWAVE_WAVE_COMMAND, this);
menu->AddMenuItem("AddSoundscape", "Add Soundscape", ADD_SOUNDSCAPE_COMMAND, this);
menu->SetBounds(x, y, 200, 50);
menu->SetBounds(x, y, 200, 50);
menu->SetVisible(true);
menu->SetVisible(true);
}
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Called on command
// Purpose: Called on command
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeRndwaveList::OnCommand(const char* pszCommand)
void CSoundscapeList::OnCommand(const char* pszCommand)
{
{
if (!Q_strcmp(pszCommand, NEW_RNDWAVE_WAVE_COMMAND))
if (!Q_strcmp(pszCommand, ADD_SOUNDSCAPE_COMMAND))
{
{
//get number of keyvalues
const char* name = CFmtStr("New Soundscape %d", m_AmtAdded);
int num = 0;
AddButton(name, name, name, GetParent());


FOR_EACH_VALUE(m_Keyvalues, kv)
//add to keyvalues file
num++;
KeyValues* kv = new KeyValues(name);
KeyValues* tmp = m_Keyvalues;
//add keyvalues and button
KeyValues* tmp2 = tmp;
AddButton("Rndwave", "", CFmtStr("$rndwave%d", num + 1), GetParent());


KeyValues* add = new KeyValues("wave");
//get last subkey
add->SetString(nullptr, "");
while (tmp != nullptr)
m_Keyvalues->AddSubKey(add);
{
tmp2 = tmp;
tmp = tmp->GetNextTrueSubKey();
}


//forward command to parent
//add to last subkey
GetParent()->OnCommand(CFmtStr("$rndwave%d", num + 1));
tmp2->SetNextKey(kv);


GetParent()->OnCommand(name);
return;
return;
}
}
Line 1,016: Line 1,214:
}
}


//-----------------------------------------------------------------------------
// Purpose: Paints the background
//-----------------------------------------------------------------------------
void CSoundscapeList::PaintBackground()
{
//colors
static Color EnabledColor = Color(100, 100, 100, 200);
static Color DisabledColor = Color(60, 60, 60, 200);


//if m_KeyValues then paint the default color
if (m_Keyvalues)
SetBgColor(EnabledColor);
else
SetBgColor(DisabledColor);


//soundscape panel
BaseClass::PaintBackground();
}


//-----------------------------------------------------------------------------
// Purpose: Called on scroll bar moved
//-----------------------------------------------------------------------------
void CSoundscapeList::ScrollBarMoved(int delta)
{
int position = m_pSideSlider->GetValue();


#define SOUNDSCAPE_PANEL_WIDTH 760
//move everything down (if needed)
#define SOUNDSCAPE_PANEL_HEIGHT 600
for (int i = 0; i < m_MenuButtons.Count(); i++)
{
//make not visible if i < position
if (i < position)
{
m_MenuButtons[i]->SetVisible(false);
continue;
}


#define NEW_BUTTON_COMMAND "NewSoundscape"
m_MenuButtons[i]->SetPos(5, 22 * ((i - position) + 1));
#define SAVE_BUTTON_COMMAND "SaveSoundscape"
m_MenuButtons[i]->SetVisible(true);
#define LOAD_BUTTON_COMMAND "LoadSoundscape"
}
#define RESET_BUTTON_COMMAND "ResetSoundscapes"
}
#define SOUNDS_LIST_BUTTON_COMMAND "ShowSoundsList"
#define PLAY_SOUNDSCAPE_COMMAND "PlaySoundscape"
#define RESET_SOUNDSCAPE_BUTTON_COMMAND "ResetSoundscape"
#define DELETE_CURRENT_ITEM_COMMAND "DeleteItem"


//static bool to determin if the soundscape panel should show or not
bool g_ShowSoundscapePanel = true;
bool g_IsPlayingSoundscape = false;


//soundscape maker panel
class CSoundscapeMaker : public vgui::Frame, CAutoGameSystem
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeMaker, vgui::Frame)


CSoundscapeMaker(vgui::VPANEL parent);


//tick functions
//soundscape data list
void OnTick();


//other functions
void OnClose();
void OnCommand(const char* pszCommand);


void PlaySelectedSoundscape();
#define NEW_PLAYLOOPING_COMMAND "NewLooping"
void LoadFile(KeyValues* file);
#define NEW_SOUNDSCAPE_COMMAND "NewSoundscape"
#define NEW_RANDOM_COMMAND "NewRandom"


void OnKeyCodePressed(vgui::KeyCode code);


void SetSoundText(const char* text);
class CSoundscapeDataList : public CSoundscapeList
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
CSoundscapeDataList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
: CSoundscapeList(parent, name, text, text_x_pos, max, width, height)
{}


//to play the soundscape on map spawn
//override right click functionality
void LevelInitPostEntity();
virtual void OnMouseReleased(vgui::MouseCode code);


//message pointer funcs
void OnCommand(const char* pszCommand);
MESSAGE_FUNC_CHARPTR(OnFileSelected, "FileSelected", fullpath);
MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);
 
~CSoundscapeMaker();


private:
private:
//the soundscape keyvalues file
friend class CSoundscapeMaker;
KeyValues* m_KeyValues = nullptr;
};


private:
void CreateEverything();


private:
//-----------------------------------------------------------------------------
//lists all the soundscapes
// Purpose: Called when a mouse code is released
CSoundscapeList* m_SoundscapesList;
//-----------------------------------------------------------------------------
CSoundscapeDataList* m_pDataList;
void CSoundscapeDataList::OnMouseReleased(vgui::MouseCode code)
CSoundscapeRndwaveList* m_pSoundList;
{
//if no soundscape is selected or mouse code != right then return
if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
return;


//buttons
//get cursor pos
vgui::Button* m_ButtonNew = nullptr;
int x, y;
vgui::Button* m_ButtonSave = nullptr;
vgui::surface()->SurfaceGetCursorPos(x, y);
vgui::Button* m_ButtonLoad = nullptr;


//file load and save dialogs
//create menu
vgui::FileOpenDialog* m_FileSave = nullptr;
menu = new vgui::Menu(this, "Menu");
vgui::FileOpenDialog* m_FileLoad = nullptr;
menu->AddMenuItem("AddLooping", "Add Looping Sound", NEW_PLAYLOOPING_COMMAND, this);
bool m_bWasFileLoad = false;
menu->AddMenuItem("AddSoundscape", "Add Soundscape", NEW_SOUNDSCAPE_COMMAND, this);
menu->AddMenuItem("AddSoundscape", "Add Random Sounds", NEW_RANDOM_COMMAND, this);
menu->SetBounds(x, y, 200, 50);
menu->SetVisible(true);
}


//text entry for name
vgui::TextEntry* m_TextEntryName;


//combo box for dsp effects
//-----------------------------------------------------------------------------
vgui::ComboBox* m_DspEffects;
// Purpose: Called on command
vgui::ComboBox* m_SoundLevels;
//-----------------------------------------------------------------------------
void CSoundscapeDataList::OnCommand(const char* pszCommand)
{
if (!Q_strcmp(pszCommand, NEW_PLAYLOOPING_COMMAND))
{
int LoopingNum = 0;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
{
//store data name
const char* name = data->GetName();


//sound data text entry
//increment variables based on name
vgui::TextEntry* m_TimeTextEntry;
if (!Q_strcasecmp(name, "playlooping"))
vgui::TextEntry* m_VolumeTextEntry;
LoopingNum++;
vgui::TextEntry* m_PitchTextEntry;
}
vgui::TextEntry* m_PositionTextEntry;
vgui::TextEntry* m_SoundNameTextEntry;


//play sound button
//add the keyvalue to both this and the keyvalues
vgui::Button* m_SoundNamePlay;
AddButton("playlooping", "playlooping", CFmtStr("$playlooping%d", LoopingNum + 1), GetParent());


//play/reset soundscape buttons
//add the keyvalues
vgui::CheckButton* m_PlaySoundscapeButton;
KeyValues* kv = new KeyValues("playlooping");
vgui::Button* m_ResetSoundscapeButton;
kv->SetFloat("volume", 1);
vgui::Button* m_DeleteCurrentButton;
kv->SetInt("pitch", 100);


//current selected soundscape
m_Keyvalues->AddSubKey(kv);
CSoundscapeButton* m_pCurrentSelected = nullptr;
KeyValues* m_kvCurrSelected = nullptr;
KeyValues* m_kvCurrSound = nullptr;
KeyValues* m_kvCurrRndwave = nullptr;


int m_iCurrRndWave = 0;
GetParent()->OnCommand(CFmtStr("$playlooping%d", LoopingNum + 1));


//currently in non randomwave thing
return;
SoundscapeMode m_iSoundscapeMode = SoundscapeMode::Mode_Random;
}
 
else if (!Q_strcmp(pszCommand, NEW_SOUNDSCAPE_COMMAND))
//temporary added soundscapes
{
CUtlVector<KeyValues*> m_TmpAddedSoundscapes;
int SoundscapeNum = 0;
};
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
{
//store data name
const char* name = data->GetName();


//-----------------------------------------------------------------------------
//increment variables based on name
// Purpose: Constructor for soundscape maker panel
if (!Q_strcasecmp(name, "playsoundscape"))
//-----------------------------------------------------------------------------
SoundscapeNum++;
CSoundscapeMaker::CSoundscapeMaker(vgui::VPANEL parent)
}
: BaseClass(nullptr, "SoundscapeMaker")
{
//set variables
m_pCurrentSelected = nullptr;


SetParent(parent);
AddButton("playsoundscape", "playsoundscape", CFmtStr("$playsoundscape%d", SoundscapeNum + 1), GetParent());
SetKeyBoardInputEnabled(true);
SetMouseInputEnabled(true);


SetProportional(false);
//add the keyvalues
SetTitleBarVisible(true);
KeyValues* kv = new KeyValues("playsoundscape");
SetMinimizeButtonVisible(false);
kv->SetFloat("volume", 1);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(true);
SetSizeable(false);
SetMoveable(true);
SetVisible(g_ShowSoundscapePanel);
int ScreenWide, ScreenTall;
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);


SetTitle("Soundscape Maker (New File)", true);
//add the keyvalue to both this and the keyvalues
SetSize(SOUNDSCAPE_PANEL_WIDTH, SOUNDSCAPE_PANEL_HEIGHT);
m_Keyvalues->AddSubKey(kv);
SetPos((ScreenWide - SOUNDSCAPE_PANEL_WIDTH) / 2, (ScreenTall - SOUNDSCAPE_PANEL_HEIGHT) / 2);


SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
GetParent()->OnCommand(CFmtStr("$playsoundscape%d", SoundscapeNum + 1));


//add a tick signal for every 50 ms
return;
vgui::ivgui()->AddTickSignal(GetVPanel(), 50);
}
else if (!Q_strcmp(pszCommand, NEW_RANDOM_COMMAND))
{
int RandomNum = 0;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
{
//store data name
const char* name = data->GetName();


CreateEverything();
//increment variables based on name
}
if (!Q_strcasecmp(name, "playrandom"))
RandomNum++;
}


//-----------------------------------------------------------------------------
AddButton("playrandom", "playrandom", CFmtStr("$playrandom%d", RandomNum + 1), GetParent());
// Purpose: Creates everything for this panel
//-----------------------------------------------------------------------------
void CSoundscapeMaker::CreateEverything()
{
//create the divider that will be the outline for the inside of the panel
vgui::Divider* PanelOutline = new vgui::Divider(this, "InsideOutline");
PanelOutline->SetEnabled(false);
PanelOutline->SetBounds(5, 25, SOUNDSCAPE_PANEL_WIDTH - 10, SOUNDSCAPE_PANEL_HEIGHT - 30);


//create the buttons
//add the keyvalues
m_ButtonNew = new vgui::Button(this, "NewButton", "New Soundscape File");
KeyValues* kv = new KeyValues("playrandom");
m_ButtonNew->SetVisible(true);
kv->SetString("volume", "0.5,0.8");
m_ButtonNew->SetBounds(325, 566, 165, 25);
kv->SetInt("pitch", 100);
m_ButtonNew->SetCommand(NEW_BUTTON_COMMAND);
kv->SetString("time", "10,20");
m_ButtonNew->SetDepressedSound("ui/buttonclickrelease.wav");
//make rndwave subkey
m_ButtonSave = new vgui::Button(this, "SaveButton", "Save Soundscapes");
KeyValues* rndwave = new KeyValues("rndwave");
m_ButtonSave->SetVisible(true);
kv->AddSubKey(rndwave);
m_ButtonSave->SetBounds(495, 566, 125, 25);
m_ButtonSave->SetCommand(SAVE_BUTTON_COMMAND);
m_ButtonSave->SetDepressedSound("ui/buttonclickrelease.wav");


m_ButtonLoad = new vgui::Button(this, "LoadButton", "Load Soundscapes");
//add the keyvalue to both this and the keyvalues
m_ButtonLoad->SetVisible(true);
m_Keyvalues->AddSubKey(kv);
m_ButtonLoad->SetBounds(625, 566, 125, 25);
m_ButtonLoad->SetCommand(LOAD_BUTTON_COMMAND);
m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");


//create the soundscapes menu
//make the parent show the new item
m_SoundscapesList = new CSoundscapeList(this, "SoundscapesList", "Soundscapes:", 90, 22, 300, 550);
GetParent()->OnCommand(CFmtStr("$playrandom%d", RandomNum + 1));
m_SoundscapesList->SetBounds(15, 35, 300, 550);
m_SoundscapesList->SetVisible(true);


//create data list
return;
m_pDataList = new CSoundscapeDataList(this, "SoudscapeDataList", "Soundscape Data:", 35, 10, 200, 280);
}
m_pDataList->SetBounds(327, 275, 200, 280);
m_pDataList->SetVisible(true);
//create sound list
m_pSoundList = new CSoundscapeRndwaveList(this, "SoudscapeDataList", "Random Sounds:", 40, 10, 200, 280);
m_pSoundList->SetBounds(542, 275, 200, 280);
m_pSoundList->SetVisible(true);


//name text entry
BaseClass::OnCommand(pszCommand);
m_TextEntryName = new vgui::TextEntry(this, "NameTextEntry");
}
m_TextEntryName->SetEnabled(false);
 
m_TextEntryName->SetBounds(325, 40, 295, 20);
 
m_TextEntryName->SetMaximumCharCount(50);
//soundscape rndwave data list
 
 
#define NEW_RNDWAVE_WAVE_COMMAND "NewRNDWave"
 
 
class CSoundscapeRndwaveList : public CSoundscapeList
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
CSoundscapeRndwaveList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
: CSoundscapeList(parent, name, text, text_x_pos, max, width, height)
{}
 
//override right click functionality
virtual void OnMouseReleased(vgui::MouseCode code);
 
void OnCommand(const char* pszCommand);
 
private:
friend class CSoundscapeMaker;
};
 
 
//-----------------------------------------------------------------------------
// Purpose: Called when a mouse code is released
//-----------------------------------------------------------------------------
void CSoundscapeRndwaveList::OnMouseReleased(vgui::MouseCode code)
{
//if no soundscape is selected or mouse code != right then return
if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
return;
 
//get cursor pos
int x, y;
vgui::surface()->SurfaceGetCursorPos(x, y);
 
//create menu
menu = new vgui::Menu(this, "Menu");
menu->AddMenuItem("AddRandom", "Add Random Wave", NEW_RNDWAVE_WAVE_COMMAND, this);
menu->SetBounds(x, y, 200, 50);
menu->SetVisible(true);
}
 
 
//-----------------------------------------------------------------------------
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundscapeRndwaveList::OnCommand(const char* pszCommand)
{
if (!Q_strcmp(pszCommand, NEW_RNDWAVE_WAVE_COMMAND))
{
//get number of keyvalues
int num = 0;
 
FOR_EACH_VALUE(m_Keyvalues, kv)
num++;
//add keyvalues and button
AddButton("Rndwave", "", CFmtStr("$rndwave%d", num + 1), GetParent());
 
KeyValues* add = new KeyValues("wave");
add->SetString(nullptr, "");
m_Keyvalues->AddSubKey(add);
 
//forward command to parent
GetParent()->OnCommand(CFmtStr("$rndwave%d", num + 1));
 
return;
}
 
BaseClass::OnCommand(pszCommand);
}
 
 
 
//soundscape panel
 
 
#define SOUNDSCAPE_PANEL_WIDTH 760
#define SOUNDSCAPE_PANEL_HEIGHT 630
 
#define NEW_BUTTON_COMMAND "$NewSoundscape"
#define SAVE_BUTTON_COMMAND "$SaveSoundscape"
#define LOAD_BUTTON_COMMAND "$LoadSoundscape"
#define OPTIONS_BUTTON_COMMAND "$ShowOptions"
#define RESET_BUTTON_COMMAND "$ResetSoundscapes"
#define SOUNDS_LIST_BUTTON_COMMAND "$ShowSoundsList"
#define PLAY_SOUNDSCAPE_COMMAND "$PlaySoundscape"
#define RESET_SOUNDSCAPE_BUTTON_COMMAND "$ResetSoundscape"
#define DELETE_CURRENT_ITEM_COMMAND "$DeleteItem"
 
//static bool to determin if the soundscape panel should show or not
bool g_ShowSoundscapePanel = true;
bool g_IsPlayingSoundscape = false;
 
//soundscape maker panel
class CSoundscapeMaker : public vgui::Frame, CAutoGameSystem
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeMaker, vgui::Frame)
 
CSoundscapeMaker(vgui::VPANEL parent);
 
//tick functions
void OnTick();
 
//other functions
void OnClose();
void OnCommand(const char* pszCommand);
 
void PlaySelectedSoundscape();
void LoadFile(KeyValues* file);
 
void OnKeyCodePressed(vgui::KeyCode code);
 
void SetSoundText(const char* text);
 
//to play the soundscape on map spawn
void LevelInitPostEntity();
 
//message pointer funcs
MESSAGE_FUNC_CHARPTR(OnFileSelected, "FileSelected", fullpath);
MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);
 
~CSoundscapeMaker();
 
private:
//the soundscape keyvalues file
KeyValues* m_KeyValues = nullptr;
 
private:
void CreateEverything();
 
private:
//lists all the soundscapes
CSoundscapeList* m_SoundscapesList;
CSoundscapeDataList* m_pDataList;
CSoundscapeRndwaveList* m_pSoundList;
 
//buttons
vgui::Button* m_ButtonNew = nullptr;
vgui::Button* m_ButtonSave = nullptr;
vgui::Button* m_ButtonLoad = nullptr;
 
//file load and save dialogs
vgui::FileOpenDialog* m_FileSave = nullptr;
vgui::FileOpenDialog* m_FileLoad = nullptr;
bool m_bWasFileLoad = false;
 
//text entry for name
vgui::TextEntry* m_TextEntryName;
 
//combo box for dsp effects
vgui::ComboBox* m_DspEffects;
vgui::ComboBox* m_SoundLevels;
 
//sound data text entry
vgui::TextEntry* m_TimeTextEntry;
vgui::TextEntry* m_VolumeTextEntry;
vgui::TextEntry* m_PitchTextEntry;
vgui::TextEntry* m_PositionTextEntry;
vgui::TextEntry* m_SoundNameTextEntry;
 
//play sound button
vgui::Button* m_SoundNamePlay;
 
//play/reset soundscape buttons
vgui::CheckButton* m_PlaySoundscapeButton;
vgui::Button* m_ResetSoundscapeButton;
vgui::Button* m_DeleteCurrentButton;
 
//current selected soundscape
CSoundscapeButton* m_pCurrentSelected = nullptr;
KeyValues* m_kvCurrSelected = nullptr;
KeyValues* m_kvCurrSound = nullptr;
KeyValues* m_kvCurrRndwave = nullptr;
 
int m_iCurrRndWave = 0;
 
//currently in non randomwave thing
SoundscapeMode m_iSoundscapeMode = SoundscapeMode::Mode_Random;
 
//temporary added soundscapes
CUtlVector<KeyValues*> m_TmpAddedSoundscapes;
};
 
//user message hook
void _SoundscapeMaker_Recieve(bf_read& bf);
 
//-----------------------------------------------------------------------------
// Purpose: Constructor for soundscape maker panel
//-----------------------------------------------------------------------------
CSoundscapeMaker::CSoundscapeMaker(vgui::VPANEL parent)
: BaseClass(nullptr, "SoundscapeMaker")
{
static bool bRegistered = false;
if (!bRegistered)
{
usermessages->HookMessage("SoundscapeMaker_Recieve", _SoundscapeMaker_Recieve);
bRegistered = true;
}
 
//set variables
m_pCurrentSelected = nullptr;
 
SetParent(parent);
SetKeyBoardInputEnabled(true);
SetMouseInputEnabled(true);
 
SetProportional(false);
SetTitleBarVisible(true);
SetMinimizeButtonVisible(false);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(true);
SetSizeable(false);
SetMoveable(true);
SetVisible(g_ShowSoundscapePanel);
int ScreenWide, ScreenTall;
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);
 
SetTitle("Soundscape Maker (New File)", true);
SetSize(SOUNDSCAPE_PANEL_WIDTH, SOUNDSCAPE_PANEL_HEIGHT);
SetPos((ScreenWide - SOUNDSCAPE_PANEL_WIDTH) / 2, (ScreenTall - SOUNDSCAPE_PANEL_HEIGHT) / 2);
 
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
 
//add a tick signal for every 50 ms
vgui::ivgui()->AddTickSignal(GetVPanel(), 50);
 
CreateEverything();
}
 
//-----------------------------------------------------------------------------
// Purpose: Creates everything for this panel
//-----------------------------------------------------------------------------
void CSoundscapeMaker::CreateEverything()
{
//create the divider that will be the outline for the inside of the panel
vgui::Divider* PanelOutline = new vgui::Divider(this, "InsideOutline");
PanelOutline->SetEnabled(false);
PanelOutline->SetBounds(5, 25, SOUNDSCAPE_PANEL_WIDTH - 10, SOUNDSCAPE_PANEL_HEIGHT - 62);
 
//create the buttons
//create the buttons
m_ButtonNew = new vgui::Button(this, "NewButton", "New Soundscape File");
m_ButtonNew->SetVisible(true);
m_ButtonNew->SetBounds(55, 600, 165, 25);
m_ButtonNew->SetCommand(NEW_BUTTON_COMMAND);
m_ButtonNew->SetDepressedSound("ui/buttonclickrelease.wav");
 
m_ButtonSave = new vgui::Button(this, "SaveButton", "Save Soundscapes");
m_ButtonSave->SetVisible(true);
m_ButtonSave->SetBounds(225, 600, 165, 25);
m_ButtonSave->SetCommand(SAVE_BUTTON_COMMAND);
m_ButtonSave->SetDepressedSound("ui/buttonclickrelease.wav");
 
m_ButtonLoad = new vgui::Button(this, "LoadButton", "Load Soundscapes");
m_ButtonLoad->SetVisible(true);
m_ButtonLoad->SetBounds(395, 600, 165, 25);
m_ButtonLoad->SetCommand(LOAD_BUTTON_COMMAND);
m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");
m_ButtonLoad = new vgui::Button(this, "LoadButton", "Show Options Panel");
m_ButtonLoad->SetVisible(true);
m_ButtonLoad->SetBounds(565, 600, 165, 25);
m_ButtonLoad->SetCommand(OPTIONS_BUTTON_COMMAND);
m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");
 
//create the soundscapes menu
m_SoundscapesList = new CSoundscapeList(this, "SoundscapesList", "Soundscapes:", 90, 22, 300, 550);
m_SoundscapesList->SetBounds(15, 35, 300, 550);
m_SoundscapesList->SetVisible(true);
 
//create data list
m_pDataList = new CSoundscapeDataList(this, "SoudscapeDataList", "Soundscape Data:", 35, 10, 200, 310);
m_pDataList->SetBounds(327, 275, 200, 310);
m_pDataList->SetVisible(true);
//create sound list
m_pSoundList = new CSoundscapeRndwaveList(this, "SoudscapeDataList", "Random Sounds:", 40, 10, 200, 310);
m_pSoundList->SetBounds(542, 275, 200, 310);
m_pSoundList->SetVisible(true);
 
//name text entry
m_TextEntryName = new vgui::TextEntry(this, "NameTextEntry");
m_TextEntryName->SetEnabled(false);
m_TextEntryName->SetBounds(325, 40, 295, 20);
m_TextEntryName->SetMaximumCharCount(50);
 
//dsp effects combo box
m_DspEffects = new vgui::ComboBox(this, "DspEffects", sizeof(g_DspEffects) / sizeof(g_DspEffects[0]), false);
m_DspEffects->SetEnabled(false);
m_DspEffects->SetBounds(325, 65, 295, 20);
m_DspEffects->SetText("");
m_DspEffects->AddActionSignalTarget(this);
 
for (int i = 0; i < sizeof(g_DspEffects) / sizeof(g_DspEffects[i]); i++)
m_DspEffects->AddItem(g_DspEffects[i], nullptr);
 
//time text entry
m_TimeTextEntry = new vgui::TextEntry(this, "TimeTextEntry");
m_TimeTextEntry->SetBounds(325, 90, 295, 20);
m_TimeTextEntry->SetEnabled(false);
m_TimeTextEntry->SetVisible(true);
 
//volume text entry
m_VolumeTextEntry = new vgui::TextEntry(this, "VolumeTextEntry");
m_VolumeTextEntry->SetBounds(325, 115, 295, 20);
m_VolumeTextEntry->SetEnabled(false);
m_VolumeTextEntry->SetVisible(true);
 
//pitch text entry
m_PitchTextEntry = new vgui::TextEntry(this, "PitchTextEntry");
m_PitchTextEntry->SetBounds(325, 140, 295, 20);
m_PitchTextEntry->SetEnabled(false);
m_PitchTextEntry->SetVisible(true);
//position text entry
m_PositionTextEntry = new vgui::TextEntry(this, "PositionTextEntry");
m_PositionTextEntry->SetBounds(325, 165, 295, 20);
m_PositionTextEntry->SetEnabled(false);
m_PositionTextEntry->SetVisible(true);
//sound levels
m_SoundLevels = new vgui::ComboBox(this, "SoundLevels", sizeof(g_SoundLevels) / sizeof(g_SoundLevels[0]), false);
m_SoundLevels->SetEnabled(false);
m_SoundLevels->SetBounds(325, 190, 295, 20);
m_SoundLevels->SetText("");
m_SoundLevels->AddActionSignalTarget(this);
 
for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
m_SoundLevels->AddItem(g_SoundLevels[i], nullptr);
//sound name
m_SoundNameTextEntry = new vgui::TextEntry(this, "SoundName");
m_SoundNameTextEntry->SetBounds(325, 215, 215, 20);
m_SoundNameTextEntry->SetEnabled(false);
m_SoundNameTextEntry->SetVisible(true);
 
//play sound button
m_SoundNamePlay = new vgui::Button(this, "SoundPlayButton", "Sounds List");
m_SoundNamePlay->SetBounds(545, 215, 75, 20);
m_SoundNamePlay->SetCommand(SOUNDS_LIST_BUTTON_COMMAND);
m_SoundNamePlay->SetEnabled(false);
 
//starts the soundscape
m_PlaySoundscapeButton = new vgui::CheckButton(this, "PlaySoundscape", "Play Soundscape");
m_PlaySoundscapeButton->SetBounds(330, 243, 125, 20);
m_PlaySoundscapeButton->SetCommand(PLAY_SOUNDSCAPE_COMMAND);
m_PlaySoundscapeButton->SetEnabled(false);
m_PlaySoundscapeButton->SetSelected(false);
 
//reset soundscape button
m_ResetSoundscapeButton = new vgui::Button(this, "ResetSoundscape", "Restart Soundscape");
m_ResetSoundscapeButton->SetBounds(465, 243, 125, 20);
m_ResetSoundscapeButton->SetCommand(RESET_SOUNDSCAPE_BUTTON_COMMAND);
m_ResetSoundscapeButton->SetEnabled(false);


//dsp effects combo box
//delete this item
m_DspEffects = new vgui::ComboBox(this, "DspEffects", sizeof(g_DspEffects) / sizeof(g_DspEffects[0]), false);
m_DeleteCurrentButton = new vgui::Button(this, "DeleteItem", "Delete Current Item");
m_DspEffects->SetEnabled(false);
m_DeleteCurrentButton->SetBounds(595, 243, 135, 20);
m_DspEffects->SetBounds(325, 65, 295, 20);
m_DeleteCurrentButton->SetCommand(DELETE_CURRENT_ITEM_COMMAND);
m_DspEffects->SetText("");
m_DeleteCurrentButton->SetEnabled(false);
m_DspEffects->AddActionSignalTarget(this);


for (int i = 0; i < sizeof(g_DspEffects) / sizeof(g_DspEffects[i]); i++)
//create the soundscape name text
m_DspEffects->AddItem(g_DspEffects[i], nullptr);
vgui::Label* NameLabel = new vgui::Label(this, "NameLabel", "Soundscape Name");
NameLabel->SetBounds(635, 40, 125, 20);


//time text entry
//create the soundscape dsp text
m_TimeTextEntry = new vgui::TextEntry(this, "TimeTextEntry");
vgui::Label* DspLabel = new vgui::Label(this, "DspLabel", "Soundscape Dsp");
m_TimeTextEntry->SetBounds(325, 90, 295, 20);
DspLabel->SetBounds(635, 65, 125, 20);
m_TimeTextEntry->SetEnabled(false);
m_TimeTextEntry->SetVisible(true);
//create the soundscape time text
vgui::Label* TimeLabel = new vgui::Label(this, "TimeLabel", "Sound Time");
TimeLabel->SetBounds(635, 90, 125, 20);
//create the soundscape volumn text
vgui::Label* VolumeLabel = new vgui::Label(this, "VolumeLabel", "Sound Volume");
VolumeLabel->SetBounds(635, 115, 125, 20);


//volume text entry
//create the soundscape pitch text
m_VolumeTextEntry = new vgui::TextEntry(this, "VolumeTextEntry");
vgui::Label* PitchLabel = new vgui::Label(this, "PitchLabel", "Sound Pitch");
m_VolumeTextEntry->SetBounds(325, 115, 295, 20);
PitchLabel->SetBounds(635, 140, 125, 20);
m_VolumeTextEntry->SetEnabled(false);
m_VolumeTextEntry->SetVisible(true);
//create the soundscape position text
vgui::Label* PositionLabel = new vgui::Label(this, "PositionLabel", "Sound Position");
PositionLabel->SetBounds(635, 165, 125, 20);


//pitch text entry
//create the soundscape sound level text
m_PitchTextEntry = new vgui::TextEntry(this, "PitchTextEntry");
vgui::Label* SoundLevelLabel = new vgui::Label(this, "SoundLevelLabel", "Sound Level");
m_PitchTextEntry->SetBounds(325, 140, 295, 20);
SoundLevelLabel ->SetBounds(635, 190, 125, 20);
m_PitchTextEntry->SetEnabled(false);
m_PitchTextEntry->SetVisible(true);
//position text entry
m_PositionTextEntry = new vgui::TextEntry(this, "PositionTextEntry");
m_PositionTextEntry->SetBounds(325, 165, 295, 20);
m_PositionTextEntry->SetEnabled(false);
m_PositionTextEntry->SetVisible(true);
//sound levels
m_SoundLevels = new vgui::ComboBox(this, "SoundLevels", sizeof(g_SoundLevels) / sizeof(g_SoundLevels[0]), false);
m_SoundLevels->SetEnabled(false);
m_SoundLevels->SetBounds(325, 190, 295, 20);
m_SoundLevels->SetText("");
m_SoundLevels->AddActionSignalTarget(this);


for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
//create the soundscape sound name text
m_SoundLevels->AddItem(g_SoundLevels[i], nullptr);
vgui::Label* SoundName = new vgui::Label(this, "SoundName", "Sound Name");
SoundName->SetBounds(635, 215, 125, 20);
//sound name
m_SoundNameTextEntry = new vgui::TextEntry(this, "SoundName");
m_SoundNameTextEntry->SetBounds(325, 215, 215, 20);
m_SoundNameTextEntry->SetEnabled(false);
m_SoundNameTextEntry->SetVisible(true);


//play sound button
//create the soundscape keyvalues and load it
m_SoundNamePlay = new vgui::Button(this, "SoundPlayButton", "Sounds List");
m_KeyValues = new KeyValues("Empty Soundscape");
m_SoundNamePlay->SetBounds(545, 215, 75, 20);
m_SoundNamePlay->SetCommand(SOUNDS_LIST_BUTTON_COMMAND);
m_SoundNamePlay->SetEnabled(false);


//starts the soundscape
LoadFile(m_KeyValues);
m_PlaySoundscapeButton = new vgui::CheckButton(this, "PlaySoundscape", "Play Soundscape");
}
m_PlaySoundscapeButton->SetBounds(330, 243, 125, 20);
m_PlaySoundscapeButton->SetCommand(PLAY_SOUNDSCAPE_COMMAND);
m_PlaySoundscapeButton->SetEnabled(false);
m_PlaySoundscapeButton->SetSelected(false);


//reset soundscape button
//-----------------------------------------------------------------------------
m_ResetSoundscapeButton = new vgui::Button(this, "ResetSoundscape", "Restart Soundscape");
// Purpose: Called every tick for the soundscape maker
m_ResetSoundscapeButton->SetBounds(465, 243, 125, 20);
//-----------------------------------------------------------------------------
m_ResetSoundscapeButton->SetCommand(RESET_SOUNDSCAPE_BUTTON_COMMAND);
void CSoundscapeMaker::OnTick()
m_ResetSoundscapeButton->SetEnabled(false);
{
//set the visibility
static bool bPrevVisible = g_ShowSoundscapePanel;
if (g_ShowSoundscapePanel != bPrevVisible)
SetVisible(g_ShowSoundscapePanel);


//delete this item
//set the old visibility
m_DeleteCurrentButton = new vgui::Button(this, "DeleteItem", "Delete Current Item");
bPrevVisible = g_ShowSoundscapePanel;
m_DeleteCurrentButton->SetBounds(595, 243, 135, 20);
}
m_DeleteCurrentButton->SetCommand(DELETE_CURRENT_ITEM_COMMAND);
m_DeleteCurrentButton->SetEnabled(false);


//create the soundscape name text
//-----------------------------------------------------------------------------
vgui::Label* NameLabel = new vgui::Label(this, "NameLabel", "Soundscape Name");
// Purpose: Called when the close button is pressed
NameLabel->SetBounds(635, 40, 125, 20);
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnClose()
{
//hide the other panels
g_SoundPanel->OnClose();
g_SettingsPanel->OnClose();


//create the soundscape dsp text
g_ShowSoundscapePanel = false;
vgui::Label* DspLabel = new vgui::Label(this, "DspLabel", "Soundscape Dsp");
}
DspLabel->SetBounds(635, 65, 125, 20);
//create the soundscape time text
vgui::Label* TimeLabel = new vgui::Label(this, "TimeLabel", "Sound Time");
TimeLabel->SetBounds(635, 90, 125, 20);
//create the soundscape volumn text
vgui::Label* VolumeLabel = new vgui::Label(this, "VolumeLabel", "Sound Volume");
VolumeLabel->SetBounds(635, 115, 125, 20);


//create the soundscape pitch text
//-----------------------------------------------------------------------------
vgui::Label* PitchLabel = new vgui::Label(this, "PitchLabel", "Sound Pitch");
// Purpose: Play the selected soundscape
PitchLabel->SetBounds(635, 140, 125, 20);
//-----------------------------------------------------------------------------
void CSoundscapeMaker::PlaySelectedSoundscape()
//create the soundscape position text
{
vgui::Label* PositionLabel = new vgui::Label(this, "PositionLabel", "Sound Position");
g_IsPlayingSoundscape = false;
PositionLabel->SetBounds(635, 165, 125, 20);


//create the soundscape sound level text
//remove all the temporary soundscapes from the soundscape system
vgui::Label* SoundLevelLabel = new vgui::Label(this, "SoundLevelLabel", "Sound Level");
for (int i = 0; i < m_TmpAddedSoundscapes.Count(); i++)
SoundLevelLabel ->SetBounds(635, 190, 125, 20);
{
for (int j = 0; j < g_SoundscapeSystem.m_soundscapes.Count(); j++)
{
if (g_SoundscapeSystem.m_soundscapes[j] == m_TmpAddedSoundscapes[i])
{
g_SoundscapeSystem.m_soundscapes.Remove(j);
break;
}
}
}


//create the soundscape sound name text
m_TmpAddedSoundscapes.RemoveAll();
vgui::Label* SoundName = new vgui::Label(this, "SoundName", "Sound Name");
SoundName->SetBounds(635, 215, 125, 20);


//create the soundscape keyvalues and load it
m_KeyValues = new KeyValues("Empty Soundscape");
//change audio params position
g_SoundscapeSystem.m_params.localBits = 0x7f;
for (int i = 0; i < MAX_SOUNDSCAPES - 1; i++)
g_SoundscapeSystem.m_params.localSound.Set(i, g_SoundscapePositions[i]);


LoadFile(m_KeyValues);
}


//-----------------------------------------------------------------------------
//if m_kvCurrSelected then add all the "playsoundscape" soundscape keyvalues
// Purpose: Called every tick for the soundscape maker
//into the g_SoundscapeSystem.m_soundscapes array
//-----------------------------------------------------------------------------
if (m_kvCurrSelected)
void CSoundscapeMaker::OnTick()
{
{
CUtlVector<const char*> SoundscapeNames;
//set the visibility
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, subkey)
static bool bPrevVisible = g_ShowSoundscapePanel;
{
if (g_ShowSoundscapePanel != bPrevVisible)
//look for playsoundscape file
SetVisible(g_ShowSoundscapePanel);
if (!Q_strcasecmp(subkey->GetName(), "playsoundscape"))
{
const char* name = subkey->GetString("name", nullptr);
if (!name || !name[0] || SoundscapeNames.Find(name) != SoundscapeNames.InvalidIndex())
continue;


//set the old visibility
SoundscapeNames.AddToTail(name);
bPrevVisible = g_ShowSoundscapePanel;
}
}
}
 
 
//-----------------------------------------------------------------------------
//now look for each keyvalue
// Purpose: Called when the close button is pressed
for (int i = 0; i < SoundscapeNames.Count(); i++)
//-----------------------------------------------------------------------------
{
void CSoundscapeMaker::OnClose()
for (KeyValues* subkey = m_KeyValues; subkey != nullptr; subkey = subkey->GetNextTrueSubKey())
{
{
//hide the sound panel
//look for playsoundscape file
g_SoundPanel->OnClose();
if (!Q_strcmp(subkey->GetName(), SoundscapeNames[i]))
 
{
g_ShowSoundscapePanel = false;
//add it to the soundscape system
}
m_TmpAddedSoundscapes.AddToTail(subkey);
g_SoundscapeSystem.m_soundscapes.AddToTail(subkey);
}
}
}
}
 
//stop all sounds
enginesound->StopAllSounds(true);
 
//stop the current soundscape and start a new soundscape
g_SoundscapeSystem.StartNewSoundscape(nullptr);
g_SoundscapeSystem.StartNewSoundscape(m_kvCurrSelected);
 
g_IsPlayingSoundscape = true;
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Play the selected soundscape
// Purpose: Called when a button or something else gets pressed
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeMaker::PlaySelectedSoundscape()
void CSoundscapeMaker::OnCommand(const char* pszCommand)
{
{
g_IsPlayingSoundscape = false;


//remove all the temporary soundscapes from the soundscape system
//check for close command first
for (int i = 0; i < m_TmpAddedSoundscapes.Count(); i++)
if (!Q_strcmp(pszCommand, "Close"))
{
{
for (int j = 0; j < g_SoundscapeSystem.m_soundscapes.Count(); j++)
BaseClass::OnCommand(pszCommand);
{
return;
if (g_SoundscapeSystem.m_soundscapes[j] == m_TmpAddedSoundscapes[i])
{
g_SoundscapeSystem.m_soundscapes.Remove(j);
break;
}
}
}
}


m_TmpAddedSoundscapes.RemoveAll();
//check for the save button command
 
else if (!Q_strcmp(pszCommand, SAVE_BUTTON_COMMAND))
//if m_kvCurrSelected then add all the "playsoundscape" soundscape keyvalues
//into the g_SoundscapeSystem.m_soundscapes array
if (m_kvCurrSelected)
{
{
CUtlVector<const char*> SoundscapeNames;
//initalize the file save dialog
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, subkey)
if (!m_FileSave)
{
{
//look for playsoundscape file
//get the current game directory
if (!Q_strcasecmp(subkey->GetName(), "playsoundscape"))
char buf[512];
{
filesystem->RelativePathToFullPath("scripts", "MOD", buf, sizeof(buf));
const char* name = subkey->GetString("name", nullptr);
if (!name || !name[0] || SoundscapeNames.Find(name) != SoundscapeNames.InvalidIndex())
continue;


SoundscapeNames.AddToTail(name);
//create the save dialog
}
m_FileSave = new vgui::FileOpenDialog(this, "Save Soundscape File", false);
m_FileSave->AddFilter("*.txt", "Soundscape Text File", true);
m_FileSave->AddFilter("*.*", "All Files (*.*)", false);
m_FileSave->SetStartDirectory(buf);
m_FileSave->AddActionSignalTarget(this);
}
}


//now look for each keyvalue
//show the dialog
for (int i = 0; i < SoundscapeNames.Count(); i++)
m_FileSave->DoModal(false);
{
m_FileSave->Activate();
for (KeyValues* subkey = m_KeyValues; subkey != nullptr; subkey = subkey->GetNextTrueSubKey())
 
{
//file wasnt loadad
//look for playsoundscape file
m_bWasFileLoad = false;
if (!Q_strcmp(subkey->GetName(), SoundscapeNames[i]))
{
//add it to the soundscape system
m_TmpAddedSoundscapes.AddToTail(subkey);
g_SoundscapeSystem.m_soundscapes.AddToTail(subkey);
}
}
}
}


//stop all sounds
enginesound->StopAllSounds(true);
//stop the current soundscape and start a new soundscape
g_SoundscapeSystem.StartNewSoundscape(nullptr);
g_SoundscapeSystem.StartNewSoundscape(m_kvCurrSelected);
g_IsPlayingSoundscape = true;
}
//-----------------------------------------------------------------------------
// Purpose: Called when a button or something else gets pressed
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnCommand(const char* pszCommand)
{
//check for close command first
if (!Q_strcmp(pszCommand, "Close"))
{
BaseClass::OnCommand(pszCommand);
return;
return;
}
}


//check for the save button command
//check for load button command
else if (!Q_strcmp(pszCommand, SAVE_BUTTON_COMMAND))
else if (!Q_strcmp(pszCommand, LOAD_BUTTON_COMMAND))
{
{
//initalize the file save dialog
//initalize the file save dialog
if (!m_FileSave)
if (!m_FileLoad)
{
//get the current game directory
char buf[512];
filesystem->RelativePathToFullPath("scripts", "MOD", buf, sizeof(buf));
 
//create the save dialog
m_FileSave = new vgui::FileOpenDialog(this, "Save Soundscape File", false);
m_FileSave->AddFilter("*.txt", "Soundscape Text File", true);
m_FileSave->AddFilter("*.*", "All Files (*.*)", false);
m_FileSave->SetStartDirectory(buf);
m_FileSave->AddActionSignalTarget(this);
}
 
//show the dialog
m_FileSave->DoModal(false);
m_FileSave->Activate();
 
//file wasnt loadad
m_bWasFileLoad = false;
 
return;
}
 
//check for load button command
else if (!Q_strcmp(pszCommand, LOAD_BUTTON_COMMAND))
{
//initalize the file save dialog
if (!m_FileLoad)
{
{
//get the current game directory
//get the current game directory
Line 1,486: Line 1,974:
m_bWasFileLoad = true;
m_bWasFileLoad = true;


return;
}
//check for options panel button
else if (!Q_strcmp(pszCommand, OPTIONS_BUTTON_COMMAND))
{
g_SettingsPanel->SetVisible(true);
g_SettingsPanel->MoveToFront();
g_SettingsPanel->RequestFocus();
return;
return;
}
}
Line 3,001: Line 3,498:
OnCommand(NEW_BUTTON_COMMAND);
OnCommand(NEW_BUTTON_COMMAND);


return;
}
if (code == vgui::KeyCode::KEY_O)
{
//show settings
g_SettingsPanel->SetVisible(true);
g_SettingsPanel->RequestFocus();
g_SettingsPanel->MoveToFront();
return;
return;
}
}
Line 3,039: Line 3,545:
m_KeyValues->deleteThis();
m_KeyValues->deleteThis();
}
}
//static panel instance
static CSoundscapeMaker* g_SSMakerPanel = nullptr;


//interface class
//interface class
Line 3,046: Line 3,555:
void Create(vgui::VPANEL parent)
void Create(vgui::VPANEL parent)
{
{
m_Panel = new CSoundscapeMaker(parent);
g_SSMakerPanel = new CSoundscapeMaker(parent);
g_SoundPanel = new CSoundListPanel(parent, "SoundListPanel");
g_SoundPanel = new CSoundListPanel(parent, "SoundListPanel");
g_SettingsPanel = new CSoundscapeSettingsPanel(parent, "SettingsPanel");
}
}


void SetVisible(bool bVisible)
void SetVisible(bool bVisible)
{
{
if (m_Panel)
if (g_SSMakerPanel)
m_Panel->SetVisible(bVisible);
g_SSMakerPanel->SetVisible(bVisible);
}
}


void Destroy()
void Destroy()
{
{
if (m_Panel)
if (g_SSMakerPanel)
m_Panel->DeletePanel();
g_SSMakerPanel->DeletePanel();


if (g_SoundPanel)
if (g_SoundPanel)
g_SoundPanel->DeletePanel();
g_SoundPanel->DeletePanel();


m_Panel = nullptr;
if (g_SettingsPanel)
g_SettingsPanel->DeletePanel();
 
g_SSMakerPanel = nullptr;
g_SoundPanel = nullptr;
g_SoundPanel = nullptr;
g_SettingsPanel = nullptr;
}
}


void SetSoundText(const char* text)
void SetSoundText(const char* text)
{
{
m_Panel->SetSoundText(text);
if (!g_SSMakerPanel)
m_Panel->RequestFocus();
return;
m_Panel->MoveToFront();
 
g_SSMakerPanel->SetSoundText(text);
g_SSMakerPanel->RequestFocus();
g_SSMakerPanel->MoveToFront();
}
 
void SetAllVisible(bool bVisible)
{
g_ShowSoundscapePanel = false;
 
if (g_SSMakerPanel)
g_SSMakerPanel->SetVisible(false);
 
if (g_SoundPanel)
g_SoundPanel->SetVisible(false);
 
if (g_SettingsPanel)
g_SettingsPanel->SetVisible(false);
}
}
private:
CSoundscapeMaker* m_Panel;
};
};


CSoundscapeMakerInterface SoundscapeMaker;
CSoundscapeMakerInterface SoundscapeMaker;
ISoundscapeMaker* g_SoundscapeMaker = &SoundscapeMaker;
ISoundscapeMaker* g_SoundscapeMaker = &SoundscapeMaker;
//-----------------------------------------------------------------------------
// Purpose: User message hook function for setting/getting soundscape position
//-----------------------------------------------------------------------------
void _SoundscapeMaker_Recieve(bf_read& bf)
{
//show the soundscape panel
g_ShowSoundscapePanel = true;
g_SSMakerPanel->SetVisible(true);
//show settings panel
g_SettingsPanel->SetVisible(true);
//get the stuff
byte index = bf.ReadByte();
Vector pos;
bf.ReadBitVec3Coord(pos);
//if index == -1 (255) then that means the message was canceled
if (index == 255)
return;
//clamp index and get pos
index = Clamp<int>(index, 0, MAX_SOUNDSCAPES - 1);
//send message to settings
g_SettingsPanel->SetItem(index, pos);
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
Line 3,088: Line 3,645:
g_ShowSoundscapePanel = !g_ShowSoundscapePanel;
g_ShowSoundscapePanel = !g_ShowSoundscapePanel;
SoundscapeMaker.SetVisible(g_ShowSoundscapePanel);
SoundscapeMaker.SetVisible(g_ShowSoundscapePanel);
//tell player to stop soundscape mode
static ConCommand* cc = cvar->FindCommand("__ss_maker_stop");
if (cc)
cc->Dispatch({});
}
}
</source>
</source>

Revision as of 02:07, 12 May 2025

vgui_soundscape_maker.cpp file needed for vgui soundscape maker

//========= Created by Waddelz. https://www.youtube.com/@WadDeIz_Real. ============//
//
// Purpose: a vgui panel that allows you to create and test soundscapes in game
//
// $NoKeywords: $
//
//=================================================================================//
#include "cbase.h"
#include "c_soundscape.h"
#include "vgui_soundscape_maker.h"
#include <vgui_controls/Frame.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/Divider.h>
#include <vgui_controls/FileOpenDialog.h>
#include <vgui_controls/QueryBox.h>
#include <vgui_controls/Label.h>
#include <vgui_controls/ScrollBar.h>
#include <vgui_controls/Button.h>
#include <vgui_controls/TextEntry.h>
#include <vgui_controls/ComboBox.h>
#include <vgui_controls/CheckButton.h>
#include <vgui_controls/Menu.h>
#include <vgui_controls/MenuItem.h>
#include <engine/IEngineSound.h>
#include <vgui/IVGui.h>
#include <vgui/IInput.h>
#include <vgui/ISurface.h>
#include <filesystem.h>
#include <usermessages.h>
#include <fmtstr.h>

//selected text mode
enum class SoundscapeMode
{
	Mode_Random,
	Mode_Soundscape,
	Mode_Looping,
};

//dsp effects
static const char* g_DspEffects[] = {
	"Normal (off)",
	"Generic",
	"Metal Small",
	"Metal Medium",
	"Metal Large",
	"Tunnel Small",
	"Tunnel Medium",
	"Tunnel Large",
	"Chamber Small",
	"Chamber Medium",
	"Chamber Large",
	"Bright Small",
	"Bright Medium",
	"Bright Large",
	"Water 1",
	"Water 2",
	"Water 3",
	"Concrete Small",
	"Concrete Medium",
	"Concrete Large",
	"Big 1",
	"Big 2",
	"Big 3",
	"Cavern Small",
	"Cavern Medium",
	"Cavern Large",
	"Weirdo 1",
	"Weirdo 2",
	"Weirdo 3",
};

//sound levels
static const char* g_SoundLevels[] = {
	"SNDLVL_50dB",
	"SNDLVL_55dB",
	"SNDLVL_IDLE",
	"SNDLVL_TALKING",
	"SNDLVL_60dB",
	"SNDLVL_65dB",
	"SNDLVL_STATIC",
	"SNDLVL_70dB",
	"SNDLVL_NORM",
	"SNDLVL_75dB",
	"SNDLVL_80dB",
	"SNDLVL_85dB",
	"SNDLVL_90dB",
	"SNDLVL_95dB",
	"SNDLVL_100dB",
	"SNDLVL_105dB",
	"SNDLVL_120dB",
	"SNDLVL_130dB",
	"SNDLVL_GUNFIRE",
	"SNDLVL_140dB",
	"SNDLVL_150dB"
};

//holds all the sound names
static CUtlVector<char*> g_SoundDirectories;

//-----------------------------------------------------------------------------
// Purpose: Sort function for utl vector
//-----------------------------------------------------------------------------
static int VectorSortFunc(char* const* p1, char* const* p2)
{
	return Q_stricmp(*p1, *p2);
}

//-----------------------------------------------------------------------------
// Purpose: Gets all the sound names and stores them into g_SoundDirectories
//-----------------------------------------------------------------------------
static void GetSoundNames()
{
	//first off clear the sound array first
	for (int i = 0; i < g_SoundDirectories.Count(); i++)
		free(g_SoundDirectories[i]);

	g_SoundDirectories.RemoveAll();

	//directories to search
	CUtlVector<char*> directoriesToSearch;
	directoriesToSearch.AddToTail(strdup("sound"));

	//loop until all directories have been processed
	while (directoriesToSearch.Count() > 0)
	{
		//take the last added directory (depth-first search)
		char* currentDir = directoriesToSearch[directoriesToSearch.Count() - 1];
		directoriesToSearch.Remove(directoriesToSearch.Count() - 1);

		//create a wildcard path to search all files and subdirs
		char searchPath[MAX_PATH];
		Q_snprintf(searchPath, sizeof(searchPath), "%s/*", currentDir);

		FileFindHandle_t findHandle;
		const char* filename = g_pFullFileSystem->FindFirst(searchPath, &findHandle);

		while (filename)
		{
			//ignore special directories
			if (Q_strcmp(filename, ".") != 0 && Q_strcmp(filename, "..") != 0)
			{
				char fullPath[MAX_PATH];
				Q_snprintf(fullPath, sizeof(fullPath), "%s/%s", currentDir, filename);

				//if it's a directory, add it to the list for later processing
				if (g_pFullFileSystem->FindIsDirectory(findHandle))
				{
					directoriesToSearch.AddToTail(strdup(fullPath));
				}
				else
				{
					//check file extension and print if it's .wav or .mp3
					const char* ext = V_GetFileExtension(filename);
					if (ext && (!Q_stricmp(ext, "wav") || !Q_stricmp(ext, "mp3")))
					{
						g_SoundDirectories.AddToTail(strdup(fullPath + 6));
					}
				}
			}

			// Move to next file
			filename = g_pFullFileSystem->FindNext(findHandle);
		}

		//free the memory
		g_pFullFileSystem->FindClose(findHandle);
		free(currentDir);
	}

	//
	g_SoundDirectories.Sort(VectorSortFunc);
}


//vector positions
Vector g_SoundscapePositions[] = {
	vec3_origin,
	vec3_origin,
	vec3_origin,
	vec3_origin,
	vec3_origin,
	vec3_origin,
	vec3_origin,
};

#define SETTINGS_PANEL_WIDTH 350
#define SETTINGS_PANEL_HEIGHT 250

#define SETTINGS_PANEL_COMMAND_POS1 "GetPos0"
#define SETTINGS_PANEL_COMMAND_POS2 "GetPos1"
#define SETTINGS_PANEL_COMMAND_POS3 "GetPos2"
#define SETTINGS_PANEL_COMMAND_POS4 "GetPos3"
#define SETTINGS_PANEL_COMMAND_POS5 "GetPos4"
#define SETTINGS_PANEL_COMMAND_POS6 "GetPos5"
#define SETTINGS_PANEL_COMMAND_POS7 "GetPos6"
#define SETTINGS_PANEL_COMMAND_POS8 "GetPos7"
#define SETTINGS_PANEL_COMMAND_SHOW "ShowPositions"

#define MAX_SOUNDSCAPES 8

//soundscape maker settings panel
class CSoundscapeSettingsPanel : public vgui::Frame
{
public:
	DECLARE_CLASS_SIMPLE(CSoundscapeSettingsPanel, vgui::Frame);

	CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name);

	//other
	void OnCommand(const char* pszCommand);

	//sets the text
	void SetItem(int index, const Vector& value);

	//message funcs
	MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);

private:
	//position text entries
	vgui::TextEntry* m_TextEntryPos0;
	vgui::TextEntry* m_TextEntryPos1;
	vgui::TextEntry* m_TextEntryPos2;
	vgui::TextEntry* m_TextEntryPos3;
	vgui::TextEntry* m_TextEntryPos4;
	vgui::TextEntry* m_TextEntryPos5;
	vgui::TextEntry* m_TextEntryPos6;
	vgui::TextEntry* m_TextEntryPos7;
	vgui::CheckButton* m_ShowSoundscapePositions;

	friend class CSoundscapeMaker;
};


//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSoundscapeSettingsPanel::CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name)
	: BaseClass(nullptr, name)
{
	SetParent(parent);

	SetKeyBoardInputEnabled(true);
	SetMouseInputEnabled(true);

	SetProportional(false);
	SetTitleBarVisible(true);
	SetMinimizeButtonVisible(false);
	SetMaximizeButtonVisible(false);
	SetCloseButtonVisible(true);
	SetSizeable(false);
	SetMoveable(true);
	SetVisible(false);

	//set the size and pos
	int ScreenWide, ScreenTall;
	vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);

	SetTitle("Soundscape Maker Settings", true);
	SetSize(SETTINGS_PANEL_WIDTH, SETTINGS_PANEL_HEIGHT);
	SetPos((ScreenWide - SETTINGS_PANEL_WIDTH) / 2, (ScreenTall - SETTINGS_PANEL_HEIGHT) / 2);

	SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));

	//create position text 1
	m_TextEntryPos0 = new vgui::TextEntry(this, "PosTextEntry0");
	m_TextEntryPos0->SetEnabled(true);
	m_TextEntryPos0->SetText("0 0 0");
	m_TextEntryPos0->SetBounds(5, 30, 230, 20);
	m_TextEntryPos0->SetMaximumCharCount(32);

	//create position 1 button
	vgui::Button* m_ButtonPos0 = new vgui::Button(this, "PosButton0", "Find Position 0", this, SETTINGS_PANEL_COMMAND_POS1);
	m_ButtonPos0->SetBounds(240, 30, 100, 20);
	
	//create position text 1
	m_TextEntryPos1 = new vgui::TextEntry(this, "PosTextEntry1");
	m_TextEntryPos1->SetEnabled(true);
	m_TextEntryPos1->SetText("0 0 0");
	m_TextEntryPos1->SetBounds(5, 55, 230, 20);
	m_TextEntryPos1->SetMaximumCharCount(32);

	//create position 2 button
	vgui::Button* m_ButtonPos1 = new vgui::Button(this, "PosButton1", "Find Position 1", this, SETTINGS_PANEL_COMMAND_POS2);
	m_ButtonPos1->SetBounds(240, 55, 100, 20);
	
	//create position text 3
	m_TextEntryPos2 = new vgui::TextEntry(this, "PosTextEntry0");
	m_TextEntryPos2->SetEnabled(true);
	m_TextEntryPos2->SetText("0 0 0");
	m_TextEntryPos2->SetBounds(5, 80, 230, 20);
	m_TextEntryPos2->SetMaximumCharCount(32);

	//create position 1 button
	vgui::Button* m_ButtonPos2 = new vgui::Button(this, "PosButton2", "Find Position 2", this, SETTINGS_PANEL_COMMAND_POS3);
	m_ButtonPos2->SetBounds(240, 80, 100, 20);

	// create position text 4
	m_TextEntryPos3 = new vgui::TextEntry(this, "PosTextEntry3");
	m_TextEntryPos3->SetEnabled(true);
	m_TextEntryPos3->SetText("0 0 0");
	m_TextEntryPos3->SetBounds(5, 105, 230, 20);
	m_TextEntryPos3->SetMaximumCharCount(32);

	// create position 4 button
	vgui::Button* m_ButtonPos3 = new vgui::Button(this, "PosButton3", "Find Position 3", this, SETTINGS_PANEL_COMMAND_POS4);
	m_ButtonPos3->SetBounds(240, 105, 100, 20);

	// create position text 5
	m_TextEntryPos4 = new vgui::TextEntry(this, "PosTextEntry4");
	m_TextEntryPos4->SetEnabled(true);
	m_TextEntryPos4->SetText("0 0 0");
	m_TextEntryPos4->SetBounds(5, 130, 230, 20);
	m_TextEntryPos4->SetMaximumCharCount(32);

	// create position 5 button
	vgui::Button* m_ButtonPos4 = new vgui::Button(this, "PosButton4", "Find Position 4", this, SETTINGS_PANEL_COMMAND_POS5);
	m_ButtonPos4->SetBounds(240, 130, 100, 20);

	// create position text 6
	m_TextEntryPos5 = new vgui::TextEntry(this, "PosTextEntry5");
	m_TextEntryPos5->SetEnabled(true);
	m_TextEntryPos5->SetText("0 0 0");
	m_TextEntryPos5->SetBounds(5, 155, 230, 20);
	m_TextEntryPos5->SetMaximumCharCount(32);

	// create position 6 button
	vgui::Button* m_ButtonPos5 = new vgui::Button(this, "PosButton5", "Find Position 5", this, SETTINGS_PANEL_COMMAND_POS6);
	m_ButtonPos5->SetBounds(240, 155, 100, 20);

	// create position text 7
	m_TextEntryPos6 = new vgui::TextEntry(this, "PosTextEntry6");
	m_TextEntryPos6->SetEnabled(true);
	m_TextEntryPos6->SetText("0 0 0");
	m_TextEntryPos6->SetBounds(5, 180, 230, 20);
	m_TextEntryPos6->SetMaximumCharCount(32);

	// create position 7 button
	vgui::Button* m_ButtonPos6 = new vgui::Button(this, "PosButton6", "Find Position 6", this, SETTINGS_PANEL_COMMAND_POS7);
	m_ButtonPos6->SetBounds(240, 180, 100, 20);
	
	// create position text 8
	m_TextEntryPos7 = new vgui::TextEntry(this, "PosTextEntry7");
	m_TextEntryPos7->SetEnabled(true);
	m_TextEntryPos7->SetText("0 0 0");
	m_TextEntryPos7->SetBounds(5, 205, 230, 20);
	m_TextEntryPos7->SetMaximumCharCount(32);

	// create position 8 button
	vgui::Button* m_ButtonPos7 = new vgui::Button(this, "PosButton7", "Find Position 7", this, SETTINGS_PANEL_COMMAND_POS8);
	m_ButtonPos7->SetBounds(240, 205, 100, 20);

	// create show soundscape positions checkbox
	m_ShowSoundscapePositions = new vgui::CheckButton(this, "ShowCheckox", "Show Soundscape Positions");
	m_ShowSoundscapePositions->SetBounds(75, 225, 200, 20);
	m_ShowSoundscapePositions->SetCommand(SETTINGS_PANEL_COMMAND_SHOW);
}

//-----------------------------------------------------------------------------
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundscapeSettingsPanel::OnCommand(const char* pszCommand)
{
	if (Q_strstr(pszCommand, "GetPos") == pszCommand)
	{
		//search for number
		pszCommand = pszCommand + 6;

		//execute command
		static ConCommand* cc = cvar->FindCommand("__ss_maker_start");
		if (cc)
		{
			//hide everything first
			g_SoundscapeMaker->SetAllVisible(false);

			CCommand args;
			args.Tokenize(CFmtStr("ssmaker %d", atoi(pszCommand)));
			cc->Dispatch(args);
		}

		return;
	}

	else if (!Q_strcmp(pszCommand, SETTINGS_PANEL_COMMAND_SHOW))
	{
		static ConVar* cv = cvar->FindVar("__ss_draw");
		if (cv)
			cv->SetValue(m_ShowSoundscapePositions->IsSelected());

		return;
	}

	BaseClass::OnCommand(pszCommand);
}

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
void CSoundscapeSettingsPanel::SetItem(int index, const Vector& value)
{
	const char* text = CFmtStr("%.3f %.3f %.3f", value.x, value.y, value.z);

	//check index
	switch (index)
	{
	case 0:
		m_TextEntryPos0->RequestFocus();
		m_TextEntryPos0->SetText(text);
		g_SoundscapePositions[0] = value;
		break;
	
	case 1:
		m_TextEntryPos1->RequestFocus();
		m_TextEntryPos1->SetText(text);
		g_SoundscapePositions[1] = value;
		break;
	
	case 2:
		m_TextEntryPos2->RequestFocus();
		m_TextEntryPos2->SetText(text);
		g_SoundscapePositions[2] = value;
		break;
	case 3:
		m_TextEntryPos3->RequestFocus();
		m_TextEntryPos3->SetText(text);
		g_SoundscapePositions[3] = value;
		break;
	
	case 4:
		m_TextEntryPos4->RequestFocus();
		m_TextEntryPos4->SetText(text);
		g_SoundscapePositions[4] = value;
		break;
	
	case 5:
		m_TextEntryPos5->RequestFocus();
		m_TextEntryPos5->SetText(text);
		g_SoundscapePositions[5] = value;
		break;

	case 6:
		m_TextEntryPos6->RequestFocus();
		m_TextEntryPos6->SetText(text);
		g_SoundscapePositions[6] = value;
		break;

	case 7:
		m_TextEntryPos7->RequestFocus();
		m_TextEntryPos7->SetText(text);
		g_SoundscapePositions[7] = value;
		break;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Called on text changed
//-----------------------------------------------------------------------------
void CSoundscapeSettingsPanel::OnTextChanged(KeyValues* kv)
{
	static ConCommand* cc = cvar->FindCommand("__ss_maker_set");

	//check focus
	if (m_TextEntryPos0->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos0->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[0].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 0 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

	//check focus
	if (m_TextEntryPos1->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos1->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[1].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 1 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

	//check focus
	if (m_TextEntryPos2->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos2->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[2].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 2 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

	//check focus
	if (m_TextEntryPos3->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos3->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[3].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 3 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

	//check focus
	if (m_TextEntryPos4->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos4->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[4].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 4 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

	//check focus
	if (m_TextEntryPos5->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos5->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[5].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 5 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

	//check focus
	if (m_TextEntryPos6->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos6->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[6].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 6 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

	//check focus
	if (m_TextEntryPos7->HasFocus())
	{
		//get text
		char buf[512];
		m_TextEntryPos7->GetText(buf, sizeof(buf));

		//convert to vector
		UTIL_StringToVector(g_SoundscapePositions[7].Base(), buf);

		//do command
		if (cc)
		{
			CCommand args;
			args.Tokenize(CFmtStr("ssmaker 7 %s", buf));
			cc->Dispatch(args);
		}

		return;
	}

}

//static soundscape settings panel
static CSoundscapeSettingsPanel* g_SettingsPanel = nullptr;


//button
class CSoundscapeButton : public vgui::Button
{
public:
	DECLARE_CLASS_SIMPLE(CSoundscapeButton, vgui::Button)

	CSoundscapeButton(vgui::Panel* parent, const char* name, const char* text, vgui::Panel* target = nullptr, const char* command = nullptr)
		: BaseClass(parent, name, text, target, command), m_bIsSelected(false) 
	{
		m_ColorSelected = Color(200, 200, 200, 200);
		m_FgColorSelected = Color(0, 0, 0, 255);
	}

	//apply scheme settings
	void ApplySchemeSettings(vgui::IScheme* scheme)
	{
		BaseClass::ApplySchemeSettings(scheme);

		m_ColorNotSelected = GetButtonArmedBgColor();
		m_FgColorNotSelectedd = GetButtonArmedFgColor();
	}

	//paints the background
	void PaintBackground()
	{
		if (m_bIsSelected)
			SetBgColor(m_ColorSelected);
		else
			SetBgColor(m_ColorNotSelected);

		BaseClass::PaintBackground();
	}
	
	//paints
	void Paint()
	{
		if (m_bIsSelected)
			SetFgColor(m_FgColorSelected);
		else
			SetFgColor(m_FgColorNotSelectedd);
			
		BaseClass::Paint();
	}

	//is this selected or not
	bool m_bIsSelected;
	static Color m_ColorSelected;
	static Color m_ColorNotSelected;
	static Color m_FgColorSelected;
	static Color m_FgColorNotSelectedd;
};

Color CSoundscapeButton::m_ColorSelected = Color();
Color CSoundscapeButton::m_ColorNotSelected = Color();
Color CSoundscapeButton::m_FgColorSelected = Color();
Color CSoundscapeButton::m_FgColorNotSelectedd = Color();


//soundscape combo box

class CSoundListComboBox : public vgui::ComboBox
{
public:
	DECLARE_CLASS_SIMPLE(CSoundListComboBox, vgui::ComboBox);

	CSoundListComboBox(Panel* parent, const char* panelName, int numLines, bool allowEdit) :
		BaseClass(parent, panelName, numLines, allowEdit) {}

	//on key typed. check for menu item with text inside it and if found then
	//select that item.
	void OnKeyTyped(wchar_t unichar)
	{
		//check for ctrl or shift down
		if (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LCONTROL) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RCONTROL) || unichar == '`')
			return;

		//open up this combo box
		if (unichar == 13)
		{
			ShowMenu();
			return;
		}

		BaseClass::OnKeyTyped(unichar);

		//check for backspace
		if (unichar == 8 || unichar == '_')
			return;

		//get text
		char buf[512];
		GetText(buf, sizeof(buf));

		//start from current index + 1
		int start = GetMenu()->GetActiveItem() + 1;

		//look for sound with same name starting from the start first
		for (int i = start; i < g_SoundDirectories.Count(); i++)
		{
			if (Q_stristr(g_SoundDirectories[i], buf))
			{
				GetMenu()->SetCurrentlyHighlightedItem(i);
				return;
			}
		}
		
		//now cheeck from 0 to the start
		for (int i = 0; i < start; i++)
		{
			if (Q_stristr(g_SoundDirectories[i], buf))
			{
				GetMenu()->SetCurrentlyHighlightedItem(i);
				return;
			}
		}
	}
};


//sounds list panel

#define SOUND_LIST_PANEL_WIDTH 375
#define SOUND_LIST_PANEL_HEIGHT 255
#define SOUND_LIST_PLAY_COMMAND "PlaySound"
#define SOUND_LIST_STOP_COMMAND "StopSound"
#define SOUND_LIST_INSERT_COMMAND "Insert"
#define SOUND_LIST_RELOAD_COMMAND "Reload"
#define SOUND_LIST_SEARCH_COMMAND "Search"

class CSoundListPanel : public vgui::Frame
{
public:
	DECLARE_CLASS_SIMPLE(CSoundListPanel, vgui::Frame);

	CSoundListPanel(vgui::VPANEL parent, const char* name);

	//initalizes sound combo box
	void InitalizeSounds();

	//other
	void OnCommand(const char* pszCommand);
	void OnClose();

private:
	friend class CSoundscapeMaker;

	CSoundListComboBox* m_SoundsList;
	vgui::TextEntry* m_SearchText;
	vgui::Button* m_SearchButton;
	vgui::Button* m_PlayButton;
	vgui::Button* m_StopSoundButton;
	vgui::Button* m_InsertButton;
	vgui::Button* m_ReloadSounds;

	//current sound guid
	int m_iSongGuid = -1;
};

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSoundListPanel::CSoundListPanel(vgui::VPANEL parent, const char* name)
	: BaseClass(nullptr, name)
{
	SetParent(parent);

	SetKeyBoardInputEnabled(true);
	SetMouseInputEnabled(true);

	SetProportional(false);
	SetTitleBarVisible(true);
	SetMinimizeButtonVisible(false);
	SetMaximizeButtonVisible(false);
	SetCloseButtonVisible(true);
	SetSizeable(false);
	SetMoveable(true);
	SetVisible(false);

	//set the size and pos
	int ScreenWide, ScreenTall;
	vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);

	SetTitle("Sounds List", true);
	SetSize(SOUND_LIST_PANEL_WIDTH, SOUND_LIST_PANEL_HEIGHT);
	SetPos((ScreenWide - SOUND_LIST_PANEL_WIDTH) / 2, (ScreenTall - SOUND_LIST_PANEL_HEIGHT) / 2);

	SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));

	//create combo box
	m_SoundsList = new CSoundListComboBox(this, "SoundsList", 20, true);
	m_SoundsList->SetBounds(5, 25, SOUND_LIST_PANEL_WIDTH - 15, 20);
	m_SoundsList->AddActionSignalTarget(this);
	
	//make divider
	vgui::Divider* divider1 = new vgui::Divider(this, "Divider");
	divider1->SetBounds(-5, 48, SOUND_LIST_PANEL_WIDTH + 10, 2);

	//create text
	vgui::Label* label1 = new vgui::Label(this, "FindSound", "Find Sound");
	label1->SetBounds(147, 51, 120, 20);

	//create text entry
	m_SearchText = new vgui::TextEntry(this, "SearchTextEntry");
	m_SearchText->SetBounds(5, 75, SOUND_LIST_PANEL_WIDTH - 15, 20);
	m_SearchText->SetEnabled(true);
	m_SearchText->SetText("");

	//create search for button
	m_SearchButton = new vgui::Button(this, "SearchButton", "Search For");
	m_SearchButton->SetBounds(5, 100, SOUND_LIST_PANEL_WIDTH - 15, 20);;
	m_SearchButton->SetEnabled(true);
	m_SearchButton->SetCommand(SOUND_LIST_SEARCH_COMMAND);

	//make divider
	vgui::Divider* divider2 = new vgui::Divider(this, "Divider");
	divider2->SetBounds(-5, 124, SOUND_LIST_PANEL_WIDTH + 10, 2);

	//create text
	vgui::Label* label2 = new vgui::Label(this, "SoundButtons", "Sound Buttons");
	label2->SetBounds(140, 127, 120, 20);

	//create play button
	m_PlayButton = new vgui::Button(this, "PlayButton", "Play Sound", this);
	m_PlayButton ->SetBounds(5, 150, SOUND_LIST_PANEL_WIDTH - 15, 20);
	m_PlayButton->SetCommand(SOUND_LIST_PLAY_COMMAND);

	//create stop sound button
	m_StopSoundButton = new vgui::Button(this, "StopSound", "Stop Sound", this);
	m_StopSoundButton ->SetBounds(5, 175, SOUND_LIST_PANEL_WIDTH - 15, 20);
	m_StopSoundButton->SetCommand(SOUND_LIST_STOP_COMMAND);

	//create sound insert button
	m_InsertButton = new vgui::Button(this, "InsertSound", "Insert Sound", this);
	m_InsertButton ->SetBounds(5, 200, SOUND_LIST_PANEL_WIDTH - 15, 20);
	m_InsertButton->SetCommand(SOUND_LIST_INSERT_COMMAND);

	//create reload sounds button
	m_ReloadSounds = new vgui::Button(this, "ReloadSounds", "Reload Sounds", this);
	m_ReloadSounds ->SetBounds(5, 225, SOUND_LIST_PANEL_WIDTH - 15, 20);
	m_ReloadSounds->SetCommand(SOUND_LIST_RELOAD_COMMAND);
}

//-----------------------------------------------------------------------------
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundListPanel::OnCommand(const char* pszCommand)
{
	if (!Q_strcmp(pszCommand, SOUND_LIST_SEARCH_COMMAND))
	{
		//get text
		char buf[512];
		m_SearchText->GetText(buf, sizeof(buf));

		//start from current index + 1
		int start = m_SoundsList->GetMenu()->GetActiveItem() + 1;

		//look for sound with same name starting from the start first
		for (int i = start; i < g_SoundDirectories.Count(); i++)
		{
			if (Q_stristr(g_SoundDirectories[i], buf))
			{
				//select item
				m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
				m_SoundsList->ActivateItem(i);

				//set text
				m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
				return;
			}
		}


		//now cheeck from 0 to the start
		for (int i = 0; i < start; i++)
		{
			if (Q_stristr(g_SoundDirectories[i], buf))
			{
				//select item
				m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
				m_SoundsList->ActivateItem(i);
				
				//set text
				m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
				return;
			}
		}

		return;
	}
	else if (!Q_strcmp(pszCommand, SOUND_LIST_PLAY_COMMAND)) 
	{
		//get the sound
		char buf[512];
		m_SoundsList->GetText(buf, sizeof(buf));

		//stop the sound
		if (enginesound->IsSoundStillPlaying(m_iSongGuid))
		{
			enginesound->StopSoundByGuid(m_iSongGuid);
			m_iSongGuid = -1;
		}

		//precache and play the sound
		if (!enginesound->IsSoundPrecached(buf))
			enginesound->PrecacheSound(buf);
		
		enginesound->EmitAmbientSound(buf, 1, 100);
		m_iSongGuid = enginesound->GetGuidForLastSoundEmitted();
		return;
	}
	else if (!Q_strcmp(pszCommand, SOUND_LIST_STOP_COMMAND)) 
	{
		//stop the sound
		if (m_iSongGuid != -1 && enginesound->IsSoundStillPlaying(m_iSongGuid))
		{
			enginesound->StopSoundByGuid(m_iSongGuid);
			m_iSongGuid = -1;
		}

		return;
	}
	else if (!Q_strcmp(pszCommand, SOUND_LIST_INSERT_COMMAND))
	{
		//make not visible
		SetVisible(false);

		//stop the sound
		if (enginesound->IsSoundStillPlaying(m_iSongGuid))
		{
			enginesound->StopSoundByGuid(m_iSongGuid);
			m_iSongGuid = -1;
		}

		//get the sound
		char buf[512];
		m_SoundsList->GetText(buf, sizeof(buf));

		//set the sound text
		g_SoundscapeMaker->SetSoundText(buf);
		return;
	}
	else if (!Q_strcmp(pszCommand, SOUND_LIST_RELOAD_COMMAND))
	{
		//clear everything for the combo box and reload it
		m_SoundsList->RemoveAll();

		InitalizeSounds();
		return;
	}

	BaseClass::OnCommand(pszCommand);
}

//-----------------------------------------------------------------------------
// Purpose: Called on panel close
//-----------------------------------------------------------------------------
void CSoundListPanel::OnClose()
{
	OnCommand(SOUND_LIST_STOP_COMMAND);
	BaseClass::OnClose();
}

//-----------------------------------------------------------------------------
// Purpose: Initalizes the sounds list
//-----------------------------------------------------------------------------
void CSoundListPanel::InitalizeSounds()
{
	//get the sound array
	GetSoundNames();

	//add all the sounds
	for (int i = 0; i < g_SoundDirectories.Size(); i++)
		m_SoundsList->AddItem(g_SoundDirectories[i], nullptr);

	m_SoundsList->ActivateItem(0);
}

//static sound list instance
static CSoundListPanel* g_SoundPanel = nullptr;
static bool g_SoundPanelInitalized = false;


//soundscape list


#define ADD_SOUNDSCAPE_COMMAND "AddSoundscape"


//soundscape list class
class CSoundscapeList : public vgui::Divider
{
public:
	DECLARE_CLASS_SIMPLE(CSoundscapeList, vgui::Divider);

	//constructor
	CSoundscapeList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height);

	//menu item stuff
	virtual void AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent);
	virtual void Clear();

	//other
	virtual void OnMouseWheeled(int delta); 
	virtual void OnMouseReleased(vgui::MouseCode code);

	virtual void OnCommand(const char* pszCommand);
	virtual void PaintBackground();

	//message funcs
	MESSAGE_FUNC_INT(ScrollBarMoved, "ScrollBarSliderMoved", position);

protected:
	friend class CSoundscapeMaker;

	//keyvalue list.
	KeyValues* m_Keyvalues;

	//says "Soundscapes List"
	vgui::Label* m_pLabel;
	vgui::ScrollBar* m_pSideSlider;

	//menu
	vgui::Menu* menu;

	//menu button stuff
	CUtlVector<CSoundscapeButton*> m_MenuButtons;
	int m_iCurrentY;
	int m_iMax;
	int m_AmtAdded;
};

//-----------------------------------------------------------------------------
// Purpose: Constructor for soundscape list panel
//-----------------------------------------------------------------------------
CSoundscapeList::CSoundscapeList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
	: BaseClass(parent, name)
{
	//create the text
	m_pLabel = new vgui::Label(this, "ListsText", text);
	m_pLabel->SetVisible(true);
	m_pLabel->SetBounds(text_x_pos, 2, 150, 20);

	//create the side slider
	m_pSideSlider = new vgui::ScrollBar(this, "ListsSlider", true);
	m_pSideSlider->SetBounds(width - 20, 0, 20, height - 2);
	m_pSideSlider->SetValue(0);
	m_pSideSlider->SetEnabled(false);
	m_pSideSlider->SetRange(0, 0);
	m_pSideSlider->SetButtonPressedScrollValue(1);
	m_pSideSlider->SetRangeWindow(0);
	m_pSideSlider->AddActionSignalTarget(this);

	m_iCurrentY = 22;
	m_iMax = max;
	m_Keyvalues = nullptr;
}

//-----------------------------------------------------------------------------
// Purpose: adds a button to the soundscape list
//-----------------------------------------------------------------------------
void CSoundscapeList::AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent)
{
	//create a new button
	CSoundscapeButton* button = new CSoundscapeButton(this, name, text, parent, command);
	button->SetBounds(5, m_iCurrentY, GetWide() - 30, 20);

	//increment current y
	m_iCurrentY = m_iCurrentY + 22;

	//add button to array
	m_MenuButtons.AddToTail(button);

	//if the count is more then m_iMax then set slider value
	if (m_MenuButtons.Count() > m_iMax)
	{
		int max = m_MenuButtons.Count() - m_iMax;

		m_pSideSlider->SetRange(0, max);
		m_pSideSlider->SetRangeWindow(1);
		m_pSideSlider->SetEnabled(true);
	}

	m_AmtAdded++;

	//check to see if we need to scroll down
	if (m_MenuButtons.Count() >= m_iMax)
		OnMouseWheeled(-1);
}

//-----------------------------------------------------------------------------
// Purpose: Clears everything for this list
//-----------------------------------------------------------------------------
void CSoundscapeList::Clear()
{
	//reset the slider
	m_pSideSlider->SetValue(0);
	m_pSideSlider->SetEnabled(false);
	m_pSideSlider->SetRange(0, 0);
	m_pSideSlider->SetButtonPressedScrollValue(1);
	m_pSideSlider->SetRangeWindow(0);

	//delete and clear the buttons
	for (int i = 0; i < m_MenuButtons.Count(); i++)
		m_MenuButtons[i]->DeletePanel();

	m_MenuButtons.RemoveAll();

	//reset current y
	m_iCurrentY = 22;

	m_AmtAdded = 0;
}

//-----------------------------------------------------------------------------
// Purpose: Called when a mouse is wheeled
//-----------------------------------------------------------------------------
void CSoundscapeList::OnMouseWheeled(int delta)
{
	//check for scroll down
	if (delta == -1)
		m_pSideSlider->SetValue(m_pSideSlider->GetValue() + 1);

	//check for scroll up
	else if (delta == 1)
		m_pSideSlider->SetValue(m_pSideSlider->GetValue() - 1);
}

//-----------------------------------------------------------------------------
// Purpose: Called when a mouse code is released
//-----------------------------------------------------------------------------
void CSoundscapeList::OnMouseReleased(vgui::MouseCode code)
{
	if (code != vgui::MouseCode::MOUSE_RIGHT)
		return;

	//get cursor pos
	int x, y;
	vgui::surface()->SurfaceGetCursorPos(x, y);

	//create menu
	menu = new vgui::Menu(this, "Menu");
	menu->AddMenuItem("AddSoundscape", "Add Soundscape", ADD_SOUNDSCAPE_COMMAND, this);
	menu->SetBounds(x, y, 200, 50);
	menu->SetVisible(true);
}

//-----------------------------------------------------------------------------
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundscapeList::OnCommand(const char* pszCommand)
{
	if (!Q_strcmp(pszCommand, ADD_SOUNDSCAPE_COMMAND))
	{
		const char* name = CFmtStr("New Soundscape %d", m_AmtAdded);
		AddButton(name, name, name, GetParent());

		//add to keyvalues file
		KeyValues* kv = new KeyValues(name);
		KeyValues* tmp = m_Keyvalues;
		KeyValues* tmp2 = tmp;

		//get last subkey
		while (tmp != nullptr)
		{
			tmp2 = tmp;
			tmp = tmp->GetNextTrueSubKey();
		}

		//add to last subkey
		tmp2->SetNextKey(kv);

		GetParent()->OnCommand(name);
		return;
	}

	BaseClass::OnCommand(pszCommand);
}

//-----------------------------------------------------------------------------
// Purpose: Paints the background
//-----------------------------------------------------------------------------
void CSoundscapeList::PaintBackground()
{
	//colors
	static Color EnabledColor = Color(100, 100, 100, 200);
	static Color DisabledColor = Color(60, 60, 60, 200);

	//if m_KeyValues then paint the default color
	if (m_Keyvalues)
		SetBgColor(EnabledColor);
	else
		SetBgColor(DisabledColor);

	BaseClass::PaintBackground();
}

//-----------------------------------------------------------------------------
// Purpose: Called on scroll bar moved
//-----------------------------------------------------------------------------
void CSoundscapeList::ScrollBarMoved(int delta)
{
	int position = m_pSideSlider->GetValue();

	//move everything down (if needed)
	for (int i = 0; i < m_MenuButtons.Count(); i++)
	{
		//make not visible if i < position
		if (i < position)
		{
			m_MenuButtons[i]->SetVisible(false);
			continue;
		}

		m_MenuButtons[i]->SetPos(5, 22 * ((i - position) + 1));
		m_MenuButtons[i]->SetVisible(true);
	}
}




//soundscape data list


#define NEW_PLAYLOOPING_COMMAND "NewLooping"
#define NEW_SOUNDSCAPE_COMMAND "NewSoundscape"
#define NEW_RANDOM_COMMAND "NewRandom"


class CSoundscapeDataList : public CSoundscapeList
{
public:
	DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
	
	CSoundscapeDataList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
		: CSoundscapeList(parent, name, text, text_x_pos, max, width, height)
	{}

	//override right click functionality
	virtual void OnMouseReleased(vgui::MouseCode code);

	void OnCommand(const char* pszCommand);

private:
	friend class CSoundscapeMaker;
};


//-----------------------------------------------------------------------------
// Purpose: Called when a mouse code is released
//-----------------------------------------------------------------------------
void CSoundscapeDataList::OnMouseReleased(vgui::MouseCode code)
{
	//if no soundscape is selected or mouse code != right then return
	if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
		return;

	//get cursor pos
	int x, y;
	vgui::surface()->SurfaceGetCursorPos(x, y);

	//create menu
	menu = new vgui::Menu(this, "Menu");
	menu->AddMenuItem("AddLooping", "Add Looping Sound", NEW_PLAYLOOPING_COMMAND, this);
	menu->AddMenuItem("AddSoundscape", "Add Soundscape", NEW_SOUNDSCAPE_COMMAND, this);
	menu->AddMenuItem("AddSoundscape", "Add Random Sounds", NEW_RANDOM_COMMAND, this);
	menu->SetBounds(x, y, 200, 50);
	menu->SetVisible(true);
}


//-----------------------------------------------------------------------------
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundscapeDataList::OnCommand(const char* pszCommand)
{
	if (!Q_strcmp(pszCommand, NEW_PLAYLOOPING_COMMAND))
	{
		int LoopingNum = 0;
		FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
		{
			//store data name
			const char* name = data->GetName();

			//increment variables based on name
			if (!Q_strcasecmp(name, "playlooping"))
				LoopingNum++;
		}

		//add the keyvalue to both this and the keyvalues
		AddButton("playlooping", "playlooping", CFmtStr("$playlooping%d", LoopingNum + 1), GetParent());

		//add the keyvalues
		KeyValues* kv = new KeyValues("playlooping");
		kv->SetFloat("volume", 1);
		kv->SetInt("pitch", 100);

		m_Keyvalues->AddSubKey(kv);

		GetParent()->OnCommand(CFmtStr("$playlooping%d", LoopingNum + 1));

		return;
	}
	else if (!Q_strcmp(pszCommand, NEW_SOUNDSCAPE_COMMAND))
	{
		int SoundscapeNum = 0;
		FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
		{
			//store data name
			const char* name = data->GetName();

			//increment variables based on name
			if (!Q_strcasecmp(name, "playsoundscape"))
				SoundscapeNum++;
		}

		AddButton("playsoundscape", "playsoundscape", CFmtStr("$playsoundscape%d", SoundscapeNum + 1), GetParent());

		//add the keyvalues
		KeyValues* kv = new KeyValues("playsoundscape");
		kv->SetFloat("volume", 1);

		//add the keyvalue to both this and the keyvalues
		m_Keyvalues->AddSubKey(kv);

		GetParent()->OnCommand(CFmtStr("$playsoundscape%d", SoundscapeNum + 1));

		return;
	}
	else if (!Q_strcmp(pszCommand, NEW_RANDOM_COMMAND))
	{
		int RandomNum = 0;
		FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
		{
			//store data name
			const char* name = data->GetName();

			//increment variables based on name
			if (!Q_strcasecmp(name, "playrandom"))
				RandomNum++;
		}

		AddButton("playrandom", "playrandom", CFmtStr("$playrandom%d", RandomNum + 1), GetParent());

		//add the keyvalues
		KeyValues* kv = new KeyValues("playrandom");
		kv->SetString("volume", "0.5,0.8");
		kv->SetInt("pitch", 100);
		kv->SetString("time", "10,20");
		
		//make rndwave subkey
		KeyValues* rndwave = new KeyValues("rndwave");
		kv->AddSubKey(rndwave);

		//add the keyvalue to both this and the keyvalues
		m_Keyvalues->AddSubKey(kv);

		//make the parent show the new item
		GetParent()->OnCommand(CFmtStr("$playrandom%d", RandomNum + 1));

		return;
	}

	BaseClass::OnCommand(pszCommand);
}


//soundscape rndwave data list


#define NEW_RNDWAVE_WAVE_COMMAND "NewRNDWave"


class CSoundscapeRndwaveList : public CSoundscapeList
{
public:
	DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
	
	CSoundscapeRndwaveList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
		: CSoundscapeList(parent, name, text, text_x_pos, max, width, height)
	{}

	//override right click functionality
	virtual void OnMouseReleased(vgui::MouseCode code);

	void OnCommand(const char* pszCommand);

private:
	friend class CSoundscapeMaker;
};


//-----------------------------------------------------------------------------
// Purpose: Called when a mouse code is released
//-----------------------------------------------------------------------------
void CSoundscapeRndwaveList::OnMouseReleased(vgui::MouseCode code)
{
	//if no soundscape is selected or mouse code != right then return
	if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
		return;

	//get cursor pos
	int x, y;
	vgui::surface()->SurfaceGetCursorPos(x, y);

	//create menu
	menu = new vgui::Menu(this, "Menu");
	menu->AddMenuItem("AddRandom", "Add Random Wave", NEW_RNDWAVE_WAVE_COMMAND, this);
	menu->SetBounds(x, y, 200, 50);
	menu->SetVisible(true);
}


//-----------------------------------------------------------------------------
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundscapeRndwaveList::OnCommand(const char* pszCommand)
{
	if (!Q_strcmp(pszCommand, NEW_RNDWAVE_WAVE_COMMAND))
	{
		//get number of keyvalues
		int num = 0;

		FOR_EACH_VALUE(m_Keyvalues, kv)
			num++;
		
		//add keyvalues and button
		AddButton("Rndwave", "", CFmtStr("$rndwave%d", num + 1), GetParent());

		KeyValues* add = new KeyValues("wave");
		add->SetString(nullptr, "");
		m_Keyvalues->AddSubKey(add);

		//forward command to parent
		GetParent()->OnCommand(CFmtStr("$rndwave%d", num + 1));

		return;
	}

	BaseClass::OnCommand(pszCommand);
}



//soundscape panel


#define SOUNDSCAPE_PANEL_WIDTH 760
#define SOUNDSCAPE_PANEL_HEIGHT 630

#define NEW_BUTTON_COMMAND "$NewSoundscape"
#define SAVE_BUTTON_COMMAND "$SaveSoundscape"
#define LOAD_BUTTON_COMMAND "$LoadSoundscape"
#define OPTIONS_BUTTON_COMMAND "$ShowOptions"
#define RESET_BUTTON_COMMAND "$ResetSoundscapes"
#define SOUNDS_LIST_BUTTON_COMMAND "$ShowSoundsList"
#define PLAY_SOUNDSCAPE_COMMAND "$PlaySoundscape"
#define RESET_SOUNDSCAPE_BUTTON_COMMAND "$ResetSoundscape"
#define DELETE_CURRENT_ITEM_COMMAND "$DeleteItem"

//static bool to determin if the soundscape panel should show or not
bool g_ShowSoundscapePanel = true;
bool g_IsPlayingSoundscape = false;

//soundscape maker panel
class CSoundscapeMaker : public vgui::Frame, CAutoGameSystem
{
public:
	DECLARE_CLASS_SIMPLE(CSoundscapeMaker, vgui::Frame)

	CSoundscapeMaker(vgui::VPANEL parent);

	//tick functions
	void OnTick();

	//other functions
	void OnClose();
	void OnCommand(const char* pszCommand);

	void PlaySelectedSoundscape();
	void LoadFile(KeyValues* file);

	void OnKeyCodePressed(vgui::KeyCode code);

	void SetSoundText(const char* text);

	//to play the soundscape on map spawn
	void LevelInitPostEntity();

	//message pointer funcs
	MESSAGE_FUNC_CHARPTR(OnFileSelected, "FileSelected", fullpath);
	MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);

	~CSoundscapeMaker();

private:
	//the soundscape keyvalues file
	KeyValues* m_KeyValues = nullptr;

private:
	void CreateEverything();

private:
	//lists all the soundscapes
	CSoundscapeList* m_SoundscapesList;
	CSoundscapeDataList* m_pDataList;
	CSoundscapeRndwaveList* m_pSoundList;

	//buttons
	vgui::Button* m_ButtonNew = nullptr;
	vgui::Button* m_ButtonSave = nullptr;
	vgui::Button* m_ButtonLoad = nullptr;

	//file load and save dialogs
	vgui::FileOpenDialog* m_FileSave = nullptr;
	vgui::FileOpenDialog* m_FileLoad = nullptr;
	bool m_bWasFileLoad = false;

	//text entry for name
	vgui::TextEntry* m_TextEntryName;

	//combo box for dsp effects
	vgui::ComboBox* m_DspEffects;
	vgui::ComboBox* m_SoundLevels;

	//sound data text entry
	vgui::TextEntry* m_TimeTextEntry;
	vgui::TextEntry* m_VolumeTextEntry;
	vgui::TextEntry* m_PitchTextEntry;
	vgui::TextEntry* m_PositionTextEntry;
	vgui::TextEntry* m_SoundNameTextEntry;

	//play sound button
	vgui::Button* m_SoundNamePlay;

	//play/reset soundscape buttons
	vgui::CheckButton* m_PlaySoundscapeButton;
	vgui::Button* m_ResetSoundscapeButton;
	vgui::Button* m_DeleteCurrentButton;

	//current selected soundscape
	CSoundscapeButton* m_pCurrentSelected = nullptr;
	KeyValues* m_kvCurrSelected = nullptr;
	KeyValues* m_kvCurrSound = nullptr;
	KeyValues* m_kvCurrRndwave = nullptr;

	int m_iCurrRndWave = 0;

	//currently in non randomwave thing
	SoundscapeMode m_iSoundscapeMode = SoundscapeMode::Mode_Random;

	//temporary added soundscapes
	CUtlVector<KeyValues*> m_TmpAddedSoundscapes;
};

//user message hook
void _SoundscapeMaker_Recieve(bf_read& bf);

//-----------------------------------------------------------------------------
// Purpose: Constructor for soundscape maker panel
//-----------------------------------------------------------------------------
CSoundscapeMaker::CSoundscapeMaker(vgui::VPANEL parent)
	: BaseClass(nullptr, "SoundscapeMaker")
{
	static bool bRegistered = false;
	if (!bRegistered)
	{
		usermessages->HookMessage("SoundscapeMaker_Recieve", _SoundscapeMaker_Recieve);
		bRegistered = true;
	}

	//set variables
	m_pCurrentSelected = nullptr;

	SetParent(parent);
	
	SetKeyBoardInputEnabled(true);
	SetMouseInputEnabled(true);

	SetProportional(false);
	SetTitleBarVisible(true);
	SetMinimizeButtonVisible(false);
	SetMaximizeButtonVisible(false);
	SetCloseButtonVisible(true);
	SetSizeable(false);
	SetMoveable(true);
	SetVisible(g_ShowSoundscapePanel);
	
	int ScreenWide, ScreenTall;
	vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);

	SetTitle("Soundscape Maker (New File)", true);
	SetSize(SOUNDSCAPE_PANEL_WIDTH, SOUNDSCAPE_PANEL_HEIGHT);
	SetPos((ScreenWide - SOUNDSCAPE_PANEL_WIDTH) / 2, (ScreenTall - SOUNDSCAPE_PANEL_HEIGHT) / 2);

	SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));

	//add a tick signal for every 50 ms
	vgui::ivgui()->AddTickSignal(GetVPanel(), 50);

	CreateEverything();
}

//-----------------------------------------------------------------------------
// Purpose: Creates everything for this panel
//-----------------------------------------------------------------------------
void CSoundscapeMaker::CreateEverything()
{
	//create the divider that will be the outline for the inside of the panel
	vgui::Divider* PanelOutline = new vgui::Divider(this, "InsideOutline");
	PanelOutline->SetEnabled(false);
	PanelOutline->SetBounds(5, 25, SOUNDSCAPE_PANEL_WIDTH - 10, SOUNDSCAPE_PANEL_HEIGHT - 62);

	//create the buttons
		//create the buttons
	m_ButtonNew = new vgui::Button(this, "NewButton", "New Soundscape File");
	m_ButtonNew->SetVisible(true);
	m_ButtonNew->SetBounds(55, 600, 165, 25);
	m_ButtonNew->SetCommand(NEW_BUTTON_COMMAND);
	m_ButtonNew->SetDepressedSound("ui/buttonclickrelease.wav");

	m_ButtonSave = new vgui::Button(this, "SaveButton", "Save Soundscapes");
	m_ButtonSave->SetVisible(true);
	m_ButtonSave->SetBounds(225, 600, 165, 25);
	m_ButtonSave->SetCommand(SAVE_BUTTON_COMMAND);
	m_ButtonSave->SetDepressedSound("ui/buttonclickrelease.wav");

	m_ButtonLoad = new vgui::Button(this, "LoadButton", "Load Soundscapes");
	m_ButtonLoad->SetVisible(true);
	m_ButtonLoad->SetBounds(395, 600, 165, 25);
	m_ButtonLoad->SetCommand(LOAD_BUTTON_COMMAND);
	m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");
	
	m_ButtonLoad = new vgui::Button(this, "LoadButton", "Show Options Panel");
	m_ButtonLoad->SetVisible(true);
	m_ButtonLoad->SetBounds(565, 600, 165, 25);
	m_ButtonLoad->SetCommand(OPTIONS_BUTTON_COMMAND);
	m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");

	//create the soundscapes menu
	m_SoundscapesList = new CSoundscapeList(this, "SoundscapesList", "Soundscapes:", 90, 22, 300, 550);
	m_SoundscapesList->SetBounds(15, 35, 300, 550);
	m_SoundscapesList->SetVisible(true);

	//create data list
	m_pDataList = new CSoundscapeDataList(this, "SoudscapeDataList", "Soundscape Data:", 35, 10, 200, 310);
	m_pDataList->SetBounds(327, 275, 200, 310);
	m_pDataList->SetVisible(true);
	
	//create sound list
	m_pSoundList = new CSoundscapeRndwaveList(this, "SoudscapeDataList", "Random Sounds:", 40, 10, 200, 310);
	m_pSoundList->SetBounds(542, 275, 200, 310);
	m_pSoundList->SetVisible(true);

	//name text entry
	m_TextEntryName = new vgui::TextEntry(this, "NameTextEntry");
	m_TextEntryName->SetEnabled(false);
	m_TextEntryName->SetBounds(325, 40, 295, 20);
	m_TextEntryName->SetMaximumCharCount(50);

	//dsp effects combo box
	m_DspEffects = new vgui::ComboBox(this, "DspEffects", sizeof(g_DspEffects) / sizeof(g_DspEffects[0]), false);
	m_DspEffects->SetEnabled(false);
	m_DspEffects->SetBounds(325, 65, 295, 20);
	m_DspEffects->SetText("");
	m_DspEffects->AddActionSignalTarget(this);

	for (int i = 0; i < sizeof(g_DspEffects) / sizeof(g_DspEffects[i]); i++)
		m_DspEffects->AddItem(g_DspEffects[i], nullptr);

	//time text entry
	m_TimeTextEntry = new vgui::TextEntry(this, "TimeTextEntry");
	m_TimeTextEntry->SetBounds(325, 90, 295, 20);
	m_TimeTextEntry->SetEnabled(false);
	m_TimeTextEntry->SetVisible(true);

	//volume text entry
	m_VolumeTextEntry = new vgui::TextEntry(this, "VolumeTextEntry");
	m_VolumeTextEntry->SetBounds(325, 115, 295, 20);
	m_VolumeTextEntry->SetEnabled(false);
	m_VolumeTextEntry->SetVisible(true);

	//pitch text entry
	m_PitchTextEntry = new vgui::TextEntry(this, "PitchTextEntry");
	m_PitchTextEntry->SetBounds(325, 140, 295, 20);
	m_PitchTextEntry->SetEnabled(false);
	m_PitchTextEntry->SetVisible(true);
	
	//position text entry
	m_PositionTextEntry = new vgui::TextEntry(this, "PositionTextEntry");
	m_PositionTextEntry->SetBounds(325, 165, 295, 20);
	m_PositionTextEntry->SetEnabled(false);
	m_PositionTextEntry->SetVisible(true);
	
	//sound levels
	m_SoundLevels = new vgui::ComboBox(this, "SoundLevels", sizeof(g_SoundLevels) / sizeof(g_SoundLevels[0]), false);
	m_SoundLevels->SetEnabled(false);
	m_SoundLevels->SetBounds(325, 190, 295, 20);
	m_SoundLevels->SetText("");
	m_SoundLevels->AddActionSignalTarget(this);

	for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
		m_SoundLevels->AddItem(g_SoundLevels[i], nullptr);
	
	//sound name
	m_SoundNameTextEntry = new vgui::TextEntry(this, "SoundName");
	m_SoundNameTextEntry->SetBounds(325, 215, 215, 20);
	m_SoundNameTextEntry->SetEnabled(false);
	m_SoundNameTextEntry->SetVisible(true);

	//play sound button
	m_SoundNamePlay = new vgui::Button(this, "SoundPlayButton", "Sounds List");
	m_SoundNamePlay->SetBounds(545, 215, 75, 20);
	m_SoundNamePlay->SetCommand(SOUNDS_LIST_BUTTON_COMMAND);
	m_SoundNamePlay->SetEnabled(false);

	//starts the soundscape
	m_PlaySoundscapeButton = new vgui::CheckButton(this, "PlaySoundscape", "Play Soundscape");
	m_PlaySoundscapeButton->SetBounds(330, 243, 125, 20);
	m_PlaySoundscapeButton->SetCommand(PLAY_SOUNDSCAPE_COMMAND);
	m_PlaySoundscapeButton->SetEnabled(false);
	m_PlaySoundscapeButton->SetSelected(false);

	//reset soundscape button
	m_ResetSoundscapeButton = new vgui::Button(this, "ResetSoundscape", "Restart Soundscape");
	m_ResetSoundscapeButton->SetBounds(465, 243, 125, 20);
	m_ResetSoundscapeButton->SetCommand(RESET_SOUNDSCAPE_BUTTON_COMMAND);
	m_ResetSoundscapeButton->SetEnabled(false);

	//delete this item
	m_DeleteCurrentButton = new vgui::Button(this, "DeleteItem", "Delete Current Item");
	m_DeleteCurrentButton->SetBounds(595, 243, 135, 20);
	m_DeleteCurrentButton->SetCommand(DELETE_CURRENT_ITEM_COMMAND);
	m_DeleteCurrentButton->SetEnabled(false);

	//create the soundscape name text
	vgui::Label* NameLabel = new vgui::Label(this, "NameLabel", "Soundscape Name");
	NameLabel->SetBounds(635, 40, 125, 20);

	//create the soundscape dsp text
	vgui::Label* DspLabel = new vgui::Label(this, "DspLabel", "Soundscape Dsp");
	DspLabel->SetBounds(635, 65, 125, 20);
	
	//create the soundscape time text
	vgui::Label* TimeLabel = new vgui::Label(this, "TimeLabel", "Sound Time");
	TimeLabel->SetBounds(635, 90, 125, 20);
	
	//create the soundscape volumn text
	vgui::Label* VolumeLabel = new vgui::Label(this, "VolumeLabel", "Sound Volume");
	VolumeLabel->SetBounds(635, 115, 125, 20);

	//create the soundscape pitch text
	vgui::Label* PitchLabel = new vgui::Label(this, "PitchLabel", "Sound Pitch");
	PitchLabel->SetBounds(635, 140, 125, 20);
	
	//create the soundscape position text
	vgui::Label* PositionLabel = new vgui::Label(this, "PositionLabel", "Sound Position");
	PositionLabel->SetBounds(635, 165, 125, 20);

	//create the soundscape sound level text
	vgui::Label* SoundLevelLabel = new vgui::Label(this, "SoundLevelLabel", "Sound Level");
	SoundLevelLabel ->SetBounds(635, 190, 125, 20);

	//create the soundscape sound name text
	vgui::Label* SoundName = new vgui::Label(this, "SoundName", "Sound Name");
	SoundName->SetBounds(635, 215, 125, 20);

	//create the soundscape keyvalues and load it
	m_KeyValues = new KeyValues("Empty Soundscape");

	LoadFile(m_KeyValues);
}

//-----------------------------------------------------------------------------
// Purpose: Called every tick for the soundscape maker
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnTick()
{
	//set the visibility
	static bool bPrevVisible = g_ShowSoundscapePanel;
	if (g_ShowSoundscapePanel != bPrevVisible)
		SetVisible(g_ShowSoundscapePanel);

	//set the old visibility
	bPrevVisible = g_ShowSoundscapePanel;
}

//-----------------------------------------------------------------------------
// Purpose: Called when the close button is pressed
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnClose()
{
	//hide the other panels
	g_SoundPanel->OnClose();
	g_SettingsPanel->OnClose();

	g_ShowSoundscapePanel = false;
}

//-----------------------------------------------------------------------------
// Purpose: Play the selected soundscape
//-----------------------------------------------------------------------------
void CSoundscapeMaker::PlaySelectedSoundscape()
{
	g_IsPlayingSoundscape = false;

	//remove all the temporary soundscapes from the soundscape system
	for (int i = 0; i < m_TmpAddedSoundscapes.Count(); i++)
	{
		for (int j = 0; j < g_SoundscapeSystem.m_soundscapes.Count(); j++)
		{
			if (g_SoundscapeSystem.m_soundscapes[j] == m_TmpAddedSoundscapes[i])
			{
				g_SoundscapeSystem.m_soundscapes.Remove(j);
				break;
			}
		}
	}

	m_TmpAddedSoundscapes.RemoveAll();

	
	//change audio params position
	g_SoundscapeSystem.m_params.localBits = 0x7f;
	for (int i = 0; i < MAX_SOUNDSCAPES - 1; i++)
		g_SoundscapeSystem.m_params.localSound.Set(i, g_SoundscapePositions[i]);


	//if m_kvCurrSelected then add all the "playsoundscape" soundscape keyvalues
	//into the g_SoundscapeSystem.m_soundscapes array
	if (m_kvCurrSelected)
	{
		CUtlVector<const char*> SoundscapeNames;
		FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, subkey)
		{
			//look for playsoundscape file
			if (!Q_strcasecmp(subkey->GetName(), "playsoundscape"))
			{
				const char* name = subkey->GetString("name", nullptr);
				if (!name || !name[0] || SoundscapeNames.Find(name) != SoundscapeNames.InvalidIndex())
					continue;

				SoundscapeNames.AddToTail(name);
			}
		}

		//now look for each keyvalue
		for (int i = 0; i < SoundscapeNames.Count(); i++)
		{
			for (KeyValues* subkey = m_KeyValues; subkey != nullptr; subkey = subkey->GetNextTrueSubKey())
			{
				//look for playsoundscape file
				if (!Q_strcmp(subkey->GetName(), SoundscapeNames[i]))
				{
					//add it to the soundscape system
					m_TmpAddedSoundscapes.AddToTail(subkey);
					g_SoundscapeSystem.m_soundscapes.AddToTail(subkey);
				}
			}
		}
	}

	//stop all sounds
	enginesound->StopAllSounds(true);

	//stop the current soundscape and start a new soundscape
	g_SoundscapeSystem.StartNewSoundscape(nullptr);
	g_SoundscapeSystem.StartNewSoundscape(m_kvCurrSelected);

	g_IsPlayingSoundscape = true;
}

//-----------------------------------------------------------------------------
// Purpose: Called when a button or something else gets pressed
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnCommand(const char* pszCommand)
{

	//check for close command first
	if (!Q_strcmp(pszCommand, "Close"))
	{
		BaseClass::OnCommand(pszCommand);
		return;
	}

	//check for the save button command
	else if (!Q_strcmp(pszCommand, SAVE_BUTTON_COMMAND))
	{
		//initalize the file save dialog
		if (!m_FileSave)
		{
			//get the current game directory
			char buf[512];
			filesystem->RelativePathToFullPath("scripts", "MOD", buf, sizeof(buf));

			//create the save dialog
			m_FileSave = new vgui::FileOpenDialog(this, "Save Soundscape File", false);
			m_FileSave->AddFilter("*.txt", "Soundscape Text File", true);
			m_FileSave->AddFilter("*.*", "All Files (*.*)", false);
			m_FileSave->SetStartDirectory(buf);
			m_FileSave->AddActionSignalTarget(this);
		}

		//show the dialog
		m_FileSave->DoModal(false);
		m_FileSave->Activate();

		//file wasnt loadad
		m_bWasFileLoad = false;

		return;
	}

	//check for load button command
	else if (!Q_strcmp(pszCommand, LOAD_BUTTON_COMMAND))
	{
		//initalize the file save dialog
		if (!m_FileLoad)
		{
			//get the current game directory
			char buf[512];
			filesystem->RelativePathToFullPath("scripts", "MOD", buf, sizeof(buf));

			//create the load dialog
			m_FileLoad = new vgui::FileOpenDialog(this, "Load Soundscape File", true);
			m_FileLoad->AddFilter("*.txt", "Soundscape Text File", true);
			m_FileLoad->AddFilter("*.*", "All Files (*.*)", false);
			m_FileLoad->SetStartDirectory(buf);
			m_FileLoad->AddActionSignalTarget(this);
		}

		//show the file load dialog
		m_FileLoad->DoModal(false);
		m_FileLoad->Activate();

		//file was loadad
		m_bWasFileLoad = true;

		return;
	}

	//check for options panel button
	else if (!Q_strcmp(pszCommand, OPTIONS_BUTTON_COMMAND))
	{
		g_SettingsPanel->SetVisible(true);
		g_SettingsPanel->MoveToFront();
		g_SettingsPanel->RequestFocus();
		return;
	}

	//check for new soundscape
	else if (!Q_strcmp(pszCommand, NEW_BUTTON_COMMAND))
	{
		//make sure you want to create a new soundscape file
		vgui::QueryBox* popup = new vgui::QueryBox("New File?", "Are you sure you want to create a new soundscape file?", this);
		popup->SetOKCommand(new KeyValues("Command", "command", RESET_BUTTON_COMMAND));
		popup->SetCancelButtonVisible(false);
		popup->AddActionSignalTarget(this);
		popup->DoModal(this);

		return;
	}

	//check for reset soundscape
	else if (!Q_strcmp(pszCommand, RESET_BUTTON_COMMAND))
	{
		m_kvCurrSelected = nullptr;

		//stop all soundscapes before deleting the old soundscapes
		if (g_IsPlayingSoundscape)
			PlaySelectedSoundscape();

		m_KeyValues->deleteThis();
		m_KeyValues = new KeyValues("Empty Soundscape");

		LoadFile(m_KeyValues);
		return;
	}

	//check for play sound
	else if (!Q_strcmp(pszCommand, SOUNDS_LIST_BUTTON_COMMAND))
	{
		//initalize the sounds
		if (!g_SoundPanelInitalized)
		{
			g_SoundPanelInitalized = true;
			g_SoundPanel->InitalizeSounds();
		}

		//set the sound list panel's combo box text and selected item
		
		//get sound text entry name
		char buf[512];
		m_SoundNameTextEntry->GetText(buf, sizeof(buf));

		//look for item with same name
		for (int i = 0; i < g_SoundDirectories.Count(); i++)
		{
			if (!Q_strcmp(buf, g_SoundDirectories[i]))
			{
				//select item
				g_SoundPanel->m_SoundsList->ActivateItem(i);
				g_SoundPanel->m_SoundsList->SetText(buf);

				break;
			}
		}

		g_SoundPanel->SetVisible(true);
		g_SoundPanel->MoveToFront();
		g_SoundPanel->RequestFocus();
		return;
	}

	//check for play soundscape
	else if (!Q_strcmp(pszCommand, PLAY_SOUNDSCAPE_COMMAND))
	{
		if (m_PlaySoundscapeButton->IsSelected())
		{
			//enable the reset soundscape button
			m_ResetSoundscapeButton->SetEnabled(true);

			//play the soundscape
			PlaySelectedSoundscape();
		}
		else
		{
			//disable the reset soundscape button
			m_ResetSoundscapeButton->SetEnabled(false);

			g_IsPlayingSoundscape = false;

			//stop all sounds and soundscapes
			enginesound->StopAllSounds(true);
			g_SoundscapeSystem.StartNewSoundscape(nullptr);
		}

		return;
	}

	//check for play soundscape
	else if (!Q_strcmp(pszCommand, RESET_SOUNDSCAPE_BUTTON_COMMAND))
	{
		PlaySelectedSoundscape();
		return;
	}
	

	//check for delete item
	else if (!Q_strcmp(pszCommand, DELETE_CURRENT_ITEM_COMMAND))
	{
		//check for current rndwave
		if (m_kvCurrRndwave && m_SoundNameTextEntry->IsEnabled())
		{
			if (!m_kvCurrRndwave || m_iCurrRndWave <= 0)
				return;

			//get the keyvalues by the index
			int curr = 0;
			KeyValues* prev = nullptr;

			FOR_EACH_VALUE(m_kvCurrRndwave, keyvalues)
			{
				if (++curr == m_iCurrRndWave)
				{
					//delete
					if (prev)
						prev->SetNextKey(keyvalues->GetNextValue());
					else
					{
						m_kvCurrRndwave->m_pSub = keyvalues->GetNextValue();
						m_iCurrRndWave = -1;
					}

					curr = curr - 1;

					keyvalues->SetNextKey(nullptr);
					keyvalues->deleteThis();
					break;
				}



				prev = keyvalues;
			}

			//reset everything
			m_SoundNameTextEntry->SetText("");
			m_SoundNameTextEntry->SetEnabled(false);
			m_SoundNamePlay->SetEnabled(false);

			//store vector
			auto& vec = m_pSoundList->m_MenuButtons;

			//remove it
			delete vec[curr];
			vec.Remove(curr);

			//move everything down
			m_pSoundList->m_iCurrentY = m_pSoundList->m_iCurrentY - 22;
			m_pSoundList->m_Keyvalues = m_kvCurrRndwave;

			if (vec.Count() >= m_pSoundList->m_iMax)
			{
				m_pSoundList->OnMouseWheeled(1);

				int min, max;
				m_pSoundList->m_pSideSlider->GetRange(min, max);
				m_pSoundList->m_pSideSlider->SetRange(0, max - 1);
			}

			for (int i = curr; i < vec.Count(); i++)
			{
				//move everything down
				int x, y = 0;
				vec[i]->GetPos(x, y);
				vec[i]->SetPos(x, y - 22);
			}

			//reset every command
			int WaveAmount = 0;
			for (int i = 0; i < vec.Count(); i++)
			{
				//store data name
				const char* name = vec[i]->GetCommand()->GetString("command");

				//increment variables based on name
				if (Q_stristr(name, "$rndwave") == name)
				{
					WaveAmount++;
					vec[i]->SetCommand(CFmtStr("$rndwave%d", WaveAmount));
				}
			}

			//bounds check
			if (vec.Count() <= 0)
				return;

			//select next item
			if (m_iCurrRndWave <= vec.Count())
				OnCommand(CFmtStr("$rndwave%d", curr + 1));
			else
				OnCommand(CFmtStr("$rndwave%d", curr));
		}
		else if (m_kvCurrSound)
		{
			if (!m_kvCurrSelected)
				return;

			//find keyvalue with same pointer and get the index
			int tmpindex = 0;
			int index = -1;

			KeyValues* prev = nullptr;
			FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, keyvalues)
			{
				if (m_kvCurrSound == keyvalues)
				{
					//remove it
					if (prev)
						prev->SetNextKey(keyvalues->GetNextTrueSubKey());
					else
						m_kvCurrSelected->m_pSub = keyvalues->GetNextTrueSubKey();

					keyvalues->SetNextKey(nullptr);
					keyvalues->deleteThis();

					//get index
					index = tmpindex;
					break;
				}

				prev = keyvalues;

				//increment
				tmpindex++;
			}

			//error
			if (index == -1)
				return;

			//store vector
			auto& vec = m_pDataList->m_MenuButtons;

			//remove it
			delete vec[index];
			vec.Remove(index);

			//move everything down
			m_pDataList->m_iCurrentY = m_pDataList->m_iCurrentY - 22;
			m_pDataList->m_Keyvalues = m_kvCurrSelected;

			for (int i = index; i < vec.Count(); i++)
			{
				//move everything down
				int x, y = 0;
				vec[i]->GetPos(x, y);
				vec[i]->SetPos(x, y - 22);
			}

			if (vec.Count() >= m_pDataList->m_iMax)
			{
				m_pDataList->OnMouseWheeled(1);

				int min, max;
				m_pDataList->m_pSideSlider->GetRange(min, max);
				m_pDataList->m_pSideSlider->SetRange(0, max - 1);
			}

			//reset the names of each button
			int RandomNum = 0;
			int LoopingNum = 0;
			int SoundscapeNum = 0;

			//change the commands of the buttons
			for (int i = 0; i < vec.Count(); i++)
			{
				//store data name
				const char* name = vec[i]->GetCommand()->GetString("command");

				//increment variables based on name
				if (Q_stristr(name, "$playrandom") == name)
				{
					RandomNum++;
					vec[i]->SetCommand(CFmtStr("$playrandom%d", RandomNum));
				}

				if (Q_stristr(name, "$playlooping") == name)
				{
					LoopingNum++;
					vec[i]->SetCommand(CFmtStr("$playlooping%d", LoopingNum));
				}

				if (Q_stristr(name, "$playsoundscape") == name)
				{
					SoundscapeNum++;
					vec[i]->SetCommand(CFmtStr("$playsoundscape%d", SoundscapeNum));
				}
			}

			//reset everything
			m_SoundLevels->SetText("");
			m_SoundNameTextEntry->SetText("");
			m_TimeTextEntry->SetText("");
			m_PitchTextEntry->SetText("");
			m_PositionTextEntry->SetText("");
			m_VolumeTextEntry->SetText("");

			m_SoundLevels->SetEnabled(false);
			m_SoundNameTextEntry->SetEnabled(false);
			m_TimeTextEntry->SetEnabled(false);
			m_PitchTextEntry->SetEnabled(false);
			m_PositionTextEntry->SetEnabled(false);
			m_VolumeTextEntry->SetEnabled(false);
			m_SoundNamePlay->SetEnabled(false);

			m_pSoundList->Clear();

			m_kvCurrSound = nullptr;
			m_pSoundList->m_Keyvalues = nullptr;

			//bounds checking
			if (index >= vec.Count())
				index = index - 1;

			//select the button
			if (index >= 0)
				OnCommand(vec[index]->GetCommand()->GetString("command"));
		}
		else if (m_kvCurrSelected)
		{
			if (m_KeyValues == m_kvCurrSelected)
			{
				//play an error sound
				vgui::surface()->PlaySound("resource/warning.wav");

				//show an error
				vgui::QueryBox* popup = new vgui::QueryBox("Error", "Can not delete base soundscape!", this);
				popup->SetOKButtonText("Ok");
				popup->SetCancelButtonVisible(false);
				popup->AddActionSignalTarget(this);
				popup->DoModal(this);

				return;
			}

			//find keyvalue with same pointer and get the index
			int tmpindex = 0;
			int index = -1;

			KeyValues* prev = nullptr;
			for (KeyValues* keyvalues = m_KeyValues; keyvalues != nullptr; keyvalues = keyvalues->GetNextTrueSubKey())
			{
				if (m_kvCurrSelected == keyvalues)
				{
					//remove it
					if (!prev)
						break;

					prev->SetNextKey(keyvalues->GetNextTrueSubKey());
					keyvalues->SetNextKey(nullptr);
					keyvalues->deleteThis();

					//get index
					index = tmpindex;
					break;
				}

				prev = keyvalues;

				//increment
				tmpindex++;
			}

			//error
			if (index == -1)
				return;

			//store vector
			auto& vec = m_SoundscapesList->m_MenuButtons;

			//remove it
			delete vec[index];
			vec.Remove(index);

			//move everything down
			m_SoundscapesList->m_iCurrentY = m_SoundscapesList->m_iCurrentY - 22;

			for (int i = index; i < vec.Count(); i++)
			{
				//move everything down
				int x, y = 0;
				vec[i]->GetPos(x, y);
				vec[i]->SetPos(x, y - 22);
			}

			if (vec.Count() >= m_SoundscapesList->m_iMax)
			{
				m_SoundscapesList->OnMouseWheeled(1);

				int min, max;
				m_SoundscapesList->m_pSideSlider->GetRange(min, max);
				m_SoundscapesList->m_pSideSlider->SetRange(0, max - 1);
			}

			//reset everything
			m_DspEffects->SetText("");
			m_SoundLevels->SetText("");
			m_TextEntryName->SetText("");
			m_SoundNameTextEntry->SetText("");
			m_TimeTextEntry->SetText("");
			m_PitchTextEntry->SetText("");
			m_PositionTextEntry->SetText("");
			m_VolumeTextEntry->SetText("");
			
			m_DspEffects->SetEnabled(false);
			m_SoundLevels->SetEnabled(false);
			m_TextEntryName->SetEnabled(false);
			m_SoundNameTextEntry->SetEnabled(false);
			m_TimeTextEntry->SetEnabled(false);
			m_PitchTextEntry->SetEnabled(false);
			m_PositionTextEntry->SetEnabled(false);
			m_VolumeTextEntry->SetEnabled(false);
			m_SoundNamePlay->SetEnabled(false);

			m_pDataList->Clear();
			m_pSoundList->Clear();

			m_kvCurrSound = nullptr;
			m_pDataList->m_Keyvalues = nullptr;

			//go to next soundscape
			if (!prev)
				return;

			if (prev->GetNextTrueSubKey())
				OnCommand(prev->GetNextTrueSubKey()->GetName());
			else
				OnCommand(prev->GetName());
		}

		return;
	}

	//check for "playrandom", "playsoundscape" or "playlooping"
	if (Q_stristr(pszCommand, "$playrandom") == pszCommand)
	{
		//get the selected number
		char* str_number = (char*)(pszCommand + 11);
		int number = atoi(str_number);
		if (number != 0)
		{
			//look for button with same command
			auto& vec = m_pDataList->m_MenuButtons;
			for (int i = 0; i < vec.Count(); i++)
			{
				//if the button doesnt have the same command then de-select it. else select it
				if (!Q_strcmp(vec[i]->GetCommand()->GetString("command"), pszCommand))
					vec[i]->m_bIsSelected = true;
				else
					vec[i]->m_bIsSelected = false;
			}


			//clear the m_pSoundList
			m_pSoundList->Clear();
			m_pSoundList->m_Keyvalues = nullptr;

			//store variables
			KeyValues* data = nullptr;
			int curr = 0;

			//get subkey
			FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, sounds)
			{
				if (Q_strcasecmp(sounds->GetName(), "playrandom"))
					continue;
				
				if (++curr == number)
				{
					data = sounds;
					break;
				}
			}

			//no data
			if (!data)
				return;

			m_kvCurrSound = data;
			m_kvCurrRndwave = nullptr;

			//set the random times
			m_TimeTextEntry->SetText(data->GetString("time", "10,20"));
			m_VolumeTextEntry->SetText(data->GetString("volume", "0.5,0.8"));
			m_PitchTextEntry->SetText(data->GetString("pitch", "100"));
			m_PositionTextEntry->SetText(data->GetString("position", ""));
			m_SoundNameTextEntry->SetText("");

			//get snd level index
			int index = 8;	//8 = SNDLVL_NORM
			const char* name = data->GetString("soundlevel", nullptr);

			//check for the name
			if (name)
			{

				//loop through the sound levels to find the right one
				for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
				{
					if (!Q_strcmp(name, g_SoundLevels[i]))
					{
						index = i;
						break;
					}
				}
			}

			//select the index
			m_SoundLevels->ActivateItem(index);

			//enable the text entries
			m_TimeTextEntry->SetEnabled(true);
			m_VolumeTextEntry->SetEnabled(true);
			m_PitchTextEntry->SetEnabled(true);
			m_PositionTextEntry->SetEnabled(true);
			m_SoundLevels->SetEnabled(true);
			m_SoundNameTextEntry->SetEnabled(false);
			m_SoundNamePlay->SetEnabled(false);

			g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
			g_SoundPanel->SetVisible(false);

			//check for randomwave subkey
			if ((data = data->FindKey("rndwave")) == nullptr)
				return;

			m_kvCurrRndwave = data;
			m_pSoundList->m_Keyvalues = data;

			//add all the data
			int i = 0;
			FOR_EACH_VALUE(data, sound)
			{
				const char* name = sound->GetName();

				m_pSoundList->AddButton(name, sound->GetString(), CFmtStr("$rndwave%d", ++i), this);
			}

			m_iSoundscapeMode = SoundscapeMode::Mode_Random;
			return;
		}
	}
	else if (Q_stristr(pszCommand, "$playlooping") == pszCommand)
	{
		//get the selected number
		char* str_number = (char*)(pszCommand + 12);
		int number = atoi(str_number);
		if (number != 0)
		{
			//look for button with same command
			auto& vec = m_pDataList->m_MenuButtons;
			for (int i = 0; i < vec.Count(); i++)
			{
				//if the button doesnt have the same command then de-select it. else select it
				if (!Q_strcmp(vec[i]->GetCommand()->GetString("command"), pszCommand))
					vec[i]->m_bIsSelected = true;
				else
					vec[i]->m_bIsSelected = false;
			}


			//clear the m_pSoundList
			m_pSoundList->Clear();
			m_pSoundList->m_Keyvalues = nullptr;

			//store variables
			KeyValues* data = nullptr;
			int curr = 0;

			//get subkey
			FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, sounds)
			{
				if (Q_strcasecmp(sounds->GetName(), "playlooping"))
					continue;

				if (++curr == number)
				{
					data = sounds;
					break;
				}
			}

			//no data
			if (!data)
				return;

			m_kvCurrSound = data;
			m_kvCurrRndwave = nullptr;

			//set the random times
			m_TimeTextEntry->SetText("");
			m_VolumeTextEntry->SetText(data->GetString("volume", "1"));
			m_PitchTextEntry->SetText(data->GetString("pitch", "100"));
			m_PositionTextEntry->SetText(data->GetString("position", ""));
			m_SoundNameTextEntry->SetText(data->GetString("wave", ""));

			//get snd level index
			int index = 8;	//8 = SNDLVL_NORM
			const char* name = data->GetString("soundlevel", nullptr);

			//check for the name
			if (name)
			{

				//loop through the sound levels to find the right one
				for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
				{
					if (!Q_strcmp(name, g_SoundLevels[i]))
					{
						index = i;
						break;
					}
				}
			}

			//select the index
			m_SoundLevels->ActivateItem(index);

			//enable the text entries
			m_TimeTextEntry->SetEnabled(false);
			m_VolumeTextEntry->SetEnabled(true);
			m_PitchTextEntry->SetEnabled(true);
			m_PositionTextEntry->SetEnabled(true);
			m_SoundLevels->SetEnabled(true);
			m_SoundNameTextEntry->SetEnabled(true);
			m_SoundNamePlay->SetEnabled(true);
			g_SoundPanel->SetVisible(false);

			m_iSoundscapeMode = SoundscapeMode::Mode_Looping;
			return;
		}
	}
	else if (Q_stristr(pszCommand, "$playsoundscape") == pszCommand)
	{
		//get the selected number
		char* str_number = (char*)(pszCommand + 15);
		int number = atoi(str_number);
		if (number != 0)
		{
			//look for button with same command
			auto& vec = m_pDataList->m_MenuButtons;
			for (int i = 0; i < vec.Count(); i++)
			{
				//if the button doesnt have the same command then de-select it. else select it
				if (!Q_strcmp(vec[i]->GetCommand()->GetString("command"), pszCommand))
					vec[i]->m_bIsSelected = true;
				else
					vec[i]->m_bIsSelected = false;
			}


			//clear the m_pSoundList
			m_pSoundList->Clear();
			m_pSoundList->m_Keyvalues = nullptr;

			//store variables
			KeyValues* data = nullptr;
			int curr = 0;

			//get subkey
			FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, sounds)
			{
				if (Q_strcasecmp(sounds->GetName(), "playsoundscape"))
					continue;

				if (++curr == number)
				{
					data = sounds;
					break;
				}
			}

			//no data
			if (!data)
				return;

			m_kvCurrSound = data;
			m_kvCurrRndwave = nullptr;

			//set the random times
			m_TimeTextEntry->SetText("");
			m_VolumeTextEntry->SetText(data->GetString("volume", "1"));
			m_PositionTextEntry->SetText(data->GetString("positionoverride", ""));
			m_SoundNameTextEntry->SetText(data->GetString("name", ""));
			m_PitchTextEntry->SetText("");

			//get snd level index
			int index = 8;	//8 = SNDLVL_NORM
			const char* name = data->GetString("soundlevel", nullptr);

			//check for the name
			if (name)
			{

				//loop through the sound levels to find the right one
				for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
				{
					if (!Q_strcmp(name, g_SoundLevels[i]))
					{
						index = i;
						break;
					}
				}
			}

			//select the index
			m_SoundLevels->ActivateItem(index);

			//enable the text entries
			m_TimeTextEntry->SetEnabled(true);
			m_VolumeTextEntry->SetEnabled(true);
			m_PitchTextEntry->SetEnabled(false);
			m_PositionTextEntry->SetEnabled(true);
			m_SoundLevels->SetEnabled(true);
			m_SoundNameTextEntry->SetEnabled(true);
			m_TimeTextEntry->SetEnabled(false);
			m_SoundNamePlay->SetEnabled(false);

			g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
			g_SoundPanel->SetVisible(false);

			m_iSoundscapeMode = SoundscapeMode::Mode_Soundscape;
			return;
		}
	}
	else if (Q_stristr(pszCommand, "$rndwave") == pszCommand)
	{
		if (!m_kvCurrRndwave)
			return;

		//get the selected number
		char* str_number = (char*)(pszCommand + 8);
		m_iCurrRndWave = atoi(str_number);
		if (m_iCurrRndWave != 0)
		{
			//look for button with same command
			auto& vec = m_pSoundList->m_MenuButtons;
			for (int i = 0; i < vec.Count(); i++)
			{
				//if the button doesnt have the same command then de-select it. else select it
				if (!Q_strcmp(vec[i]->GetCommand()->GetString("command"), pszCommand))
					vec[i]->m_bIsSelected = true;
				else
					vec[i]->m_bIsSelected = false;
			}


			int i = 0;

			//get value
			KeyValues* curr = nullptr;
			FOR_EACH_VALUE(m_kvCurrRndwave, wave)
			{
				if (++i == m_iCurrRndWave)
				{
					curr = wave;
					break;
				}
			}

			//if no curr then throw an error
			if (!curr)
			{
				//play an error sound
				vgui::surface()->PlaySound("resource/warning.wav");

				//show error
				char buf[1028];
				Q_snprintf(buf, sizeof(buf), "Failed to get rndwave '%d' for subkey \"%s\"\nfor current soundscape file!", i, m_kvCurrSelected->GetName());

				//show an error
				vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
				popup->SetOKButtonText("Ok");
				popup->SetCancelButtonVisible(false);
				popup->AddActionSignalTarget(this);
				popup->DoModal(this);
				return;
			}

			m_SoundNameTextEntry->SetEnabled(true);
			m_SoundNameTextEntry->SetText(curr->GetString());

			m_SoundNamePlay->SetEnabled(true);

			m_iSoundscapeMode = SoundscapeMode::Mode_Random;
			return;
		}
	}

	//look for button with the same name as the command
	{
		//store vars
		CUtlVector<CSoundscapeButton*>& array = m_SoundscapesList->m_MenuButtons;

		//de-select button
		if (m_pCurrentSelected)
			m_pCurrentSelected->m_bIsSelected = false;

		//check for name
		for (int i = 0; i < m_SoundscapesList->m_MenuButtons.Size(); i++)
		{
			//check button name
			if (!Q_strcmp(array[i]->GetCommand()->GetString("command"), pszCommand))
			{
				//found it
				m_pCurrentSelected = array[i];
				break;
			}
		}

		//find selected keyvalue

		//set needed stuff
		if (m_pCurrentSelected)
		{
			//select button
			m_pCurrentSelected->m_bIsSelected = true;

			m_DeleteCurrentButton->SetEnabled(false);

			//reset the selected kv
			m_kvCurrSelected = nullptr;

			//find selected keyvalues

			for (KeyValues* kv = m_KeyValues; kv != nullptr; kv = kv->GetNextTrueSubKey())
			{
				if (!Q_strcmp(kv->GetName(), pszCommand))
				{
					m_kvCurrSelected = kv;
					break;
				}
			}

			//set 
			m_kvCurrSound = nullptr;
			m_kvCurrRndwave = nullptr;

			m_TimeTextEntry->SetEnabled(false);
			m_TimeTextEntry->SetText("");

			m_VolumeTextEntry->SetEnabled(false);
			m_VolumeTextEntry->SetText("");

			m_PitchTextEntry->SetEnabled(false);
			m_PitchTextEntry->SetText("");

			m_PositionTextEntry->SetEnabled(false);
			m_PositionTextEntry->SetText("");
			
			m_SoundLevels->SetEnabled(false);
			m_SoundLevels->SetText("");

			m_SoundNameTextEntry->SetEnabled(false);
			m_SoundNameTextEntry->SetText("");

			m_SoundNamePlay->SetEnabled(false);

			if (g_SoundPanel)
			{
				g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
				g_SoundPanel->SetVisible(false);
			}

			//check for current keyvalues. should never bee nullptr but could be
			if (!m_kvCurrSelected)
			{
				//play an error sound
				vgui::surface()->PlaySound("resource/warning.wav");

				//show error
				char buf[1028];
				Q_snprintf(buf, sizeof(buf), "Failed to find KeyValue subkey \"%s\"\nfor current soundscape file!", pszCommand);

				//show an error
				vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
				popup->SetOKButtonText("Ok");
				popup->SetCancelButtonVisible(false);
				popup->AddActionSignalTarget(this);
				popup->DoModal(this);

				//reset vars
				m_pCurrentSelected = nullptr;

				m_TextEntryName->SetEnabled(false);
				m_TextEntryName->SetText("");

				m_DspEffects->SetEnabled(false);
				m_DspEffects->SetText("");
				return;
			}

			if (g_IsPlayingSoundscape)
				PlaySelectedSoundscape();

			m_DeleteCurrentButton->SetEnabled(true);

			//set current soundscape name
			m_TextEntryName->SetText(pszCommand);
			m_TextEntryName->SetEnabled(true);
			m_pDataList->m_Keyvalues = m_kvCurrSelected;

			//set dsp effect
			int dsp = Clamp<int>(m_kvCurrSelected->GetInt("dsp"), 0, 29);

			m_PlaySoundscapeButton->SetEnabled(true);

			m_DspEffects->SetEnabled(true);
			m_DspEffects->ActivateItem(dsp);

			//clear these
			m_pDataList->Clear();
			m_pSoundList->Clear();
			m_pSoundList->m_Keyvalues = nullptr;

			//set variables
			int RandomNum = 0;
			int LoopingNum = 0;
			int SoundscapeNum = 0;

			FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, data)
			{
				//store data name
				const char* name = data->GetName();

				//increment variables based on name
				if (!Q_strcasecmp(name, "playrandom"))
				{
					RandomNum++;
					m_pDataList->AddButton(data->GetName(), data->GetName(), CFmtStr("$playrandom%d", RandomNum), this);
				}
				
				if (!Q_strcasecmp(name, "playlooping"))
				{
					LoopingNum++;
					m_pDataList->AddButton(data->GetName(), data->GetName(), CFmtStr("$playlooping%d", LoopingNum), this);
				}
				
				if (!Q_strcasecmp(name, "playsoundscape"))
				{
					SoundscapeNum++;
					m_pDataList->AddButton(data->GetName(), data->GetName(), CFmtStr("$playsoundscape%d", SoundscapeNum), this);
				}
			}
		}
	}

	BaseClass::OnCommand(pszCommand);
}

//-----------------------------------------------------------------------------
// Purpose: Function to recursivly write keyvalues to keyvalue files. the keyvalues
//			class does have a function to do this BUT this function writes every single
//			item one after another. this function does that but writes the keys
//			first then the subkeys so the order is good.
//-----------------------------------------------------------------------------
void RecursivlyWriteKeyvalues(KeyValues* prev, CUtlBuffer& buffer, int& indent)
{
	//write \t indent
	for (int i = 0; i < indent; i++)
		buffer.PutChar('\t');

	//write name
	buffer.PutChar('"');
	buffer.PutString(prev->GetName());
	buffer.PutString("\"\n");

	//write {
	for (int i = 0; i < indent; i++)
		buffer.PutChar('\t');

	buffer.PutString("{\n");

	//increment indent
	indent++;

	//write all the keys first
	FOR_EACH_VALUE(prev, value)
	{
		for (int i = 0; i < indent; i++)
			buffer.PutChar('\t');

		//write name and value
		buffer.PutChar('"');
		buffer.PutString(value->GetName());
		buffer.PutString("\"\t");
		
		buffer.PutChar('"');
		buffer.PutString(value->GetString());
		buffer.PutString("\"\n");
	}
	
	//write all the subkeys now
	FOR_EACH_TRUE_SUBKEY(prev, value)
	{
		//increment indent
		RecursivlyWriteKeyvalues(value, buffer, indent);
		
		if (value->GetNextTrueSubKey())
			buffer.PutChar('\n');
	}

	//decrement indent
	indent--;

	//write ending }
	for (int i = 0; i < indent; i++)
		buffer.PutChar('\t');

	buffer.PutString("}\n");
}

//-----------------------------------------------------------------------------
// Purpose: Called when a file gets opened/closed
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnFileSelected(const char* pszFileName)
{
	//check for null or empty string
	if (!pszFileName || pszFileName[0] == '\0')
		return;

	//check for file save
	if (!m_bWasFileLoad)
	{
		//save the file
		if (m_KeyValues)
		{
			//write everything into a buffer
			CUtlBuffer buf(0, 0, CUtlBuffer::TEXT_BUFFER);
			buf.PutString("//------------------------------------------------------------------------------------\n");
			buf.PutString("//\n");
			buf.PutString("// Auto-generated soundscape file created with modbases soundscape tool'\n");
			buf.PutString("//\n");
			buf.PutString("//------------------------------------------------------------------------------------\n");

			//now write the keyvalues
			KeyValues* pCurrent = m_KeyValues;
			while (pCurrent)
			{
				int indent = 0;
				RecursivlyWriteKeyvalues(pCurrent, buf, indent);
				pCurrent = pCurrent->GetNextTrueSubKey();

				//put a newline
				buf.PutChar('\n');
			}

			if (!g_pFullFileSystem->WriteFile(pszFileName, "MOD", buf))
			{
				//play an error sound
				vgui::surface()->PlaySound("resource/warning.wav");

				//get the error first
				char buf[1028];
				Q_snprintf(buf, sizeof(buf), "Failed to save soundscape to file \"%s\"", pszFileName);

				//show an error
				vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
				popup->SetOKButtonText("Ok");
				popup->SetCancelButtonVisible(false);
				popup->AddActionSignalTarget(this);
				popup->DoModal(this);
				return;
			}
		}


		//store vars
		const char* last = pszFileName;
		const char* tmp = nullptr;

		//get the last /
		while ((last = Q_strstr(last, "\\")) != nullptr)
			tmp = ++last; //move past the backslash

		//check tmp
		if (!tmp || !*tmp)
			tmp = pszFileName;

		//set new title
		char buf[1028];
		Q_snprintf(buf, sizeof(buf), "Soundscape Maker (%s)", tmp);

		SetTitle(buf, true);

		//create copy of pszFileName
		char manifest[1028];
		Q_strncpy(manifest, pszFileName, sizeof(manifest));

		//get last /
		char* lastSlash = Q_strrchr(manifest, '\\');
		if (lastSlash == nullptr || *lastSlash == '\0') 
			return;

		//append 'soundscapes_manifest.txt'
		lastSlash[1] = '\0';
		strcat(manifest, "soundscapes_manifest.txt");

		//see if we can open manifest file
		KeyValues* man_file = new KeyValues("manifest");
		if (!man_file->LoadFromFile(g_pFullFileSystem, manifest))
		{
			//cant open manifest file
			man_file->deleteThis();
			return;
		}

		//get real filename
		pszFileName = Q_strrchr(pszFileName, '\\');
		if (!pszFileName || !*pszFileName)
		{
			man_file->deleteThis();
			return;
		}

		pszFileName = pszFileName + 1;

		//create name to be added to the manifest file
		char add_file[1028];
		Q_snprintf(add_file, sizeof(add_file), "scripts/%s", pszFileName);

		//add filename to manifest file if not found
		FOR_EACH_VALUE(man_file, value)
		{
			if (!Q_strcmp(value->GetString(), add_file))
			{
				man_file->deleteThis();
				return;
			}
		}


		//add to manifest file
		KeyValues* kv = new KeyValues("file");
		kv->SetString(nullptr, add_file);
		man_file->AddSubKey(kv);

		//write to file
		man_file->SaveToFile(g_pFullFileSystem, manifest);

		man_file->deleteThis();
		return;
	}

	//try and load the keyvalues file first
	KeyValues* temp = new KeyValues("SoundscapeFile");
	if (!temp->LoadFromFile(filesystem, pszFileName))
	{
		//play an error sound
		vgui::surface()->PlaySound("resource/warning.wav");
		
		//get the error first
		char buf[1028];
		Q_snprintf(buf, sizeof(buf), "Failed to open keyvalues file \"%s\"", pszFileName);

		//show an error
		vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
		popup->SetOKButtonText("Ok");
		popup->SetCancelButtonVisible(false);
		popup->AddActionSignalTarget(this);
		popup->DoModal(this);

		temp->deleteThis();
		return;
	}

	//set the new title
	{
		//store vars
		const char* last = pszFileName;
		const char* tmp = nullptr;

		//get the last /
		while ((last = Q_strstr(last, "\\")) != nullptr)
			tmp = ++last; //move past the backslash

		//check tmp
		if (!tmp || !*tmp)
			tmp = pszFileName;

		//create the new new title
		char buf[1028];
		Q_snprintf(buf, sizeof(buf), "Soundscape Maker (%s)", tmp);

		SetTitle(buf, true);
	}

	//stop all soundscapes before deleting the old soundscapes
	m_kvCurrSelected = nullptr;

	if (g_IsPlayingSoundscape)
		PlaySelectedSoundscape();

	//delete and set the old keyvalues
	if (m_KeyValues)
		m_KeyValues->deleteThis();

	m_KeyValues = temp;

	//load the file
	LoadFile(m_KeyValues);
}

//-----------------------------------------------------------------------------
// Purpose: Called when a text thing changes
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnTextChanged(KeyValues* keyvalues)
{
	//check for these things
	if (!m_pCurrentSelected || !m_kvCurrSelected)
		return;

	//check to see if the current focus is the text text entry
	if (m_TextEntryName->HasFocus())
	{
		//get text
		char buf[50];
		m_TextEntryName->GetText(buf, sizeof(buf));

		//set current text and keyvalue name
		m_kvCurrSelected->SetName(buf);
		m_pCurrentSelected->SetText(buf);
		m_pCurrentSelected->SetCommand(buf);
		return;
	}

	//set dsp
	m_kvCurrSelected->SetInt("dsp", Clamp<int>(m_DspEffects->GetActiveItem(), 0, 28));
	
	//if the m_kvCurrSound is nullptr then dont do the rest of the stuff
	if (!m_kvCurrSound)
		return;

	//set the curr sound and stuff
	if (m_TimeTextEntry->HasFocus())
	{
		//get text
		char buf[38];
		m_TimeTextEntry->GetText(buf, sizeof(buf));

		m_kvCurrSound->SetString("time", buf);
		return;
	}
	else if (m_VolumeTextEntry->HasFocus())
	{
		//get text
		char buf[38];
		m_VolumeTextEntry->GetText(buf, sizeof(buf));

		m_kvCurrSound->SetString("volume", buf);
		return;
	}
	else if (m_PitchTextEntry->HasFocus())
	{
		//dont add to soundscaep
		if (m_iSoundscapeMode == SoundscapeMode::Mode_Soundscape)
			return;

		//get text
		char buf[38];
		m_PitchTextEntry->GetText(buf, sizeof(buf));

		m_kvCurrSound->SetString("pitch", buf);
		return;
	}
	else if (m_PositionTextEntry->HasFocus())
	{
		//get text
		char buf[38];
		m_PositionTextEntry->GetText(buf, sizeof(buf));

		//if the string is empty then remove the position instead
		if (!buf[0])
		{
			if (m_iSoundscapeMode == SoundscapeMode::Mode_Soundscape)
				m_kvCurrSound->RemoveSubKey(m_kvCurrSound->FindKey("positionoverride"));
			else
				m_kvCurrSound->RemoveSubKey(m_kvCurrSound->FindKey("position"));
		}
		else
		{
			if (m_iSoundscapeMode == SoundscapeMode::Mode_Soundscape)
				m_kvCurrSound->SetString("positionoverride", buf);
			else
				m_kvCurrSound->SetString("position", buf);

		}

		return;
	}

	//get the sound level amount
	int sndlevel = Clamp<int>(m_SoundLevels->GetActiveItem(), 0, 20);
	m_kvCurrSound->SetString("soundlevel", g_SoundLevels[sndlevel]);

	//set soundscape name/wave
	if (m_SoundNameTextEntry->HasFocus())
	{
		//get text
		char buf[512];
		m_SoundNameTextEntry->GetText(buf, sizeof(buf));
		
		if (m_iSoundscapeMode == SoundscapeMode::Mode_Looping)
			m_kvCurrSound->SetString("wave", buf);
		else if (m_iSoundscapeMode == SoundscapeMode::Mode_Soundscape)
			m_kvCurrSound->SetString("name", buf);
		else if (m_iSoundscapeMode == SoundscapeMode::Mode_Random && m_kvCurrRndwave)
		{
			//get value
			int i = 0;

			FOR_EACH_VALUE(m_kvCurrRndwave, wave)
			{
				if (++i == m_iCurrRndWave)
				{
					wave->SetStringValue(buf);

					//set text on the sounds panel
					vgui::Button* button = m_pSoundList->m_MenuButtons[i - 1];
					if (button)
					{
						//get last / or \ and make the string be that + 1
						char* fslash = Q_strrchr(buf, '/');
						char* bslash = Q_strrchr(buf, '\\');

						//no forward slash and no back slash
						if (!fslash && !bslash)
						{
							button->SetText(buf);
							return;
						}

						if (fslash > bslash)
						{
							button->SetText(fslash + 1);
							return;
						}
						
						else if (bslash > fslash)
						{
							button->SetText(bslash + 1);
							return;
						}
					}

					break;
				}
			}
		}

		return;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Loads the keyvalues
//-----------------------------------------------------------------------------
void CSoundscapeMaker::LoadFile(KeyValues* file)
{
	//clear all the text's
	m_TextEntryName->SetEnabled(false);
	m_TextEntryName->SetText("");

	m_DspEffects->SetEnabled(false);
	m_DspEffects->SetText("");

	m_TimeTextEntry->SetEnabled(false);
	m_TimeTextEntry->SetText("");
	
	m_VolumeTextEntry->SetEnabled(false);
	m_VolumeTextEntry->SetText("");
	
	m_PitchTextEntry->SetEnabled(false);
	m_PitchTextEntry->SetText("");
	
	m_PositionTextEntry->SetEnabled(false);
	m_PositionTextEntry->SetText("");
	
	m_SoundNameTextEntry->SetEnabled(false);
	m_SoundNameTextEntry->SetText("");

	m_SoundNamePlay->SetEnabled(false);
	
	if (g_SoundPanel)
	{
		g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
		g_SoundPanel->SetVisible(false);
	}

	m_PlaySoundscapeButton->SetEnabled(false);
	m_PlaySoundscapeButton->SetSelected(false);

	m_ResetSoundscapeButton->SetEnabled(false);
	m_DeleteCurrentButton->SetEnabled(false);

	//clear current file
	m_pCurrentSelected = nullptr;
	m_kvCurrSelected = nullptr;
	m_kvCurrSound = nullptr;
	m_kvCurrRndwave = nullptr;

	//clear the menu items
	m_SoundscapesList->Clear();
	m_pSoundList->Clear();
	m_pDataList->Clear();
	
	m_SoundscapesList->m_Keyvalues = file;
	m_pDataList->m_Keyvalues = nullptr;
	m_pSoundList->m_Keyvalues = nullptr;

	g_IsPlayingSoundscape = false;

	//temp soundscapes list
	CUtlVector<const char*> Added;

	//add all the menu items
	for (KeyValues* soundscape = file; soundscape != nullptr; soundscape = soundscape->GetNextTrueSubKey())
	{
		//add the menu buttons
		const char* name = soundscape->GetName();

		//check for the soundscape first
		if (Added.Find(name) != Added.InvalidIndex())
		{
			ConWarning("CSoundscapePanel: Failed to add repeated soundscape '%s'\n", name);
			continue;
		}

		Added.AddToTail(name);
		m_SoundscapesList->AddButton(name, name, name, this);
	}

	//
	OnCommand(file->GetName());
}

//-----------------------------------------------------------------------------
// Purpose: Sets the sounds text
//-----------------------------------------------------------------------------
void CSoundscapeMaker::SetSoundText(const char* text)
{
	m_SoundNameTextEntry->SetText(text);

	//set soundscape name/wave
	if (m_iSoundscapeMode != SoundscapeMode::Mode_Random)
	{
		m_kvCurrSound->SetString("wave", text);
	}
	else
	{
		//get value
		int i = 0;

		FOR_EACH_VALUE(m_kvCurrRndwave, wave)
		{
			if (++i == m_iCurrRndWave)
			{
				wave->SetStringValue(text);

				//set text on the sounds panel
				vgui::Button* button = m_pSoundList->m_MenuButtons[i - 1];
				if (button)
				{
					//get last / or \ and make the string be that + 1
					char* fslash = Q_strrchr(text, '/');
					char* bslash = Q_strrchr(text, '\\');

					//no forward slash and no back slash
					if (!fslash && !bslash)
					{
						button->SetText(text);
						return;
					}

					if (fslash > bslash)
					{
						button->SetText(fslash + 1);
						return;
					}

					else if (bslash > fslash)
					{
						button->SetText(bslash + 1);
						return;
					}
				}

				break;
			}
		}
	}

	return;
}

//-----------------------------------------------------------------------------
// Purpose: Called when a keyboard key is pressed
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnKeyCodePressed(vgui::KeyCode code)
{
	//check for ctrl o or ctrl s
	if (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LCONTROL))
	{
		if (code == vgui::KeyCode::KEY_O)
			OnCommand(LOAD_BUTTON_COMMAND);
		else if (code == vgui::KeyCode::KEY_S)
			OnCommand(SAVE_BUTTON_COMMAND);
		else if (code == vgui::KeyCode::KEY_N)
			OnCommand(NEW_BUTTON_COMMAND);

		return;
	}

	if (code == vgui::KeyCode::KEY_O)
	{
		//show settings
		g_SettingsPanel->SetVisible(true);
		g_SettingsPanel->RequestFocus();
		g_SettingsPanel->MoveToFront();
		return;
	}

	//get key bound to this
	const char* key = engine->Key_LookupBinding("modbase_soundscape_panel");
	if (!key)
		return;

	//convert the key to a keyboard code
	const char* keystring = KeyCodeToString(code);
	
	//remove the KEY_ if found
	if (Q_strstr(keystring, "KEY_") == keystring)
		keystring = keystring + 4;

	//check both strings
	if (!Q_strcasecmp(key, keystring))
		OnClose();
}

//-----------------------------------------------------------------------------
// Purpose: Starts the soundscape on map spawn
//-----------------------------------------------------------------------------
void CSoundscapeMaker::LevelInitPostEntity()
{
	if (g_IsPlayingSoundscape)
		PlaySelectedSoundscape();
}

//-----------------------------------------------------------------------------
// Purpose: Destructor for soundscape maker panel
//-----------------------------------------------------------------------------
CSoundscapeMaker::~CSoundscapeMaker()
{
	//delete the keyvalue files if needed
	if (m_KeyValues)
		m_KeyValues->deleteThis();
}

//static panel instance
static CSoundscapeMaker* g_SSMakerPanel = nullptr;

//interface class
class CSoundscapeMakerInterface : public ISoundscapeMaker
{
public:
	void Create(vgui::VPANEL parent)
	{
		g_SSMakerPanel = new CSoundscapeMaker(parent);
		g_SoundPanel = new CSoundListPanel(parent, "SoundListPanel");
		g_SettingsPanel = new CSoundscapeSettingsPanel(parent, "SettingsPanel");
	}

	void SetVisible(bool bVisible)
	{
		if (g_SSMakerPanel)
			g_SSMakerPanel->SetVisible(bVisible);
	}

	void Destroy()
	{
		if (g_SSMakerPanel)
			g_SSMakerPanel->DeletePanel();

		if (g_SoundPanel)
			g_SoundPanel->DeletePanel();

		if (g_SettingsPanel)
			g_SettingsPanel->DeletePanel();

		g_SSMakerPanel = nullptr;
		g_SoundPanel = nullptr;
		g_SettingsPanel = nullptr;
	}

	void SetSoundText(const char* text)
	{
		if (!g_SSMakerPanel)
			return;

		g_SSMakerPanel->SetSoundText(text);
		g_SSMakerPanel->RequestFocus();
		g_SSMakerPanel->MoveToFront();
	}

	void SetAllVisible(bool bVisible)
	{
		g_ShowSoundscapePanel = false;

		if (g_SSMakerPanel)
			g_SSMakerPanel->SetVisible(false);

		if (g_SoundPanel)
			g_SoundPanel->SetVisible(false);

		if (g_SettingsPanel)
			g_SettingsPanel->SetVisible(false);
	}
};

CSoundscapeMakerInterface SoundscapeMaker;
ISoundscapeMaker* g_SoundscapeMaker = &SoundscapeMaker;

//-----------------------------------------------------------------------------
// Purpose: User message hook function for setting/getting soundscape position
//-----------------------------------------------------------------------------
void _SoundscapeMaker_Recieve(bf_read& bf)
{
	//show the soundscape panel
	g_ShowSoundscapePanel = true;
	g_SSMakerPanel->SetVisible(true);

	//show settings panel
	g_SettingsPanel->SetVisible(true);

	//get the stuff
	byte index = bf.ReadByte();
	Vector pos;
	bf.ReadBitVec3Coord(pos);

	//if index == -1 (255) then that means the message was canceled
	if (index == 255)
		return;

	//clamp index and get pos
	index = Clamp<int>(index, 0, MAX_SOUNDSCAPES - 1);

	//send message to settings
	g_SettingsPanel->SetItem(index, pos);
}

//-----------------------------------------------------------------------------
// Purpose: Command to toggle the soundscape panel
//-----------------------------------------------------------------------------
CON_COMMAND(modbase_soundscape_panel, "Toggles the modebase soundscape panel")
{
	g_ShowSoundscapePanel = !g_ShowSoundscapePanel;
	SoundscapeMaker.SetVisible(g_ShowSoundscapePanel);

	//tell player to stop soundscape mode
	static ConCommand* cc = cvar->FindCommand("__ss_maker_stop");
	if (cc)
		cc->Dispatch({});
}