Programming/vgui soundscape maker.cpp: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
m (set g_ShowSoundscapePanel to false by default)
(Added new "text editor" panel that can be used to edit the soundscape file in text format)
Line 24: Line 24:
#include <vgui_controls/Menu.h>
#include <vgui_controls/Menu.h>
#include <vgui_controls/MenuItem.h>
#include <vgui_controls/MenuItem.h>
#include <vgui_controls/RichText.h>
#include <engine/IEngineSound.h>
#include <engine/IEngineSound.h>
#include <vgui/IVGui.h>
#include <vgui/IVGui.h>
Line 97: Line 98:
"SNDLVL_150dB"
"SNDLVL_150dB"
};
};
//-----------------------------------------------------------------------------
// Purpose: Helper funciton to compare vector and string
//-----------------------------------------------------------------------------
int Q_vecstr(const CUtlVector<wchar_t>& vec, int startindex, int endindex, const char* substr)
{
//check for null substring
if (!substr || !*substr)
return -1;
//store variables
int substrLen = Q_strlen(substr);
//search for match
for (int i = startindex; i <= endindex; ++i)
{
bool match = true;
for (int j = 0; j < substrLen; ++j)
{
wchar_t wc = vec[i + j];
char ch = substr[j];
if (wc != ch)
{
match = false;
break;
}
}
//found match
if (match)
return i;
}
//didnt find match
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: Helper funciton to compare vector and string but reversed
//-----------------------------------------------------------------------------
int Q_vecrstr(const CUtlVector<wchar_t>& vec, int startindex, int endindex, const char* substr)
{
//check for null substring
if (!substr || !*substr)
return -1;
//store variables
int substrLen = Q_strlen(substr);
//search for match
for (int i = endindex - substrLen + 1; i >= startindex; --i)
{
bool match = true;
for (int j = 0; j < substrLen; ++j)
{
wchar_t wc = vec[i + j];
char ch = substr[j];
if (wc != ch)
{
match = false;
break;
}
}
//found match
if (match)
return i;
}
//didnt find match
return -1;
}


//holds all the sound names
//holds all the sound names
Line 176: Line 249:




//vector positions
//text entry for text edit panel
Vector g_SoundscapePositions[] = {
 
vec3_origin,
 
vec3_origin,
class CTextPanelTextEntry : public vgui::TextEntry
vec3_origin,
{
vec3_origin,
public:
vec3_origin,
DECLARE_CLASS_SIMPLE(CTextPanelTextEntry, vgui::TextEntry)
vec3_origin,
 
vec3_origin,
//constructor
vec3_origin
CTextPanelTextEntry(vgui::Panel* parent, const char* panelName)
};
: TextEntry(parent, panelName)
{
SetMultiline(true);
}


#define SETTINGS_PANEL_WIDTH 350
//called on keycode typed
#define SETTINGS_PANEL_HEIGHT 250
virtual void OnKeyCodeTyped(vgui::KeyCode code)
{
//check for enter or enter
if (code == KEY_ENTER || code == KEY_PAD_ENTER)
InsertString("\n");


#define SETTINGS_PANEL_COMMAND_POS1 "GetPos0"
//check for tab
#define SETTINGS_PANEL_COMMAND_POS2 "GetPos1"
else if (code == KEY_TAB)
#define SETTINGS_PANEL_COMMAND_POS3 "GetPos2"
InsertString("   ");
#define SETTINGS_PANEL_COMMAND_POS4 "GetPos3"
#define SETTINGS_PANEL_COMMAND_POS5 "GetPos4"
//do other key code
#define SETTINGS_PANEL_COMMAND_POS6 "GetPos5"
else
#define SETTINGS_PANEL_COMMAND_POS7 "GetPos6"
BaseClass::OnKeyCodeTyped(code);
#define SETTINGS_PANEL_COMMAND_POS8 "GetPos7"
}
#define SETTINGS_PANEL_COMMAND_SHOW "ShowPositions"


#define MAX_SOUNDSCAPES 8
//called on keycode pressed
void OnKeyCodePressed(vgui::KeyCode code)
{
if (code == KEY_ENTER || code == KEY_PAD_ENTER
|| code == KEY_TAB)
return;


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


CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name);
//called on keycode insert
void OnKeyTyped(wchar_t c)
{
//if (c == '{')
//{
// //insert:
// //{
// //
// //}
// //and set cursor in the middle
// BaseClass::OnKeyTyped(c);
// InsertString("\n\n}    ");
// GotoLeft();
// GotoUp();
// SelectNoText();
//}
if (c == '"')
{
//check next item
if (_cursorPos < m_TextStream.Count())
{


//other
//check for " so you dont insert string inside string
void OnCommand(const char* pszCommand);
if (m_TextStream[_cursorPos] == '"')
{
GotoRight();
SelectNone();
return;
}


//sets the text
}
void SetItem(int index, const Vector& value);
 
//insert:
//""
//and set cursor in the middle
BaseClass::OnKeyTyped(c);
InsertString("\"");
GotoLeft();
SelectNone();
}
else
{
BaseClass::OnKeyTyped(c);
}
}
};
 
 
//soundscape maker text editor panel
#define TEXT_PANEL_WIDTH 760
#define TEXT_PANEL_HEIGHT 630
 
#define TEXT_PANEL_COMMAND_SET "Set"
#define TEXT_PANEL_COMMAND_SET_OK "SetOk"
#define TEXT_PANEL_COMMAND_FIND "FInd"
 
class CSoundscapeTextPanel : public vgui::Frame
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeTextPanel, vgui::Frame);
 
CSoundscapeTextPanel(vgui::VPANEL parent, const char* name);


//message funcs
//sets the keyvalues
MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);
void Set(KeyValues* keyvalues);
void RecursiveSetText(KeyValues* keyvalues, CUtlBuffer& buffer, int indent);


~CSoundscapeSettingsPanel();
//other
void OnCommand(const char* pszCommand);
void PerformLayout();
void OnClose() { BaseClass::OnClose(); }


private:
private:
//position text entries
CTextPanelTextEntry* m_Text;
vgui::TextEntry* m_TextEntryPos0;
vgui::Button* m_SetButton;
vgui::TextEntry* m_TextEntryPos1;
vgui::TextEntry* m_FindTextEntry;
vgui::TextEntry* m_TextEntryPos2;
vgui::Button* m_FindButton;
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
// Purpose: Constructor
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CSoundscapeSettingsPanel::CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name)
CSoundscapeTextPanel::CSoundscapeTextPanel(vgui::VPANEL parent, const char* name)
: BaseClass(nullptr, name)
: BaseClass(nullptr, name)
{
{
Line 254: Line 385:
SetMaximizeButtonVisible(false);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(true);
SetCloseButtonVisible(true);
SetSizeable(false);
SetSizeable(true);
SetMoveable(true);
SetMoveable(true);
SetVisible(false);
SetVisible(false);
SetMinimumSize(575, 120);


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


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


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


//load settings
//make text entry
KeyValues* settings = new KeyValues("settings");
m_Text = new CTextPanelTextEntry(this, "EditBox");
if (!settings->LoadFromFile(filesystem, "cfg/soundscape_maker.txt", "MOD"))
m_Text->SetBounds(5, 25, TEXT_PANEL_WIDTH - 10, TEXT_PANEL_HEIGHT - 55);
ConWarning("Failed to load settings for 'cfg/soundscape_maker.txt'. Using default settings.");
m_Text->SetEnabled(true);
m_Text->SetMultiline(true);
m_Text->SetVerticalScrollbar(true);
 
//make set button
m_SetButton = new vgui::Button(this, "SetButton", "Apply Changes To Keyvalue Maker");
m_SetButton->SetBounds(5, TEXT_PANEL_HEIGHT - 27, 250, 25);
m_SetButton->SetCommand(TEXT_PANEL_COMMAND_SET);
 
//make find text entry
m_FindTextEntry = new vgui::TextEntry(this, "FindTextEntry");
m_FindTextEntry->SetBounds(450, TEXT_PANEL_HEIGHT - 27, 200, 25);


//get positions
//make find button
const char* pos0 = settings->GetString("Position0", "0 0 0");
m_FindButton = new vgui::Button(this, "FindButton", "Find String");
const char* pos1 = settings->GetString("Position1", "0 0 0");
m_FindButton->SetBounds(655, TEXT_PANEL_HEIGHT - 27, 100, 25);
const char* pos2 = settings->GetString("Position2", "0 0 0");
m_FindButton->SetCommand(TEXT_PANEL_COMMAND_FIND);
const char* pos3 = settings->GetString("Position3", "0 0 0");
}
const char* pos4 = settings->GetString("Position4", "0 0 0");
const char* pos5 = settings->GetString("Position5", "0 0 0");
const char* pos6 = settings->GetString("Position6", "0 0 0");
const char* pos7 = settings->GetString("Position7", "0 0 0");


//create position text 1
//-----------------------------------------------------------------------------
m_TextEntryPos0 = new vgui::TextEntry(this, "PosTextEntry0");
// Purpose: Sets the keyvalues
m_TextEntryPos0->SetEnabled(true);
//-----------------------------------------------------------------------------
m_TextEntryPos0->SetText(pos0 ? pos0 : "0 0 0");
void CSoundscapeTextPanel::Set(KeyValues* keyvalues)
m_TextEntryPos0->SetBounds(5, 30, 230, 20);
{
m_TextEntryPos0->SetMaximumCharCount(32);
//write everything into a buffer
CUtlBuffer buf(0, 0, CUtlBuffer::TEXT_BUFFER);


//create position 1 button
//now write the keyvalues
vgui::Button* m_ButtonPos0 = new vgui::Button(this, "PosButton0", "Find Position 0", this, SETTINGS_PANEL_COMMAND_POS1);
KeyValues* pCurrent = keyvalues;
m_ButtonPos0->SetBounds(240, 30, 100, 20);
while (pCurrent)
{
RecursiveSetText(pCurrent, buf, 0);


//create position text 1
//put a newline
m_TextEntryPos1 = new vgui::TextEntry(this, "PosTextEntry1");
if (pCurrent->GetNextTrueSubKey())
m_TextEntryPos1->SetEnabled(true);
buf.PutChar('\n');
m_TextEntryPos1->SetText(pos1 ? pos1 : "0 0 0");
m_TextEntryPos1->SetBounds(5, 55, 230, 20);
//get next
m_TextEntryPos1->SetMaximumCharCount(32);
pCurrent = pCurrent->GetNextTrueSubKey();
}


//create position 2 button
//write that to the m_Text
vgui::Button* m_ButtonPos1 = new vgui::Button(this, "PosButton1", "Find Position 1", this, SETTINGS_PANEL_COMMAND_POS2);
m_Text->SetText((const char*)buf.Base());
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(pos2 ? pos2 : "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);
// Purpose: Recursively writes to a util buffer
m_ButtonPos2->SetBounds(240, 80, 100, 20);
//-----------------------------------------------------------------------------
void CSoundscapeTextPanel::RecursiveSetText(KeyValues* keyvalues, CUtlBuffer& buffer, int indent)
{
//write \t indent
for (int i = 0; i < indent; i++)
buffer.PutString("    ");


// create position text 4
//write name
m_TextEntryPos3 = new vgui::TextEntry(this, "PosTextEntry3");
buffer.PutChar('"');
m_TextEntryPos3->SetEnabled(true);
buffer.PutString(keyvalues->GetName());
m_TextEntryPos3->SetText(pos3 ? pos3 : "0 0 0");
buffer.PutString("\"\n");
m_TextEntryPos3->SetBounds(5, 105, 230, 20);
m_TextEntryPos3->SetMaximumCharCount(32);


// create position 4 button
//write {
vgui::Button* m_ButtonPos3 = new vgui::Button(this, "PosButton3", "Find Position 3", this, SETTINGS_PANEL_COMMAND_POS4);
for (int i = 0; i < indent; i++)
m_ButtonPos3->SetBounds(240, 105, 100, 20);
buffer.PutString("   ");


// create position text 5
buffer.PutString("{\n");
m_TextEntryPos4 = new vgui::TextEntry(this, "PosTextEntry4");
m_TextEntryPos4->SetEnabled(true);
m_TextEntryPos4->SetText(pos4 ? pos4 : "0 0 0");
m_TextEntryPos4->SetBounds(5, 130, 230, 20);
m_TextEntryPos4->SetMaximumCharCount(32);


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


// create position text 6
//write all the keys first
m_TextEntryPos5 = new vgui::TextEntry(this, "PosTextEntry5");
FOR_EACH_VALUE(keyvalues, value)
m_TextEntryPos5->SetEnabled(true);
{
m_TextEntryPos5->SetText(pos5 ? pos5 : "0 0 0");
for (int i = 0; i < indent; i++)
m_TextEntryPos5->SetBounds(5, 155, 230, 20);
buffer.PutString("    ");
m_TextEntryPos5->SetMaximumCharCount(32);


// create position 6 button
//write name and value
vgui::Button* m_ButtonPos5 = new vgui::Button(this, "PosButton5", "Find Position 5", this, SETTINGS_PANEL_COMMAND_POS6);
buffer.PutChar('"');
m_ButtonPos5->SetBounds(240, 155, 100, 20);
buffer.PutString(value->GetName());
buffer.PutString("\"    ");


// create position text 7
buffer.PutChar('"');
m_TextEntryPos6 = new vgui::TextEntry(this, "PosTextEntry6");
buffer.PutString(value->GetString());
m_TextEntryPos6->SetEnabled(true);
buffer.PutString("\"\n");
m_TextEntryPos6->SetText(pos6 ? pos6 : "0 0 0");
}
m_TextEntryPos6->SetBounds(5, 180, 230, 20);
m_TextEntryPos6->SetMaximumCharCount(32);


// create position 7 button
//write all the subkeys now
vgui::Button* m_ButtonPos6 = new vgui::Button(this, "PosButton6", "Find Position 6", this, SETTINGS_PANEL_COMMAND_POS7);
FOR_EACH_TRUE_SUBKEY(keyvalues, value)
m_ButtonPos6->SetBounds(240, 180, 100, 20);
{
//increment indent
// create position text 8
RecursiveSetText(value, buffer, indent);
m_TextEntryPos7 = new vgui::TextEntry(this, "PosTextEntry7");
m_TextEntryPos7->SetEnabled(true);
m_TextEntryPos7->SetText(pos7 ? pos7 : "0 0 0");
m_TextEntryPos7->SetBounds(5, 205, 230, 20);
m_TextEntryPos7->SetMaximumCharCount(32);


// create position 8 button
if (value->GetNextTrueSubKey())
vgui::Button* m_ButtonPos7 = new vgui::Button(this, "PosButton7", "Find Position 7", this, SETTINGS_PANEL_COMMAND_POS8);
buffer.PutChar('\n');
m_ButtonPos7->SetBounds(240, 205, 100, 20);
}
 
//decrement indent
indent--;
 
//write ending }
for (int i = 0; i < indent; i++)
buffer.PutString("   ");
 
buffer.PutString("}\n");  
}


// create show soundscape positions checkbox
//-----------------------------------------------------------------------------
m_ShowSoundscapePositions = new vgui::CheckButton(this, "ShowCheckox", "Show Soundscape Positions");
// Purpose: Called on command
m_ShowSoundscapePositions->SetBounds(75, 225, 200, 20);
//-----------------------------------------------------------------------------
m_ShowSoundscapePositions->SetCommand(SETTINGS_PANEL_COMMAND_SHOW);
void CSoundscapeTextPanel::OnCommand(const char* pszCommand)
m_ShowSoundscapePositions->SetSelected(settings->GetBool("ShowSoundscapes", false));
{
if (!Q_strcmp(pszCommand, TEXT_PANEL_COMMAND_SET))
{
//play sound
vgui::surface()->PlaySound("ui/buttonclickrelease.wav");


//set convar value
//check first incase you accidentally press it
static ConVar* cv = cvar->FindVar("__ss_draw");
vgui::QueryBox* popup = new vgui::QueryBox("Set File?", "Are you sure you want to set the current keyvalues for the keyvalue maker?\nIf there are errors then this could break the keyvalue file.", this);
if (cv)
popup->SetOKCommand(new KeyValues("Command", "command", TEXT_PANEL_COMMAND_SET_OK));
cv->SetValue(m_ShowSoundscapePositions->IsSelected());
popup->SetCancelButtonVisible(false);
popup->AddActionSignalTarget(this);
popup->DoModal(this);
return;
}


//set server positions
//set text
ConCommand* cc = cvar->FindCommand("__ss_maker_set");
if (!Q_strcmp(pszCommand, TEXT_PANEL_COMMAND_SET_OK))
if (cc)
{
{
CCommand args;
//get string
int len = m_Text->GetTextLength() + 1;


//do pos 0
char* buf = new char[len];
if (pos0)
m_Text->GetText(buf, len);
{
args.Tokenize(CFmtStr("ssmaker 0 %s 1", pos0));
cc->Dispatch(args);


UTIL_StringToVector(g_SoundscapePositions[0].Base(), pos0);
g_SoundscapeMaker->SetBuffer(buf);
}


//do pos 1
//delete string
if (pos1)
delete[] buf;
//hide this
SetVisible(false);
return;
}
 
//find text
if (!Q_strcmp(pszCommand, TEXT_PANEL_COMMAND_FIND))
{
//get buffer
char buf[128];
m_FindTextEntry->GetText(buf, sizeof(buf));
 
int index = m_Text->_cursorPos + 1;
int find = -1;
//go in reversed order if holding shift
if (vgui::input()->IsKeyDown(KEY_LSHIFT) || vgui::input()->IsKeyDown(KEY_RSHIFT))
{
{
args.Tokenize(CFmtStr("ssmaker 1 %s 1", pos1));
cc->Dispatch(args);


UTIL_StringToVector(g_SoundscapePositions[1].Base(), pos1);
//see if we find index
find = Q_vecrstr(m_Text->m_TextStream, 0, index - 2, buf);
if (find == -1)
//look again
find = Q_vecrstr(m_Text->m_TextStream, index, m_Text->m_TextStream.Count() - 1, buf);
 
}
}
 
else
//do pos 2
if (pos2)
{
{
args.Tokenize(CFmtStr("ssmaker 2 %s 1", pos2));
cc->Dispatch(args);


UTIL_StringToVector(g_SoundscapePositions[2].Base(), pos2);
//see if we find index
}
find = Q_vecstr(m_Text->m_TextStream, index, m_Text->m_TextStream.Count(), buf);
if (find == -1)


//do pos 3
//look again
if (pos3)
find = Q_vecstr(m_Text->m_TextStream, 0, index, buf);
{
args.Tokenize(CFmtStr("ssmaker 3 %s 1", pos3));
cc->Dispatch(args);


UTIL_StringToVector(g_SoundscapePositions[3].Base(), pos3);
}
}


//do pos 4
//check for invalid index
if (pos4)
if (find == -1)
{
{
args.Tokenize(CFmtStr("ssmaker 4 %s 1", pos4));
//play an error sound
cc->Dispatch(args);
vgui::surface()->PlaySound("resource/warning.wav");


UTIL_StringToVector(g_SoundscapePositions[4].Base(), pos4);
//get text
}
char error[512];
Q_snprintf(error, sizeof(error), "Couldnt find any instances of '%s'", buf);


//do pos 5
//show an error
if (pos5)
vgui::QueryBox* popup = new vgui::QueryBox("No Instances Found", error, this);
{
popup->SetOKButtonText("Ok");
args.Tokenize(CFmtStr("ssmaker 5 %s 1", pos5));
popup->SetCancelButtonVisible(false);
cc->Dispatch(args);
popup->AddActionSignalTarget(this);
popup->DoModal(this);


UTIL_StringToVector(g_SoundscapePositions[5].Base(), pos5);
return;
}
}


//do pos 6
//get number of newlines
if (pos6)
/*int newline = 0;
{
int column = 0;
args.Tokenize(CFmtStr("ssmaker 6 %s 1", pos6));
for (int i = 0; i < find; i++)
cc->Dispatch(args);
{
if (m_Text->m_TextStream[i] == '\n')
{
newline++;
column = 0;
}
else
{
column++;
}
}*/


UTIL_StringToVector(g_SoundscapePositions[6].Base(), pos6);
//select that
}
m_Text->_cursorPos = find;
m_Text->_select[0] = find;
m_Text->_select[1] = find + Q_strlen(buf);
m_Text->LayoutVerticalScrollBarSlider();
m_Text->Repaint();
m_Text->RequestFocus();


//do pos 7
return;
if (pos7)
{
args.Tokenize(CFmtStr("ssmaker 7 %s", pos7));
cc->Dispatch(args);
 
UTIL_StringToVector(g_SoundscapePositions[7].Base(), pos7);
}
}
}
 
//delete settings
BaseClass::OnCommand(pszCommand);
settings->deleteThis();
}
}


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


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


CCommand args;
if (m_Text)
args.Tokenize(CFmtStr("ssmaker %d", atoi(pszCommand)));
m_Text->SetBounds(5, 25, wide - 10, tall - 55);
cc->Dispatch(args);
}


return;
if (m_SetButton)
}
m_SetButton->SetBounds(5, tall - 27, 250, 25);


else if (!Q_strcmp(pszCommand, SETTINGS_PANEL_COMMAND_SHOW))
if (m_FindTextEntry)
{
m_FindTextEntry->SetBounds(wide - 310, tall - 27, 200, 25);
static ConVar* cv = cvar->FindVar("__ss_draw");
if (cv)
cv->SetValue(m_ShowSoundscapePositions->IsSelected());


return;
if (m_FindButton)
}
m_FindButton->SetBounds(wide - 105, tall - 27, 100, 25);
}


BaseClass::OnCommand(pszCommand);
//soundscape settings panel
}
static CSoundscapeTextPanel* g_SoundscapeTextPanel = nullptr;


//-----------------------------------------------------------------------------
// 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
//vector positions
switch (index)
Vector g_SoundscapePositions[] = {
{
vec3_origin,
case 0:
vec3_origin,
m_TextEntryPos0->RequestFocus();
vec3_origin,
m_TextEntryPos0->SetText(text);
vec3_origin,
g_SoundscapePositions[0] = value;
vec3_origin,
break;
vec3_origin,
vec3_origin,
case 1:
vec3_origin
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:
//should the soundscape's show
m_TextEntryPos7->RequestFocus();
bool g_SSMakerShowMessages = false;
m_TextEntryPos7->SetText(text);
g_SoundscapePositions[7] = value;
break;
}
}


//-----------------------------------------------------------------------------
#define SETTINGS_PANEL_WIDTH 350
// Purpose: Called on text changed
#define SETTINGS_PANEL_HEIGHT 275
//-----------------------------------------------------------------------------
 
void CSoundscapeSettingsPanel::OnTextChanged(KeyValues* kv)
#define SETTINGS_PANEL_COMMAND_POS1 "GetPos0"
{
#define SETTINGS_PANEL_COMMAND_POS2 "GetPos1"
static ConCommand* cc = cvar->FindCommand("__ss_maker_set");
#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 SETTINGS_PANEL_COMMAND_DEBUG "Debug"


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


//convert to vector
//soundscape maker settings panel
UTIL_StringToVector(g_SoundscapePositions[0].Base(), buf);
class CSoundscapeSettingsPanel : public vgui::Frame
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeSettingsPanel, vgui::Frame);


//do command
CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name);
if (cc)
{
CCommand args;
args.Tokenize(CFmtStr("ssmaker 0 %s 1", buf));
cc->Dispatch(args);
}


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


//check focus
//sets the text
if (m_TextEntryPos1->HasFocus())
void SetItem(int index, const Vector& value);
{
 
//get text
//message funcs
char buf[512];
MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);
m_TextEntryPos1->GetText(buf, sizeof(buf));


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


//do command
private:
if (cc)
//position text entries
{
vgui::TextEntry* m_TextEntryPos0;
CCommand args;
vgui::TextEntry* m_TextEntryPos1;
args.Tokenize(CFmtStr("ssmaker 1 %s 1", buf));
vgui::TextEntry* m_TextEntryPos2;
cc->Dispatch(args);
vgui::TextEntry* m_TextEntryPos3;
}
vgui::TextEntry* m_TextEntryPos4;
vgui::TextEntry* m_TextEntryPos5;
vgui::TextEntry* m_TextEntryPos6;
vgui::TextEntry* m_TextEntryPos7;
vgui::CheckButton* m_ShowSoundscapePositions;
vgui::CheckButton* m_ShowSoundscapeDebug;


return;
friend class CSoundscapeMaker;
}
};


//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);
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSoundscapeSettingsPanel::CSoundscapeSettingsPanel(vgui::VPANEL parent, const char* name)
: BaseClass(nullptr, name)
{
SetParent(parent);


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


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


//check focus
//set the size and pos
if (m_TextEntryPos3->HasFocus())
int ScreenWide, ScreenTall;
{
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);
//get text
char buf[512];
m_TextEntryPos3->GetText(buf, sizeof(buf));


//convert to vector
SetTitle("Soundscape Maker Settings", true);
UTIL_StringToVector(g_SoundscapePositions[3].Base(), buf);
SetSize(SETTINGS_PANEL_WIDTH, SETTINGS_PANEL_HEIGHT);
SetPos((ScreenWide - SETTINGS_PANEL_WIDTH) / 2, (ScreenTall - SETTINGS_PANEL_HEIGHT) / 2);


//do command
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
if (cc)
{
CCommand args;
args.Tokenize(CFmtStr("ssmaker 3 %s 1", buf));
cc->Dispatch(args);
}


return;
//load settings
}
KeyValues* settings = new KeyValues("settings");
if (!settings->LoadFromFile(filesystem, "cfg/soundscape_maker.txt", "MOD"))
ConWarning("Failed to load settings for 'cfg/soundscape_maker.txt'. Using default settings.");


//check focus
//get positions
if (m_TextEntryPos4->HasFocus())
const char* pos0 = settings->GetString("Position0", "0 0 0");
{
const char* pos1 = settings->GetString("Position1", "0 0 0");
//get text
const char* pos2 = settings->GetString("Position2", "0 0 0");
char buf[512];
const char* pos3 = settings->GetString("Position3", "0 0 0");
m_TextEntryPos4->GetText(buf, sizeof(buf));
const char* pos4 = settings->GetString("Position4", "0 0 0");
const char* pos5 = settings->GetString("Position5", "0 0 0");
const char* pos6 = settings->GetString("Position6", "0 0 0");
const char* pos7 = settings->GetString("Position7", "0 0 0");


//convert to vector
//create position text 1
UTIL_StringToVector(g_SoundscapePositions[4].Base(), buf);
m_TextEntryPos0 = new vgui::TextEntry(this, "PosTextEntry0");
m_TextEntryPos0->SetEnabled(true);
m_TextEntryPos0->SetText(pos0 ? pos0 : "0 0 0");
m_TextEntryPos0->SetBounds(5, 30, 230, 20);
m_TextEntryPos0->SetMaximumCharCount(32);


//do command
//create position 1 button
if (cc)
vgui::Button* m_ButtonPos0 = new vgui::Button(this, "PosButton0", "Find Position 0", this, SETTINGS_PANEL_COMMAND_POS1);
{
m_ButtonPos0->SetBounds(240, 30, 100, 20);
CCommand args;
args.Tokenize(CFmtStr("ssmaker 4 %s 1", buf));
cc->Dispatch(args);
}


return;
//create position text 1
}
m_TextEntryPos1 = new vgui::TextEntry(this, "PosTextEntry1");
m_TextEntryPos1->SetEnabled(true);
m_TextEntryPos1->SetText(pos1 ? pos1 : "0 0 0");
m_TextEntryPos1->SetBounds(5, 55, 230, 20);
m_TextEntryPos1->SetMaximumCharCount(32);


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


//convert to vector
//create position 1 button
UTIL_StringToVector(g_SoundscapePositions[5].Base(), buf);
vgui::Button* m_ButtonPos2 = new vgui::Button(this, "PosButton2", "Find Position 2", this, SETTINGS_PANEL_COMMAND_POS3);
m_ButtonPos2->SetBounds(240, 80, 100, 20);


//do command
// create position text 4
if (cc)
m_TextEntryPos3 = new vgui::TextEntry(this, "PosTextEntry3");
{
m_TextEntryPos3->SetEnabled(true);
CCommand args;
m_TextEntryPos3->SetText(pos3 ? pos3 : "0 0 0");
args.Tokenize(CFmtStr("ssmaker 5 %s 1", buf));
m_TextEntryPos3->SetBounds(5, 105, 230, 20);
cc->Dispatch(args);
m_TextEntryPos3->SetMaximumCharCount(32);
}


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


//check focus
// create position text 5
if (m_TextEntryPos6->HasFocus())
m_TextEntryPos4 = new vgui::TextEntry(this, "PosTextEntry4");
{
m_TextEntryPos4->SetEnabled(true);
//get text
m_TextEntryPos4->SetText(pos4 ? pos4 : "0 0 0");
char buf[512];
m_TextEntryPos4->SetBounds(5, 130, 230, 20);
m_TextEntryPos6->GetText(buf, sizeof(buf));
m_TextEntryPos4->SetMaximumCharCount(32);


//convert to vector
// create position 5 button
UTIL_StringToVector(g_SoundscapePositions[6].Base(), buf);
vgui::Button* m_ButtonPos4 = new vgui::Button(this, "PosButton4", "Find Position 4", this, SETTINGS_PANEL_COMMAND_POS5);
m_ButtonPos4->SetBounds(240, 130, 100, 20);


//do command
// create position text 6
if (cc)
m_TextEntryPos5 = new vgui::TextEntry(this, "PosTextEntry5");
{
m_TextEntryPos5->SetEnabled(true);
CCommand args;
m_TextEntryPos5->SetText(pos5 ? pos5 : "0 0 0");
args.Tokenize(CFmtStr("ssmaker 6 %s 1", buf));
m_TextEntryPos5->SetBounds(5, 155, 230, 20);
cc->Dispatch(args);
m_TextEntryPos5->SetMaximumCharCount(32);
}


return;
// 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);


//check focus
// create position text 7
if (m_TextEntryPos7->HasFocus())
m_TextEntryPos6 = new vgui::TextEntry(this, "PosTextEntry6");
{
m_TextEntryPos6->SetEnabled(true);
//get text
m_TextEntryPos6->SetText(pos6 ? pos6 : "0 0 0");
char buf[512];
m_TextEntryPos6->SetBounds(5, 180, 230, 20);
m_TextEntryPos7->GetText(buf, sizeof(buf));
m_TextEntryPos6->SetMaximumCharCount(32);


//convert to vector
// create position 7 button
UTIL_StringToVector(g_SoundscapePositions[7].Base(), buf);
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(pos7 ? pos7 : "0 0 0");
m_TextEntryPos7->SetBounds(5, 205, 230, 20);
m_TextEntryPos7->SetMaximumCharCount(32);


//do command
// create position 8 button
if (cc)
vgui::Button* m_ButtonPos7 = new vgui::Button(this, "PosButton7", "Find Position 7", this, SETTINGS_PANEL_COMMAND_POS8);
{
m_ButtonPos7->SetBounds(240, 205, 100, 20);
CCommand args;
args.Tokenize(CFmtStr("ssmaker 7 %s 1", buf));
cc->Dispatch(args);
}


return;
// 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);
m_ShowSoundscapePositions->SetSelected(settings->GetBool("ShowSoundscapes", false));
 
//set convar value
ConVar* cv = cvar->FindVar("__ss_draw");
if (cv)
cv->SetValue(m_ShowSoundscapePositions->IsSelected());


}
//create divider
vgui::Divider* div = new vgui::Divider(this, "Divider");
div->SetBounds(-2, 247, SETTINGS_PANEL_WIDTH + 4, 2);


//-----------------------------------------------------------------------------
//create debug thing
// Purpose: Destructor
bool bDebugSelected = settings->GetBool("PrintDebug");
//-----------------------------------------------------------------------------
CSoundscapeSettingsPanel::~CSoundscapeSettingsPanel()
{
//save everything
KeyValues* settings = new KeyValues("settings");


//get text's
m_ShowSoundscapeDebug = new vgui::CheckButton(this, "DebugInfo", "Print Soundscape Debug Info");
char text0[64];
m_ShowSoundscapeDebug->SetBounds(73, 250, 200, 20);
char text1[64];
m_ShowSoundscapeDebug->SetCommand(SETTINGS_PANEL_COMMAND_DEBUG);
char text2[64];
m_ShowSoundscapeDebug->SetSelected(bDebugSelected);
char text3[64];
char text4[64];
char text5[64];
char text6[64];
char text7[64];


m_TextEntryPos0->GetText(text0, sizeof(text0));
if (bDebugSelected)
m_TextEntryPos1->GetText(text1, sizeof(text1));
OnCommand(SETTINGS_PANEL_COMMAND_DEBUG);
m_TextEntryPos2->GetText(text2, sizeof(text2));
m_TextEntryPos3->GetText(text3, sizeof(text3));
m_TextEntryPos4->GetText(text4, sizeof(text4));
m_TextEntryPos5->GetText(text5, sizeof(text5));
m_TextEntryPos6->GetText(text6, sizeof(text6));
m_TextEntryPos7->GetText(text7, sizeof(text7));


//save text entries
//set server positions
settings->SetString("Position0", text0);
ConCommand* cc = cvar->FindCommand("__ss_maker_set");
settings->SetString("Position1", text1);
if (cc)
settings->SetString("Position2", text2);
{
settings->SetString("Position3", text3);
CCommand args;
settings->SetString("Position4", text4);
settings->SetString("Position5", text5);
settings->SetString("Position6", text6);
settings->SetString("Position7", text7);


//save check buttons
//do pos 0
settings->SetBool("ShowSoundscapes", m_ShowSoundscapePositions->IsSelected());
if (pos0)
{
args.Tokenize(CFmtStr("ssmaker 0 %s 1", pos0));
cc->Dispatch(args);


//save to file
UTIL_StringToVector(g_SoundscapePositions[0].Base(), pos0);
settings->SaveToFile(filesystem, "cfg/soundscape_maker.txt", "MOD");
}
settings->deleteThis();
}


//static soundscape settings panel
//do pos 1
static CSoundscapeSettingsPanel* g_SettingsPanel = nullptr;
if (pos1)
{
args.Tokenize(CFmtStr("ssmaker 1 %s 1", pos1));
cc->Dispatch(args);


UTIL_StringToVector(g_SoundscapePositions[1].Base(), pos1);
}


//button
//do pos 2
class CSoundscapeButton : public vgui::Button
if (pos2)
{
{
public:
args.Tokenize(CFmtStr("ssmaker 2 %s 1", pos2));
DECLARE_CLASS_SIMPLE(CSoundscapeButton, vgui::Button)
cc->Dispatch(args);


CSoundscapeButton(vgui::Panel* parent, const char* name, const char* text, vgui::Panel* target = nullptr, const char* command = nullptr)
UTIL_StringToVector(g_SoundscapePositions[2].Base(), pos2);
: BaseClass(parent, name, text, target, command), m_bIsSelected(false)  
}
{
 
m_ColorSelected = Color(200, 200, 200, 200);
//do pos 3
m_FgColorSelected = Color(0, 0, 0, 255);
if (pos3)
}
{
args.Tokenize(CFmtStr("ssmaker 3 %s 1", pos3));
cc->Dispatch(args);


//apply scheme settings
UTIL_StringToVector(g_SoundscapePositions[3].Base(), pos3);
void ApplySchemeSettings(vgui::IScheme* scheme)
}
{
BaseClass::ApplySchemeSettings(scheme);


m_ColorNotSelected = GetButtonArmedBgColor();
//do pos 4
m_FgColorNotSelectedd = GetButtonArmedFgColor();
if (pos4)
}
{
args.Tokenize(CFmtStr("ssmaker 4 %s 1", pos4));
cc->Dispatch(args);


//paints the background
UTIL_StringToVector(g_SoundscapePositions[4].Base(), pos4);
void PaintBackground()
}
{
if (m_bIsSelected)
SetBgColor(m_ColorSelected);
else
SetBgColor(m_ColorNotSelected);


BaseClass::PaintBackground();
//do pos 5
}
if (pos5)
{
//paints
args.Tokenize(CFmtStr("ssmaker 5 %s 1", pos5));
void Paint()
cc->Dispatch(args);
{
if (m_bIsSelected)
SetFgColor(m_FgColorSelected);
else
SetFgColor(m_FgColorNotSelectedd);
BaseClass::Paint();
}


//is this selected or not
UTIL_StringToVector(g_SoundscapePositions[5].Base(), pos5);
bool m_bIsSelected;
}
static Color m_ColorSelected;
static Color m_ColorNotSelected;
static Color m_FgColorSelected;
static Color m_FgColorNotSelectedd;
};


Color CSoundscapeButton::m_ColorSelected = Color();
//do pos 6
Color CSoundscapeButton::m_ColorNotSelected = Color();
if (pos6)
Color CSoundscapeButton::m_FgColorSelected = Color();
{
Color CSoundscapeButton::m_FgColorNotSelectedd = Color();
args.Tokenize(CFmtStr("ssmaker 6 %s 1", pos6));
cc->Dispatch(args);


UTIL_StringToVector(g_SoundscapePositions[6].Base(), pos6);
}


//soundscape combo box
//do pos 7
if (pos7)
{
args.Tokenize(CFmtStr("ssmaker 7 %s", pos7));
cc->Dispatch(args);


class CSoundListComboBox : public vgui::ComboBox
UTIL_StringToVector(g_SoundscapePositions[7].Base(), pos7);
{
}
public:
}
DECLARE_CLASS_SIMPLE(CSoundListComboBox, vgui::ComboBox);


CSoundListComboBox(Panel* parent, const char* panelName, int numLines, bool allowEdit) :
//delete settings
BaseClass(parent, panelName, numLines, allowEdit) {}
settings->deleteThis();
}


//on key typed. check for menu item with text inside it and if found then
//-----------------------------------------------------------------------------
//select that item.
// Purpose: Called on command
void OnKeyTyped(wchar_t unichar)
//-----------------------------------------------------------------------------
void CSoundscapeSettingsPanel::OnCommand(const char* pszCommand)
{
if (Q_strstr(pszCommand, "GetPos") == pszCommand)
{
{
//check for ctrl or shift down
//search for number
if (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LCONTROL) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RCONTROL) || unichar == '`')
pszCommand = pszCommand + 6;
return;


//open up this combo box
//execute command
if (unichar == 13)
static ConCommand* cc = cvar->FindCommand("__ss_maker_start");
if (cc)
{
{
ShowMenu();
//hide everything first
return;
g_SoundscapeMaker->SetAllVisible(false);
 
CCommand args;
args.Tokenize(CFmtStr("ssmaker %d", atoi(pszCommand)));
cc->Dispatch(args);
}
}


BaseClass::OnKeyTyped(unichar);
return;
}


//check for backspace
else if (!Q_strcmp(pszCommand, SETTINGS_PANEL_COMMAND_SHOW))
if (unichar == 8 || unichar == '_')
{
return;
static ConVar* cv = cvar->FindVar("__ss_draw");
if (cv)
cv->SetValue(m_ShowSoundscapePositions->IsSelected());


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


//start from current index + 1
//handle debug thing
int start = GetMenu()->GetActiveItem() + 1;
else if (!Q_strcmp(pszCommand, SETTINGS_PANEL_COMMAND_DEBUG))
{
//get vars
static ConVar* con_filter_enable = cvar->FindVar("con_filter_enable");
static ConVar* con_filter_text = cvar->FindVar("con_filter_text");


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


BaseClass::OnCommand(pszCommand);
}


//sounds list panel
//-----------------------------------------------------------------------------
 
// Purpose: Constructor
#define SOUND_LIST_PANEL_WIDTH 375
//-----------------------------------------------------------------------------
#define SOUND_LIST_PANEL_HEIGHT 255
void CSoundscapeSettingsPanel::SetItem(int index, const Vector& value)
#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:
const char* text = CFmtStr("%.3f %.3f %.3f", value.x, value.y, value.z);
DECLARE_CLASS_SIMPLE(CSoundListPanel, vgui::Frame);


CSoundListPanel(vgui::VPANEL parent, const char* name);
//check index
 
switch (index)
//initalizes sound combo box
{
void InitalizeSounds();
case 0:
 
m_TextEntryPos0->RequestFocus();
//other
m_TextEntryPos0->SetText(text);
void OnCommand(const char* pszCommand);
g_SoundscapePositions[0] = value;
void OnClose();
break;
 
private:
case 1:
friend class CSoundscapeMaker;
m_TextEntryPos1->RequestFocus();
 
m_TextEntryPos1->SetText(text);
CSoundListComboBox* m_SoundsList;
g_SoundscapePositions[1] = value;
vgui::TextEntry* m_SearchText;
break;
vgui::Button* m_SearchButton;
vgui::Button* m_PlayButton;
case 2:
vgui::Button* m_StopSoundButton;
m_TextEntryPos2->RequestFocus();
vgui::Button* m_InsertButton;
m_TextEntryPos2->SetText(text);
vgui::Button* m_ReloadSounds;
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;


//current sound guid
case 6:
int m_iSongGuid = -1;
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
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
void CSoundscapeSettingsPanel::OnTextChanged(KeyValues* kv)
//-----------------------------------------------------------------------------
CSoundListPanel::CSoundListPanel(vgui::VPANEL parent, const char* name)
: BaseClass(nullptr, name)
{
{
SetParent(parent);
static ConCommand* cc = cvar->FindCommand("__ss_maker_set");


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


SetProportional(false);
//convert to vector
SetTitleBarVisible(true);
UTIL_StringToVector(g_SoundscapePositions[0].Base(), buf);
SetMinimizeButtonVisible(false);
SetMaximizeButtonVisible(false);
SetCloseButtonVisible(true);
SetSizeable(false);
SetMoveable(true);
SetVisible(false);


//set the size and pos
//do command
int ScreenWide, ScreenTall;
if (cc)
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);
{
 
CCommand args;
SetTitle("Sounds List", true);
args.Tokenize(CFmtStr("ssmaker 0 %s 1", buf));
SetSize(SOUND_LIST_PANEL_WIDTH, SOUND_LIST_PANEL_HEIGHT);
cc->Dispatch(args);
SetPos((ScreenWide - SOUND_LIST_PANEL_WIDTH) / 2, (ScreenTall - SOUND_LIST_PANEL_HEIGHT) / 2);
}


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


//create combo box
//check focus
m_SoundsList = new CSoundListComboBox(this, "SoundsList", 20, true);
if (m_TextEntryPos1->HasFocus())
m_SoundsList->SetBounds(5, 25, SOUND_LIST_PANEL_WIDTH - 15, 20);
{
m_SoundsList->AddActionSignalTarget(this);
//get text
char buf[512];
//make divider
m_TextEntryPos1->GetText(buf, sizeof(buf));
vgui::Divider* divider1 = new vgui::Divider(this, "Divider");
divider1->SetBounds(-5, 48, SOUND_LIST_PANEL_WIDTH + 10, 2);


//create text
//convert to vector
vgui::Label* label1 = new vgui::Label(this, "FindSound", "Find Sound");
UTIL_StringToVector(g_SoundscapePositions[1].Base(), buf);
label1->SetBounds(147, 51, 120, 20);


//create text entry
//do command
m_SearchText = new vgui::TextEntry(this, "SearchTextEntry");
if (cc)
m_SearchText->SetBounds(5, 75, SOUND_LIST_PANEL_WIDTH - 15, 20);
{
m_SearchText->SetEnabled(true);
CCommand args;
m_SearchText->SetText("");
args.Tokenize(CFmtStr("ssmaker 1 %s 1", buf));
cc->Dispatch(args);
}


//create search for button
return;
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
//check focus
vgui::Divider* divider2 = new vgui::Divider(this, "Divider");
if (m_TextEntryPos2->HasFocus())
divider2->SetBounds(-5, 124, SOUND_LIST_PANEL_WIDTH + 10, 2);
{
//get text
char buf[512];
m_TextEntryPos2->GetText(buf, sizeof(buf));


//create text
//convert to vector
vgui::Label* label2 = new vgui::Label(this, "SoundButtons", "Sound Buttons");
UTIL_StringToVector(g_SoundscapePositions[2].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 2 %s 1", 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_TextEntryPos3->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_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 1", 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_TextEntryPos4->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_TextEntryPos4->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[4].Base(), buf);


//check for shift key
//do command
bool shift = (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LSHIFT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RSHIFT));
if (cc)
if (shift)
{
{
//start from current index - 1
CCommand args;
int start = m_SoundsList->GetMenu()->GetActiveItem() - 1;
args.Tokenize(CFmtStr("ssmaker 4 %s 1", buf));
cc->Dispatch(args);
}


//look for sound with same name starting from the start first and going down
return;
for (int i = start; i >= 0; i--)
}
{
if (Q_stristr(g_SoundDirectories[i], buf))
{
//select item
m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
m_SoundsList->ActivateItem(i);


//set text
//check focus
m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
if (m_TextEntryPos5->HasFocus())
return;
{
}
//get text
}
char buf[512];
m_TextEntryPos5->GetText(buf, sizeof(buf));


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


//now cheeck from the g_SoundDirectories to the start
//do command
for (int i = g_SoundDirectories.Count() - 1; i > start; i--)
if (cc)
{
{
if (Q_stristr(g_SoundDirectories[i], buf))
CCommand args;
{
args.Tokenize(CFmtStr("ssmaker 5 %s 1", 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;
}
}
}
}
else
{
//start from current index + 1
int start = m_SoundsList->GetMenu()->GetActiveItem() + 1;


//look for sound with same name starting from the start first
return;
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
//check focus
m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
if (m_TextEntryPos6->HasFocus())
return;
{
}
//get text
}
char buf[512];
m_TextEntryPos6->GetText(buf, sizeof(buf));


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


//now cheeck from 0 to the start
//do command
for (int i = 0; i < start; i++)
if (cc)
{
{
if (Q_stristr(g_SoundDirectories[i], buf))
CCommand args;
{
args.Tokenize(CFmtStr("ssmaker 6 %s 1", 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_TextEntryPos7->HasFocus())
{
{
//get the sound
//get text
char buf[512];
char buf[512];
m_SoundsList->GetText(buf, sizeof(buf));
m_TextEntryPos7->GetText(buf, sizeof(buf));
 
//convert to vector
UTIL_StringToVector(g_SoundscapePositions[7].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 7 %s 1", 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))
{
//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))
// Purpose: Destructor
{
//-----------------------------------------------------------------------------
enginesound->StopSoundByGuid(m_iSongGuid);
CSoundscapeSettingsPanel::~CSoundscapeSettingsPanel()
m_iSongGuid = -1;
{
}
//save everything
KeyValues* settings = new KeyValues("settings");


//get the sound
//get text's
char buf[512];
char text0[64];
m_SoundsList->GetText(buf, sizeof(buf));
char text1[64];
char text2[64];
char text3[64];
char text4[64];
char text5[64];
char text6[64];
char text7[64];


//set the sound text
m_TextEntryPos0->GetText(text0, sizeof(text0));
g_SoundscapeMaker->SetSoundText(buf);
m_TextEntryPos1->GetText(text1, sizeof(text1));
return;
m_TextEntryPos2->GetText(text2, sizeof(text2));
}
m_TextEntryPos3->GetText(text3, sizeof(text3));
else if (!Q_strcmp(pszCommand, SOUND_LIST_RELOAD_COMMAND))
m_TextEntryPos4->GetText(text4, sizeof(text4));
{
m_TextEntryPos5->GetText(text5, sizeof(text5));
//clear everything for the combo box and reload it
m_TextEntryPos6->GetText(text6, sizeof(text6));
m_SoundsList->RemoveAll();
m_TextEntryPos7->GetText(text7, sizeof(text7));


InitalizeSounds();
//save text entries
return;
settings->SetString("Position0", text0);
}
settings->SetString("Position1", text1);
settings->SetString("Position2", text2);
settings->SetString("Position3", text3);
settings->SetString("Position4", text4);
settings->SetString("Position5", text5);
settings->SetString("Position6", text6);
settings->SetString("Position7", text7);


BaseClass::OnCommand(pszCommand);
//save check buttons
}
settings->SetBool("ShowSoundscapes", m_ShowSoundscapePositions->IsSelected());
settings->SetBool("PrintDebug", m_ShowSoundscapeDebug->IsSelected());


//-----------------------------------------------------------------------------
//save to file
// Purpose: Called on panel close
settings->SaveToFile(filesystem, "cfg/soundscape_maker.txt", "MOD");
//-----------------------------------------------------------------------------
settings->deleteThis();
void CSoundListPanel::OnClose()
{
OnCommand(SOUND_LIST_STOP_COMMAND);
BaseClass::OnClose();
}
}


//-----------------------------------------------------------------------------
//static soundscape settings panel
// Purpose: Initalizes the sounds list
static CSoundscapeSettingsPanel* g_SettingsPanel = nullptr;
//-----------------------------------------------------------------------------
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);
//button
}
class CSoundscapeButton : public vgui::Button
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeButton, vgui::Button)


//static sound list instance
CSoundscapeButton(vgui::Panel* parent, const char* name, const char* text, vgui::Panel* target = nullptr, const char* command = nullptr)
static CSoundListPanel* g_SoundPanel = nullptr;
: BaseClass(parent, name, text, target, command), m_bIsSelected(false)
static bool g_SoundPanelInitalized = 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);


//soundscape list
m_ColorNotSelected = GetButtonArmedBgColor();
 
m_FgColorNotSelectedd = GetButtonArmedFgColor();
 
}
#define ADD_SOUNDSCAPE_COMMAND "AddSoundscape"


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


//soundscape list class
BaseClass::PaintBackground();
class CSoundscapeList : public vgui::Divider
}
{
public:
//paints
DECLARE_CLASS_SIMPLE(CSoundscapeList, vgui::Divider);
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;
};


//constructor
Color CSoundscapeButton::m_ColorSelected = Color();
CSoundscapeList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height);
Color CSoundscapeButton::m_ColorNotSelected = Color();
Color CSoundscapeButton::m_FgColorSelected = Color();
Color CSoundscapeButton::m_FgColorNotSelectedd = Color();


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


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


virtual void OnCommand(const char* pszCommand);
class CSoundListComboBox : public vgui::ComboBox
virtual void PaintBackground();
{
public:
DECLARE_CLASS_SIMPLE(CSoundListComboBox, vgui::ComboBox);


//message funcs
CSoundListComboBox(Panel* parent, const char* panelName, int numLines, bool allowEdit) :
MESSAGE_FUNC_INT(ScrollBarMoved, "ScrollBarSliderMoved", position);
BaseClass(parent, panelName, numLines, allowEdit) {}


protected:
//on key typed. check for menu item with text inside it and if found then
friend class CSoundscapeMaker;
//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;


//keyvalue list.
//open up this combo box
KeyValues* m_Keyvalues = nullptr;
if (unichar == 13)
{
ShowMenu();
return;
}


//says "Soundscapes List"
BaseClass::OnKeyTyped(unichar);
vgui::Label* m_pLabel;
vgui::ScrollBar* m_pSideSlider;


//menu
//check for backspace
vgui::Menu* menu;
if (unichar == 8 || unichar == '_')
return;


//menu button stuff
//get text
CUtlVector<CSoundscapeButton*> m_MenuButtons;
char buf[512];
int m_iCurrentY;
GetText(buf, sizeof(buf));
int m_iMax;
 
int m_AmtAdded;
//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;
}
}
}
};
};


//-----------------------------------------------------------------------------
// 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
//sounds list panel
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;
#define SOUND_LIST_PANEL_WIDTH 375
m_iMax = max;
#define SOUND_LIST_PANEL_HEIGHT 255
m_Keyvalues = nullptr;
#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
// 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
public:
CSoundscapeButton* button = new CSoundscapeButton(this, name, text, parent, command);
DECLARE_CLASS_SIMPLE(CSoundListPanel, vgui::Frame);
button->SetBounds(5, m_iCurrentY, GetWide() - 30, 20);


//increment current y
CSoundListPanel(vgui::VPANEL parent, const char* name);
m_iCurrentY = m_iCurrentY + 22;


//add button to array
//initalizes sound combo box
m_MenuButtons.AddToTail(button);
void InitalizeSounds();


//if the count is more then m_iMax then set slider value
//other
if (m_MenuButtons.Count() > m_iMax)
void OnCommand(const char* pszCommand);
{
void OnClose();
int max = m_MenuButtons.Count() - m_iMax;


m_pSideSlider->SetRange(0, max);
private:
m_pSideSlider->SetRangeWindow(1);
friend class CSoundscapeMaker;
m_pSideSlider->SetEnabled(true);
}


m_AmtAdded++;
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;


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


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Clears everything for this list
// Purpose: Constructor
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeList::Clear()
CSoundListPanel::CSoundListPanel(vgui::VPANEL parent, const char* name)
: BaseClass(nullptr, name)
{
{
//reset the slider
SetParent(parent);
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
SetKeyBoardInputEnabled(true);
for (int i = 0; i < m_MenuButtons.Count(); i++)
SetMouseInputEnabled(true);
m_MenuButtons[i]->DeletePanel();


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


//reset current y
//set the size and pos
m_iCurrentY = 22;
int ScreenWide, ScreenTall;
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);


m_AmtAdded = 0;
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"));
// 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
//create combo box
else if (delta == 1)
m_SoundsList = new CSoundListComboBox(this, "SoundsList", 20, true);
m_pSideSlider->SetValue(m_pSideSlider->GetValue() - 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: Called when a mouse code is released
vgui::Label* label1 = new vgui::Label(this, "FindSound", "Find Sound");
//-----------------------------------------------------------------------------
label1->SetBounds(147, 51, 120, 20);
void CSoundscapeList::OnMouseReleased(vgui::MouseCode code)
{
if (code != vgui::MouseCode::MOUSE_RIGHT)
return;


//get cursor pos
//create text entry
int x, y;
m_SearchText = new vgui::TextEntry(this, "SearchTextEntry");
vgui::surface()->SurfaceGetCursorPos(x, y);
m_SearchText->SetBounds(5, 75, SOUND_LIST_PANEL_WIDTH - 15, 20);
m_SearchText->SetEnabled(true);
m_SearchText->SetText("");


//create menu
//create search for button
menu = new vgui::Menu(this, "Menu");
m_SearchButton = new vgui::Button(this, "SearchButton", "Search For");
menu->AddMenuItem("AddSoundscape", "Add Soundscape", ADD_SOUNDSCAPE_COMMAND, this);
m_SearchButton->SetBounds(5, 100, SOUND_LIST_PANEL_WIDTH - 15, 20);;
menu->SetBounds(x, y, 200, 50);
m_SearchButton->SetEnabled(true);
menu->SetVisible(true);
m_SearchButton->SetCommand(SOUND_LIST_SEARCH_COMMAND);
}


//-----------------------------------------------------------------------------
//make divider
// Purpose: Called on command
vgui::Divider* divider2 = new vgui::Divider(this, "Divider");
//-----------------------------------------------------------------------------
divider2->SetBounds(-5, 124, SOUND_LIST_PANEL_WIDTH + 10, 2);
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
//create text
KeyValues* kv = new KeyValues(name);
vgui::Label* label2 = new vgui::Label(this, "SoundButtons", "Sound Buttons");
KeyValues* tmp = m_Keyvalues;
label2->SetBounds(140, 127, 120, 20);
KeyValues* tmp2 = tmp;


//get last subkey
//create play button
while (tmp != nullptr)
m_PlayButton = new vgui::Button(this, "PlayButton", "Play Sound", this);
{
m_PlayButton ->SetBounds(5, 150, SOUND_LIST_PANEL_WIDTH - 15, 20);
tmp2 = tmp;
m_PlayButton->SetCommand(SOUND_LIST_PLAY_COMMAND);
tmp = tmp->GetNextTrueSubKey();
}


//add to last subkey
//create stop sound button
tmp2->SetNextKey(kv);
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);


GetParent()->OnCommand(name);
//create sound insert button
return;
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);


BaseClass::OnCommand(pszCommand);
//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: Paints the background
// Purpose: Called on command
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeList::PaintBackground()
void CSoundListPanel::OnCommand(const char* pszCommand)
{
{
//colors
if (!Q_strcmp(pszCommand, SOUND_LIST_SEARCH_COMMAND))
static Color EnabledColor = Color(100, 100, 100, 200);
{
static Color DisabledColor = Color(60, 60, 60, 200);
//get text
char buf[512];
m_SearchText->GetText(buf, sizeof(buf));
 
//check for shift key
bool shift = (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LSHIFT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RSHIFT));
if (shift)
{
//start from current index - 1
int start = m_SoundsList->GetMenu()->GetActiveItem() - 1;


//if m_KeyValues then paint the default color
//look for sound with same name starting from the start first and going down
if (m_Keyvalues)
for (int i = start; i >= 0; i--)
SetBgColor(EnabledColor);
{
else
if (Q_stristr(g_SoundDirectories[i], buf))
SetBgColor(DisabledColor);
{
//select item
m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
m_SoundsList->ActivateItem(i);


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


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


//move everything down (if needed)
//now cheeck from the g_SoundDirectories to the start
for (int i = 0; i < m_MenuButtons.Count(); i++)
for (int i = g_SoundDirectories.Count() - 1; i > start; i--)
{
{
//make not visible if i < position
if (Q_stristr(g_SoundDirectories[i], buf))
if (i < position)
{
//select item
m_SoundsList->GetMenu()->SetCurrentlyHighlightedItem(i);
m_SoundsList->ActivateItem(i);
 
//set text
m_SoundsList->SetText(m_SoundsList->GetMenu()->GetMenuItem(i)->GetName());
return;
}
}
}
else
{
{
m_MenuButtons[i]->SetVisible(false);
//start from current index + 1
continue;
int start = m_SoundsList->GetMenu()->GetActiveItem() + 1;
}


m_MenuButtons[i]->SetPos(5, 22 * ((i - position) + 1));
//look for sound with same name starting from the start first
m_MenuButtons[i]->SetVisible(true);
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);


//soundscape data list
//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));


#define NEW_PLAYLOOPING_COMMAND "NewLooping"
//stop the sound
#define NEW_SOUNDSCAPE_COMMAND "NewSoundscape"
if (enginesound->IsSoundStillPlaying(m_iSongGuid))
#define NEW_RANDOM_COMMAND "NewRandom"
{
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;
}


class CSoundscapeDataList : public CSoundscapeList
return;
{
}
public:
else if (!Q_strcmp(pszCommand, SOUND_LIST_INSERT_COMMAND))
DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
{
//make not visible
CSoundscapeDataList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
SetVisible(false);
: 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);
//stop the sound
if (enginesound->IsSoundStillPlaying(m_iSongGuid))
{
enginesound->StopSoundByGuid(m_iSongGuid);
m_iSongGuid = -1;
}


private:
//get the sound
friend class CSoundscapeMaker;
char buf[512];
};
m_SoundsList->GetText(buf, sizeof(buf));


 
//set the sound text
//-----------------------------------------------------------------------------
g_SoundscapeMaker->SetSoundText(buf);
// Purpose: Called when a mouse code is released
return;
//-----------------------------------------------------------------------------
}
void CSoundscapeDataList::OnMouseReleased(vgui::MouseCode code)
else if (!Q_strcmp(pszCommand, SOUND_LIST_RELOAD_COMMAND))
{
{
//if no soundscape is selected or mouse code != right then return
//clear everything for the combo box and reload it
if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
m_SoundsList->RemoveAll();
 
InitalizeSounds();
return;
return;
}


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


//create menu
//-----------------------------------------------------------------------------
menu = new vgui::Menu(this, "Menu");
// Purpose: Called on panel close
menu->AddMenuItem("AddLooping", "Add Looping Sound", NEW_PLAYLOOPING_COMMAND, this);
//-----------------------------------------------------------------------------
menu->AddMenuItem("AddSoundscape", "Add Soundscape", NEW_SOUNDSCAPE_COMMAND, this);
void CSoundListPanel::OnClose()
menu->AddMenuItem("AddSoundscape", "Add Random Sounds", NEW_RANDOM_COMMAND, this);
{
menu->SetBounds(x, y, 200, 50);
OnCommand(SOUND_LIST_STOP_COMMAND);
menu->SetVisible(true);
BaseClass::OnClose();
}
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Called on command
// Purpose: Initalizes the sounds list
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeDataList::OnCommand(const char* pszCommand)
void CSoundListPanel::InitalizeSounds()
{
{
if (!Q_strcmp(pszCommand, NEW_PLAYLOOPING_COMMAND))
//get the sound array
{
GetSoundNames();
int LoopingNum = 0;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
{
//store data name
const char* name = data->GetName();


//increment variables based on name
//add all the sounds
if (!Q_strcasecmp(name, "playlooping"))
for (int i = 0; i < g_SoundDirectories.Size(); i++)
LoopingNum++;
m_SoundsList->AddItem(g_SoundDirectories[i], nullptr);
}


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


//add the keyvalues
//static sound list instance
KeyValues* kv = new KeyValues("playlooping");
static CSoundListPanel* g_SoundPanel = nullptr;
kv->SetFloat("volume", 1);
static bool g_SoundPanelInitalized = false;
kv->SetInt("pitch", 100);


m_Keyvalues->AddSubKey(kv);


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


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
#define ADD_SOUNDSCAPE_COMMAND "AddSoundscape"
if (!Q_strcasecmp(name, "playsoundscape"))
SoundscapeNum++;
}


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


//add the keyvalues
//soundscape list class
KeyValues* kv = new KeyValues("playsoundscape");
class CSoundscapeList : public vgui::Divider
kv->SetFloat("volume", 1);
{
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);


//add the keyvalue to both this and the keyvalues
//menu item stuff
m_Keyvalues->AddSubKey(kv);
virtual void AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent);
virtual void Clear();


GetParent()->OnCommand(CFmtStr("$playsoundscape%d", SoundscapeNum + 1));
//other
virtual void OnMouseWheeled(int delta);
virtual void OnMouseReleased(vgui::MouseCode code);


return;
virtual void OnCommand(const char* pszCommand);
}
virtual void PaintBackground();
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
virtual void OnKeyCodePressed(vgui::KeyCode code);
if (!Q_strcasecmp(name, "playrandom"))
RandomNum++;
}


AddButton("playrandom", "playrandom", CFmtStr("$playrandom%d", RandomNum + 1), GetParent());
//message funcs
MESSAGE_FUNC_INT(ScrollBarMoved, "ScrollBarSliderMoved", position);


//add the keyvalues
protected:
KeyValues* kv = new KeyValues("playrandom");
friend class CSoundscapeMaker;
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
//keyvalue list.
m_Keyvalues->AddSubKey(kv);
KeyValues* m_Keyvalues = nullptr;


//make the parent show the new item
//says "Soundscapes List"
GetParent()->OnCommand(CFmtStr("$playrandom%d", RandomNum + 1));
vgui::Label* m_pLabel;
vgui::ScrollBar* m_pSideSlider;


return;
//menu
}
vgui::Menu* menu;


BaseClass::OnCommand(pszCommand);
//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);


//soundscape rndwave data list
//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;
}


#define NEW_RNDWAVE_WAVE_COMMAND "NewRNDWave"
//-----------------------------------------------------------------------------
 
// Purpose: adds a button to the soundscape list
 
//-----------------------------------------------------------------------------
class CSoundscapeRndwaveList : public CSoundscapeList
void CSoundscapeList::AddButton(const char* name, const char* text, const char* command, vgui::Panel* parent)
{
{
public:
//create a new button
DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
CSoundscapeButton* button = new CSoundscapeButton(this, name, text, parent, command);
button->SetBounds(5, m_iCurrentY, GetWide() - 30, 20);
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
//increment current y
virtual void OnMouseReleased(vgui::MouseCode code);
m_iCurrentY = m_iCurrentY + 22;


void OnCommand(const char* pszCommand);
//add button to array
m_MenuButtons.AddToTail(button);


private:
//if the count is more then m_iMax then set slider value
friend class CSoundscapeMaker;
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++;
// 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
//check to see if we need to scroll down
int x, y;
if (m_MenuButtons.Count() >= m_iMax)
vgui::surface()->SurfaceGetCursorPos(x, y);
OnMouseWheeled(-1);
 
//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
// Purpose: Clears everything for this list
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeRndwaveList::OnCommand(const char* pszCommand)
void CSoundscapeList::Clear()
{
{
if (!Q_strcmp(pszCommand, NEW_RNDWAVE_WAVE_COMMAND) && m_Keyvalues)
//reset the slider
{
m_pSideSlider->SetValue(0);
//get number of keyvalues
m_pSideSlider->SetEnabled(false);
int num = 0;
m_pSideSlider->SetRange(0, 0);
m_pSideSlider->SetButtonPressedScrollValue(1);
m_pSideSlider->SetRangeWindow(0);


FOR_EACH_VALUE(m_Keyvalues, kv)
//delete and clear the buttons
num++;
for (int i = 0; i < m_MenuButtons.Count(); i++)
m_MenuButtons[i]->DeletePanel();
//add keyvalues and button
AddButton("Rndwave", "", CFmtStr("$rndwave%d", num + 1), GetParent());


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


//forward command to parent
//reset current y
GetParent()->OnCommand(CFmtStr("$rndwave%d", num + 1));
m_iCurrentY = 22;


return;
m_AmtAdded = 0;
}
 
BaseClass::OnCommand(pszCommand);
}
}


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


//soundscape panel
//-----------------------------------------------------------------------------
 
// Purpose: Called when a mouse code is released
 
//-----------------------------------------------------------------------------
#define SOUNDSCAPE_PANEL_WIDTH 760
void CSoundscapeList::OnMouseReleased(vgui::MouseCode code)
#define SOUNDSCAPE_PANEL_HEIGHT 630
{
if (code != vgui::MouseCode::MOUSE_RIGHT)
return;


#define NEW_BUTTON_COMMAND "$NewSoundscape"
//get cursor pos
#define SAVE_BUTTON_COMMAND "$SaveSoundscape"
int x, y;
#define LOAD_BUTTON_COMMAND "$LoadSoundscape"
vgui::surface()->SurfaceGetCursorPos(x, y);
#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
//create menu
bool g_ShowSoundscapePanel = false;
menu = new vgui::Menu(this, "Menu");
bool g_IsPlayingSoundscape = false;
menu->AddMenuItem("AddSoundscape", "Add Soundscape", ADD_SOUNDSCAPE_COMMAND, this);
menu->SetBounds(x, y, 200, 50);
menu->SetVisible(true);
}


//soundscape maker panel
//-----------------------------------------------------------------------------
class CSoundscapeMaker : public vgui::Frame, CAutoGameSystem
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundscapeList::OnCommand(const char* pszCommand)
{
{
public:
if (!Q_strcmp(pszCommand, ADD_SOUNDSCAPE_COMMAND))
DECLARE_CLASS_SIMPLE(CSoundscapeMaker, vgui::Frame)
{
const char* name = CFmtStr("New Soundscape %d", m_AmtAdded);
AddButton(name, name, name, GetParent());


CSoundscapeMaker(vgui::VPANEL parent);
//add to keyvalues file
KeyValues* kv = new KeyValues(name);
KeyValues* tmp = m_Keyvalues;
KeyValues* tmp2 = tmp;


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


//other functions
//add to last subkey
void OnClose();
tmp2->SetNextKey(kv);
void OnCommand(const char* pszCommand);


void PlaySelectedSoundscape();
GetParent()->OnCommand(name);
void LoadFile(KeyValues* file);
return;
}


void OnKeyCodePressed(vgui::KeyCode code);
BaseClass::OnCommand(pszCommand);
}


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


//to play the soundscape on map spawn
//if m_KeyValues then paint the default color
void LevelInitPostEntity();
if (m_Keyvalues)
SetBgColor(EnabledColor);
else
SetBgColor(DisabledColor);


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


~CSoundscapeMaker();
//-----------------------------------------------------------------------------
// Purpose: Called on keyboard code pressed
//-----------------------------------------------------------------------------
void CSoundscapeList::OnKeyCodePressed(vgui::KeyCode code)
{
//check for arrow
if (code == KEY_UP)
{
//find selected item
for (int i = 0; i < m_MenuButtons.Count(); i++)
{
if (m_MenuButtons[i]->m_bIsSelected)
{
//check for size and to see if we can select item
if (i - 1 < 0)
return;


private:
//select that item
//the soundscape keyvalues file
GetParent()->OnCommand(m_MenuButtons[i-1]->GetCommand()->GetString("command"));
KeyValues* m_KeyValues = nullptr;
return;
}
}
}
//check for arrow
if (code == KEY_DOWN)
{
//find selected item
for (int i = 0; i < m_MenuButtons.Count(); i++)
{
if (m_MenuButtons[i]->m_bIsSelected)
{
//check for size and to see if we can select item
if (i + 1 >= m_MenuButtons.Count())
return;


private:
//select that item
void CreateEverything();
GetParent()->OnCommand(m_MenuButtons[i+1]->GetCommand()->GetString("command"));
return;
}
}
}
}


private:
//-----------------------------------------------------------------------------
//lists all the soundscapes
// Purpose: Called on scroll bar moved
CSoundscapeList* m_SoundscapesList;
//-----------------------------------------------------------------------------
CSoundscapeDataList* m_pDataList;
void CSoundscapeList::ScrollBarMoved(int delta)
CSoundscapeRndwaveList* m_pSoundList;
{
int position = m_pSideSlider->GetValue();


//buttons
//move everything down (if needed)
vgui::Button* m_ButtonNew = nullptr;
for (int i = 0; i < m_MenuButtons.Count(); i++)
vgui::Button* m_ButtonSave = nullptr;
{
vgui::Button* m_ButtonLoad = nullptr;
//make not visible if i < position
if (i < position)
{
m_MenuButtons[i]->SetVisible(false);
continue;
}


//file load and save dialogs
m_MenuButtons[i]->SetPos(5, 22 * ((i - position) + 1));
vgui::FileOpenDialog* m_FileSave = nullptr;
m_MenuButtons[i]->SetVisible(true);
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
//soundscape data list
vgui::Button* m_SoundNamePlay;


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


//current selected soundscape
#define NEW_PLAYLOOPING_COMMAND "NewLooping"
CSoundscapeButton* m_pCurrentSelected = nullptr;
#define NEW_SOUNDSCAPE_COMMAND "NewSoundscape"
KeyValues* m_kvCurrSelected = nullptr;
#define NEW_RANDOM_COMMAND "NewRandom"
KeyValues* m_kvCurrSound = nullptr;
 
KeyValues* m_kvCurrRndwave = nullptr;
 
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)
{}


int m_iCurrRndWave = 0;
//override right click functionality
virtual void OnMouseReleased(vgui::MouseCode code);


//currently in non randomwave thing
void OnCommand(const char* pszCommand);
SoundscapeMode m_iSoundscapeMode = SoundscapeMode::Mode_Random;


//temporary added soundscapes
private:
CUtlVector<KeyValues*> m_TmpAddedSoundscapes;
friend class CSoundscapeMaker;
};
};


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


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor for soundscape maker panel
// Purpose: Called when a mouse code is released
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CSoundscapeMaker::CSoundscapeMaker(vgui::VPANEL parent)
void CSoundscapeDataList::OnMouseReleased(vgui::MouseCode code)
: BaseClass(nullptr, "SoundscapeMaker")
{
{
static bool bRegistered = false;
//if no soundscape is selected or mouse code != right then return
if (!bRegistered)
if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
{
return;
usermessages->HookMessage("SoundscapeMaker_Recieve", _SoundscapeMaker_Recieve);
 
bRegistered = true;
//get cursor pos
}
int x, y;
vgui::surface()->SurfaceGetCursorPos(x, y);


//set variables
//create menu
m_pCurrentSelected = nullptr;
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);
}


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


SetProportional(false);
//-----------------------------------------------------------------------------
SetTitleBarVisible(true);
// Purpose: Called on command
SetMinimizeButtonVisible(false);
//-----------------------------------------------------------------------------
SetMaximizeButtonVisible(false);
void CSoundscapeDataList::OnCommand(const char* pszCommand)
SetCloseButtonVisible(true);
{
SetSizeable(false);
if (!Q_strcmp(pszCommand, NEW_PLAYLOOPING_COMMAND))
SetMoveable(true);
{
SetVisible(g_ShowSoundscapePanel);
int LoopingNum = 0;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
int ScreenWide, ScreenTall;
{
vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);
//store data name
const char* name = data->GetName();


SetTitle("Soundscape Maker (New File)", true);
//increment variables based on name
SetSize(SOUNDSCAPE_PANEL_WIDTH, SOUNDSCAPE_PANEL_HEIGHT);
if (!Q_strcasecmp(name, "playlooping"))
SetPos((ScreenWide - SOUNDSCAPE_PANEL_WIDTH) / 2, (ScreenTall - SOUNDSCAPE_PANEL_HEIGHT) / 2);
LoopingNum++;
}


SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
//add the keyvalue to both this and the keyvalues
AddButton("playlooping", "playlooping", CFmtStr("$playlooping%d", LoopingNum + 1), GetParent());


//add a tick signal for every 50 ms
//add the keyvalues
vgui::ivgui()->AddTickSignal(GetVPanel(), 50);
KeyValues* kv = new KeyValues("playlooping");
kv->SetFloat("volume", 1);
kv->SetInt("pitch", 100);


CreateEverything();
m_Keyvalues->AddSubKey(kv);
}


//-----------------------------------------------------------------------------
GetParent()->OnCommand(CFmtStr("$playlooping%d", LoopingNum + 1));
// 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
return;
//create the buttons
}
m_ButtonNew = new vgui::Button(this, "NewButton", "New Soundscape File");
else if (!Q_strcmp(pszCommand, NEW_SOUNDSCAPE_COMMAND))
m_ButtonNew->SetVisible(true);
{
m_ButtonNew->SetBounds(45, 600, 165, 25);
int SoundscapeNum = 0;
m_ButtonNew->SetCommand(NEW_BUTTON_COMMAND);
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
m_ButtonNew->SetDepressedSound("ui/buttonclickrelease.wav");
{
//store data name
const char* name = data->GetName();
 
//increment variables based on name
if (!Q_strcasecmp(name, "playsoundscape"))
SoundscapeNum++;
}


m_ButtonSave = new vgui::Button(this, "SaveButton", "Save Soundscapes");
AddButton("playsoundscape", "playsoundscape", CFmtStr("$playsoundscape%d", SoundscapeNum + 1), GetParent());
m_ButtonSave->SetVisible(true);
m_ButtonSave->SetBounds(215, 600, 165, 25);
m_ButtonSave->SetCommand(SAVE_BUTTON_COMMAND);
m_ButtonSave->SetDepressedSound("ui/buttonclickrelease.wav");


m_ButtonLoad = new vgui::Button(this, "LoadButton", "Load Soundscapes");
//add the keyvalues
m_ButtonLoad->SetVisible(true);
KeyValues* kv = new KeyValues("playsoundscape");
m_ButtonLoad->SetBounds(385, 600, 165, 25);
kv->SetFloat("volume", 1);
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(555, 600, 165, 25);
m_ButtonLoad->SetCommand(OPTIONS_BUTTON_COMMAND);
m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");


//create the soundscapes menu
//add the keyvalue to both this and the keyvalues
m_SoundscapesList = new CSoundscapeList(this, "SoundscapesList", "Soundscapes:", 90, 22, 300, 550);
m_Keyvalues->AddSubKey(kv);
m_SoundscapesList->SetBounds(15, 35, 300, 550);
m_SoundscapesList->SetVisible(true);


//create data list
GetParent()->OnCommand(CFmtStr("$playsoundscape%d", SoundscapeNum + 1));
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
return;
m_TextEntryName = new vgui::TextEntry(this, "NameTextEntry");
}
m_TextEntryName->SetEnabled(false);
else if (!Q_strcmp(pszCommand, NEW_RANDOM_COMMAND))
m_TextEntryName->SetBounds(325, 40, 295, 20);
{
m_TextEntryName->SetMaximumCharCount(50);
int RandomNum = 0;
FOR_EACH_TRUE_SUBKEY(m_Keyvalues, data)
{
//store data name
const char* name = data->GetName();


//dsp effects combo box
//increment variables based on name
m_DspEffects = new vgui::ComboBox(this, "DspEffects", sizeof(g_DspEffects) / sizeof(g_DspEffects[0]), false);
if (!Q_strcasecmp(name, "playrandom"))
m_DspEffects->SetEnabled(false);
RandomNum++;
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++)
AddButton("playrandom", "playrandom", CFmtStr("$playrandom%d", RandomNum + 1), GetParent());
m_DspEffects->AddItem(g_DspEffects[i], nullptr);


//time text entry
//add the keyvalues
m_TimeTextEntry = new vgui::TextEntry(this, "TimeTextEntry");
KeyValues* kv = new KeyValues("playrandom");
m_TimeTextEntry->SetBounds(325, 90, 295, 20);
kv->SetString("volume", "0.5,0.8");
m_TimeTextEntry->SetEnabled(false);
kv->SetInt("pitch", 100);
m_TimeTextEntry->SetVisible(true);
kv->SetString("time", "10,20");
//make rndwave subkey
KeyValues* rndwave = new KeyValues("rndwave");
kv->AddSubKey(rndwave);


//volume text entry
//add the keyvalue to both this and the keyvalues
m_VolumeTextEntry = new vgui::TextEntry(this, "VolumeTextEntry");
m_Keyvalues->AddSubKey(kv);
m_VolumeTextEntry->SetBounds(325, 115, 295, 20);
 
m_VolumeTextEntry->SetEnabled(false);
//make the parent show the new item
m_VolumeTextEntry->SetVisible(true);
GetParent()->OnCommand(CFmtStr("$playrandom%d", RandomNum + 1));


//pitch text entry
return;
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++)
BaseClass::OnCommand(pszCommand);
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
//soundscape rndwave data list
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
#define NEW_RNDWAVE_WAVE_COMMAND "NewRNDWave"
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
class CSoundscapeRndwaveList : public CSoundscapeList
vgui::Label* DspLabel = new vgui::Label(this, "DspLabel", "Soundscape Dsp");
{
DspLabel->SetBounds(635, 65, 125, 20);
public:
DECLARE_CLASS_SIMPLE(CSoundscapeDataList, CSoundscapeList);
//create the soundscape time text
CSoundscapeRndwaveList(vgui::Panel* parent, const char* name, const char* text, int text_x_pos, int max, int width, int height)
vgui::Label* TimeLabel = new vgui::Label(this, "TimeLabel", "Sound Time");
: CSoundscapeList(parent, name, text, text_x_pos, max, width, height)
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
//override right click functionality
vgui::Label* PitchLabel = new vgui::Label(this, "PitchLabel", "Sound Pitch");
virtual void OnMouseReleased(vgui::MouseCode code);
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
void OnCommand(const char* pszCommand);
vgui::Label* SoundLevelLabel = new vgui::Label(this, "SoundLevelLabel", "Sound Level");
SoundLevelLabel ->SetBounds(635, 190, 125, 20);


//create the soundscape sound name text
private:
vgui::Label* SoundName = new vgui::Label(this, "SoundName", "Sound Name");
friend class CSoundscapeMaker;
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
// Purpose: Called when a mouse code is released
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnTick()
void CSoundscapeRndwaveList::OnMouseReleased(vgui::MouseCode code)
{
{
//set the visibility
//if no soundscape is selected or mouse code != right then return
static bool bPrevVisible = g_ShowSoundscapePanel;
if (code != vgui::MouseCode::MOUSE_RIGHT || !m_Keyvalues)
if (g_ShowSoundscapePanel != bPrevVisible)
return;
SetVisible(g_ShowSoundscapePanel);


//set the old visibility
//get cursor pos
bPrevVisible = g_ShowSoundscapePanel;
int x, y;
}
vgui::surface()->SurfaceGetCursorPos(x, y);


//-----------------------------------------------------------------------------
//create menu
// Purpose: Called when the close button is pressed
menu = new vgui::Menu(this, "Menu");
//-----------------------------------------------------------------------------
menu->AddMenuItem("AddRandom", "Add Random Wave", NEW_RNDWAVE_WAVE_COMMAND, this);
void CSoundscapeMaker::OnClose()
menu->SetBounds(x, y, 200, 50);
{
menu->SetVisible(true);
//hide the other panels
}
g_SoundPanel->OnClose();
g_SettingsPanel->OnClose();


g_ShowSoundscapePanel = false;
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Play the selected soundscape
// Purpose: Called on command
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeMaker::PlaySelectedSoundscape()
void CSoundscapeRndwaveList::OnCommand(const char* pszCommand)
{
{
g_IsPlayingSoundscape = false;
if (!Q_strcmp(pszCommand, NEW_RNDWAVE_WAVE_COMMAND) && m_Keyvalues)
 
//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++)
//get number of keyvalues
{
int num = 0;
if (g_SoundscapeSystem.m_soundscapes[j] == m_TmpAddedSoundscapes[i])
{
g_SoundscapeSystem.m_soundscapes.Remove(j);
break;
}
}
}


m_TmpAddedSoundscapes.RemoveAll();
FOR_EACH_VALUE(m_Keyvalues, kv)
 
num++;
//change audio params position
//add keyvalues and button
g_SoundscapeSystem.m_params.localBits = 0x7f;
AddButton("Rndwave", "", CFmtStr("$rndwave%d", num + 1), GetParent());
for (int i = 0; i < MAX_SOUNDSCAPES - 1; i++)
 
g_SoundscapeSystem.m_params.localSound.Set(i, g_SoundscapePositions[i]);
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);
}


//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
//soundscape panel
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
#define SOUNDSCAPE_PANEL_WIDTH 760
enginesound->StopAllSounds(true);
#define SOUNDSCAPE_PANEL_HEIGHT 630


//stop the current soundscape and start a new soundscape
#define NEW_BUTTON_COMMAND "$NewSoundscape"
g_SoundscapeSystem.StartNewSoundscape(nullptr);
#define SAVE_BUTTON_COMMAND "$SaveSoundscape"
g_SoundscapeSystem.StartNewSoundscape(m_kvCurrSelected);
#define LOAD_BUTTON_COMMAND "$LoadSoundscape"
#define OPTIONS_BUTTON_COMMAND "$ShowOptions"
#define EDIT_BUTTON_COMMAND "$Edit"
#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"


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


//-----------------------------------------------------------------------------
//soundscape maker panel
// Purpose: Called when a button or something else gets pressed
class CSoundscapeMaker : public vgui::Frame, CAutoGameSystem
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnCommand(const char* pszCommand)
{
{
public:
DECLARE_CLASS_SIMPLE(CSoundscapeMaker, vgui::Frame)


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


//check for the save button command
//tick functions
else if (!Q_strcmp(pszCommand, SAVE_BUTTON_COMMAND))
void OnTick();
{
//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
//other functions
m_FileSave = new vgui::FileOpenDialog(this, "Save Soundscape File", false);
void OnClose();
m_FileSave->AddFilter("*.txt", "Soundscape Text File", true);
void OnCommand(const char* pszCommand);
m_FileSave->AddFilter("*.*", "All Files (*.*)", false);
m_FileSave->SetStartDirectory(buf);
m_FileSave->AddActionSignalTarget(this);
}


//show the dialog
void PlaySelectedSoundscape();
m_FileSave->DoModal(false);
void LoadFile(KeyValues* file);
m_FileSave->Activate();


//file wasnt loadad
void OnKeyCodePressed(vgui::KeyCode code);
m_bWasFileLoad = false;


return;
void SetSoundText(const char* text);
}


//check for load button command
//to play the soundscape on map spawn
else if (!Q_strcmp(pszCommand, LOAD_BUTTON_COMMAND))
void LevelInitPostEntity();
{
//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
//sets the keyvalue file
m_FileLoad = new vgui::FileOpenDialog(this, "Load Soundscape File", true);
void Set(const char* buffer);
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
//message pointer funcs
m_FileLoad->DoModal(false);
MESSAGE_FUNC_CHARPTR(OnFileSelected, "FileSelected", fullpath);
m_FileLoad->Activate();
MESSAGE_FUNC_PARAMS(OnTextChanged, "TextChanged", data);


//file was loadad
~CSoundscapeMaker();
m_bWasFileLoad = true;


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


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


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


return;
//buttons
}
vgui::Button* m_ButtonNew = nullptr;
vgui::Button* m_ButtonSave = nullptr;
vgui::Button* m_ButtonLoad = nullptr;
vgui::Button* m_ButtonOptions = nullptr;
vgui::Button* m_EditButton = nullptr;


//check for reset soundscape
//file load and save dialogs
else if (!Q_strcmp(pszCommand, RESET_BUTTON_COMMAND))
vgui::FileOpenDialog* m_FileSave = nullptr;
{
vgui::FileOpenDialog* m_FileLoad = nullptr;
m_kvCurrSelected = nullptr;
bool m_bWasFileLoad = false;


//stop all soundscapes before deleting the old soundscapes
//text entry for name
if (g_IsPlayingSoundscape)
vgui::TextEntry* m_TextEntryName;
PlaySelectedSoundscape();


m_KeyValues->deleteThis();
//combo box for dsp effects
m_KeyValues = new KeyValues("Empty Soundscape");
vgui::ComboBox* m_DspEffects;
vgui::ComboBox* m_SoundLevels;


LoadFile(m_KeyValues);
//sound data text entry
return;
vgui::TextEntry* m_TimeTextEntry;
}
vgui::TextEntry* m_VolumeTextEntry;
vgui::TextEntry* m_PitchTextEntry;
vgui::TextEntry* m_PositionTextEntry;
vgui::TextEntry* m_SoundNameTextEntry;


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


//set the sound list panel's combo box text and selected item
//play/reset soundscape buttons
vgui::CheckButton* m_PlaySoundscapeButton;
//get sound text entry name
vgui::Button* m_ResetSoundscapeButton;
char buf[512];
vgui::Button* m_DeleteCurrentButton;
m_SoundNameTextEntry->GetText(buf, sizeof(buf));


//look for item with same name
//current selected soundscape
for (int i = 0; i < g_SoundDirectories.Count(); i++)
CSoundscapeButton* m_pCurrentSelected = nullptr;
{
KeyValues* m_kvCurrSelected = nullptr;
if (!Q_strcmp(buf, g_SoundDirectories[i]))
KeyValues* m_kvCurrSound = nullptr;
{
KeyValues* m_kvCurrRndwave = nullptr;
//select item
g_SoundPanel->m_SoundsList->ActivateItem(i);
g_SoundPanel->m_SoundsList->SetText(buf);


break;
int m_iCurrRndWave = 0;
}
}


g_SoundPanel->SetVisible(true);
//currently in non randomwave thing
g_SoundPanel->MoveToFront();
SoundscapeMode m_iSoundscapeMode = SoundscapeMode::Mode_Random;
g_SoundPanel->RequestFocus();
 
return;
//temporary added soundscapes
}
CUtlVector<KeyValues*> m_TmpAddedSoundscapes;
};
 
//user message hook
void _SoundscapeMaker_Recieve(bf_read& bf);


//check for play soundscape
//-----------------------------------------------------------------------------
else if (!Q_strcmp(pszCommand, PLAY_SOUNDSCAPE_COMMAND))
// Purpose: Constructor for soundscape maker panel
//-----------------------------------------------------------------------------
CSoundscapeMaker::CSoundscapeMaker(vgui::VPANEL parent)
: BaseClass(nullptr, "SoundscapeMaker")
{
static bool bRegistered = false;
if (!bRegistered)
{
{
if (m_PlaySoundscapeButton->IsSelected())
usermessages->HookMessage("SoundscapeMaker_Recieve", _SoundscapeMaker_Recieve);
{
bRegistered = true;
//enable the reset soundscape button
}
m_ResetSoundscapeButton->SetEnabled(true);


//play the soundscape
//set variables
PlaySelectedSoundscape();
m_pCurrentSelected = nullptr;
}
else
{
//disable the reset soundscape button
m_ResetSoundscapeButton->SetEnabled(false);


g_IsPlayingSoundscape = false;
SetParent(parent);
 
//stop all sounds and soundscapes
SetKeyBoardInputEnabled(true);
enginesound->StopAllSounds(true);
SetMouseInputEnabled(true);
g_SoundscapeSystem.StartNewSoundscape(nullptr);
}


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


//check for play soundscape
SetTitle("Soundscape Maker (New File)", true);
else if (!Q_strcmp(pszCommand, RESET_SOUNDSCAPE_BUTTON_COMMAND))
SetSize(SOUNDSCAPE_PANEL_WIDTH, SOUNDSCAPE_PANEL_HEIGHT);
{
SetPos((ScreenWide - SOUNDSCAPE_PANEL_WIDTH) / 2, (ScreenTall - SOUNDSCAPE_PANEL_HEIGHT) / 2);
PlaySelectedSoundscape();
return;
}


//check for delete item
SetScheme(vgui::scheme()->LoadSchemeFromFile("resource/SourceScheme.res", "SourceScheme"));
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
//add a tick signal for every 50 ms
int curr = 0;
vgui::ivgui()->AddTickSignal(GetVPanel(), 50);
KeyValues* prev = nullptr;


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


curr = curr - 1;
//-----------------------------------------------------------------------------
 
// Purpose: Creates everything for this panel
keyvalues->SetNextKey(nullptr);
//-----------------------------------------------------------------------------
keyvalues->deleteThis();
void CSoundscapeMaker::CreateEverything()
break;
{
}
//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(7, 600, 145, 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(157, 600, 145, 25);
m_ButtonSave->SetCommand(SAVE_BUTTON_COMMAND);
m_ButtonSave->SetDepressedSound("ui/buttonclickrelease.wav");


prev = keyvalues;
m_ButtonLoad = new vgui::Button(this, "LoadButton", "Load Soundscapes");
}
m_ButtonLoad->SetVisible(true);
m_ButtonLoad->SetBounds(307, 600, 145, 25);
m_ButtonLoad->SetCommand(LOAD_BUTTON_COMMAND);
m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");
m_ButtonOptions = new vgui::Button(this, "OptionsButton", "Show Options Panel");
m_ButtonOptions->SetVisible(true);
m_ButtonOptions->SetBounds(457, 600, 145, 25);
m_ButtonOptions->SetCommand(OPTIONS_BUTTON_COMMAND);
m_ButtonOptions->SetDepressedSound("ui/buttonclickrelease.wav");
m_EditButton = new vgui::Button(this, "EditButton", "Show Text Editor");
m_EditButton->SetVisible(true);
m_EditButton->SetBounds(607, 600, 145, 25);
m_EditButton->SetCommand(EDIT_BUTTON_COMMAND);
m_EditButton->SetDepressedSound("ui/buttonclickrelease.wav");


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


//store vector
//create data list
auto& vec = m_pSoundList->m_MenuButtons;
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);


//remove it
//name text entry
delete vec[curr];
m_TextEntryName = new vgui::TextEntry(this, "NameTextEntry");
vec.Remove(curr);
m_TextEntryName->SetEnabled(false);
m_TextEntryName->SetBounds(325, 40, 295, 20);
m_TextEntryName->SetMaximumCharCount(50);


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


if (vec.Count() >= m_pSoundList->m_iMax)
for (int i = 0; i < sizeof(g_DspEffects) / sizeof(g_DspEffects[i]); i++)
{
m_DspEffects->AddItem(g_DspEffects[i], nullptr);
m_pSoundList->OnMouseWheeled(1);


int min, max;
//time text entry
m_pSoundList->m_pSideSlider->GetRange(min, max);
m_TimeTextEntry = new vgui::TextEntry(this, "TimeTextEntry");
m_pSoundList->m_pSideSlider->SetRange(0, max - 1);
m_TimeTextEntry->SetBounds(325, 90, 295, 20);
}
m_TimeTextEntry->SetEnabled(false);
m_TimeTextEntry->SetVisible(true);


for (int i = curr; i < vec.Count(); i++)
//volume text entry
{
m_VolumeTextEntry = new vgui::TextEntry(this, "VolumeTextEntry");
//move everything down
m_VolumeTextEntry->SetBounds(325, 115, 295, 20);
int x, y = 0;
m_VolumeTextEntry->SetEnabled(false);
vec[i]->GetPos(x, y);
m_VolumeTextEntry->SetVisible(true);
vec[i]->SetPos(x, y - 22);
}


//reset every command
//pitch text entry
int WaveAmount = 0;
m_PitchTextEntry = new vgui::TextEntry(this, "PitchTextEntry");
for (int i = 0; i < vec.Count(); i++)
m_PitchTextEntry->SetBounds(325, 140, 295, 20);
{
m_PitchTextEntry->SetEnabled(false);
//store data name
m_PitchTextEntry->SetVisible(true);
const char* name = vec[i]->GetCommand()->GetString("command");
//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);


//increment variables based on name
for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
if (Q_stristr(name, "$rndwave") == name)
m_SoundLevels->AddItem(g_SoundLevels[i], nullptr);
{
WaveAmount++;
//sound name
vec[i]->SetCommand(CFmtStr("$rndwave%d", WaveAmount));
m_SoundNameTextEntry = new vgui::TextEntry(this, "SoundName");
}
m_SoundNameTextEntry->SetBounds(325, 215, 215, 20);
}
m_SoundNameTextEntry->SetEnabled(false);
m_SoundNameTextEntry->SetVisible(true);


//bounds check
//play sound button
if (vec.Count() <= 0)
m_SoundNamePlay = new vgui::Button(this, "SoundPlayButton", "Sounds List");
{
m_SoundNamePlay->SetBounds(545, 215, 75, 20);
m_kvCurrRndwave = nullptr;
m_SoundNamePlay->SetCommand(SOUNDS_LIST_BUTTON_COMMAND);
m_pSoundList->m_Keyvalues = nullptr;
m_SoundNamePlay->SetEnabled(false);


//restart soundscape
//starts the soundscape
PlaySelectedSoundscape();
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);


return;
//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);


//select next item
//create the soundscape name text
if (m_iCurrRndWave <= vec.Count())
vgui::Label* NameLabel = new vgui::Label(this, "NameLabel", "Soundscape Name");
OnCommand(CFmtStr("$rndwave%d", curr + 1));
NameLabel->SetBounds(635, 40, 125, 20);
else
OnCommand(CFmtStr("$rndwave%d", curr));
}
else if (m_kvCurrSound)
{
//find keyvalue with same pointer and get the index
int tmpindex = 0;
int index = -1;


KeyValues* prev = nullptr;
//create the soundscape dsp text
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, keyvalues)
vgui::Label* DspLabel = new vgui::Label(this, "DspLabel", "Soundscape Dsp");
{
DspLabel->SetBounds(635, 65, 125, 20);
if (m_kvCurrSound == keyvalues)
{
//create the soundscape time text
//remove it
vgui::Label* TimeLabel = new vgui::Label(this, "TimeLabel", "Sound Time");
if (prev)
TimeLabel->SetBounds(635, 90, 125, 20);
prev->SetNextKey(keyvalues->GetNextTrueSubKey());
else
//create the soundscape volumn text
m_kvCurrSelected->m_pSub = keyvalues->GetNextTrueSubKey();
vgui::Label* VolumeLabel = new vgui::Label(this, "VolumeLabel", "Sound Volume");
VolumeLabel->SetBounds(635, 115, 125, 20);


keyvalues->SetNextKey(nullptr);
//create the soundscape pitch text
keyvalues->deleteThis();
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);


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


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


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


//error
LoadFile(m_KeyValues);
if (index == -1)
}
return;


//store vector
//-----------------------------------------------------------------------------
auto& vec = m_pDataList->m_MenuButtons;
// 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);


//remove it
//set the old visibility
delete vec[index];
bPrevVisible = g_ShowSoundscapePanel;
vec.Remove(index);
}


//move everything down
//-----------------------------------------------------------------------------
m_pDataList->m_iCurrentY = m_pDataList->m_iCurrentY - 22;
// Purpose: Called when the close button is pressed
m_pDataList->m_Keyvalues = m_kvCurrSelected;
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnClose()
{
//hide the other panels
g_SoundPanel->OnClose();
g_SettingsPanel->OnClose();
g_SoundscapeTextPanel->OnClose();


for (int i = index; i < vec.Count(); i++)
g_ShowSoundscapePanel = false;
{
}
//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)
//-----------------------------------------------------------------------------
// Purpose: Play the selected soundscape
//-----------------------------------------------------------------------------
void CSoundscapeMaker::PlaySelectedSoundscape()
{
g_IsPlayingSoundscape = true;
g_bSSMHack = true;
 
//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])
{
{
m_pDataList->OnMouseWheeled(1);
g_SoundscapeSystem.m_soundscapes.Remove(j);
break;
}
}
}


int min, max;
m_TmpAddedSoundscapes.RemoveAll();
m_pDataList->m_pSideSlider->GetRange(min, max);
if (max > 0)
m_pDataList->m_pSideSlider->SetRange(0, max - 1);
else
m_pDataList->m_pSideSlider->SetRange(0, 0);
}


//reset the names of each button
int RandomNum = 0;
//change audio params position
int LoopingNum = 0;
g_SoundscapeSystem.m_params.localBits = 0x7f;
int SoundscapeNum = 0;
for (int i = 0; i < MAX_SOUNDSCAPES - 1; i++)
g_SoundscapeSystem.m_params.localSound.Set(i, g_SoundscapePositions[i]);


//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 m_kvCurrSelected then add all the "playsoundscape" soundscape keyvalues
if (Q_stristr(name, "$playrandom") == name)
//into the g_SoundscapeSystem.m_soundscapes array
{
if (m_kvCurrSelected)
RandomNum++;
{
vec[i]->SetCommand(CFmtStr("$playrandom%d", RandomNum));
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;


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


if (Q_stristr(name, "$playsoundscape") == 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]))
{
{
SoundscapeNum++;
//add it to the soundscape system
vec[i]->SetCommand(CFmtStr("$playsoundscape%d", SoundscapeNum));
m_TmpAddedSoundscapes.AddToTail(subkey);
g_SoundscapeSystem.m_soundscapes.AddToTail(subkey);
}
}
}
}
}
}


//reset everything
//stop all sounds
m_SoundLevels->SetText("");
enginesound->StopAllSounds(true);
m_SoundNameTextEntry->SetText("");
m_TimeTextEntry->SetText("");
m_PitchTextEntry->SetText("");
m_PositionTextEntry->SetText("");
m_VolumeTextEntry->SetText("");


m_SoundLevels->SetEnabled(false);
//stop the current soundscape and start a new soundscape
m_SoundNameTextEntry->SetEnabled(false);
g_SoundscapeSystem.StartNewSoundscape(nullptr);
m_TimeTextEntry->SetEnabled(false);
g_SoundscapeSystem.StartNewSoundscape(m_kvCurrSelected);
m_PitchTextEntry->SetEnabled(false);
m_PositionTextEntry->SetEnabled(false);
m_VolumeTextEntry->SetEnabled(false);
m_SoundNamePlay->SetEnabled(false);


m_pSoundList->Clear();
g_bSSMHack = false;
}


m_kvCurrSound = nullptr;
//-----------------------------------------------------------------------------
m_pSoundList->m_Keyvalues = nullptr;
// Purpose: Called when a button or something else gets pressed
//-----------------------------------------------------------------------------
void CSoundscapeMaker::OnCommand(const char* pszCommand)
{


//bounds checking
//check for close command first
if (index >= vec.Count())
if (!Q_strcmp(pszCommand, "Close"))
index = vec.Count() - 1; // fix bounds more safely
{
BaseClass::OnCommand(pszCommand);
return;
}


//select the button
//check for the save button command
if (index >= 0)
else if (!Q_strcmp(pszCommand, SAVE_BUTTON_COMMAND))
OnCommand(vec[index]->GetCommand()->GetString("command"));
{
}
//initalize the file save dialog
else if (m_kvCurrSelected)
if (!m_FileSave)
{
{
if (m_KeyValues == m_kvCurrSelected)
//get the current game directory
{
char buf[512];
//play an error sound
filesystem->RelativePathToFullPath("scripts", "MOD", buf, sizeof(buf));
vgui::surface()->PlaySound("resource/warning.wav");


//show an error
//create the save dialog
vgui::QueryBox* popup = new vgui::QueryBox("Error", "Can not delete base soundscape!", this);
m_FileSave = new vgui::FileOpenDialog(this, "Save Soundscape File", false);
popup->SetOKButtonText("Ok");
m_FileSave->AddFilter("*.txt", "Soundscape Text File", true);
popup->SetCancelButtonVisible(false);
m_FileSave->AddFilter("*.*", "All Files (*.*)", false);
popup->AddActionSignalTarget(this);
m_FileSave->SetStartDirectory(buf);
popup->DoModal(this);
m_FileSave->AddActionSignalTarget(this);
}


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


//find keyvalue with same pointer and get the index
//file wasnt loadad
int tmpindex = 0;
m_bWasFileLoad = false;
int index = -1;


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


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


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


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


//increment
//file was loadad
tmpindex++;
m_bWasFileLoad = true;
}


//error
return;
if (index == -1)
}
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 edit panel button
else if (!Q_strcmp(pszCommand, EDIT_BUTTON_COMMAND))
{
g_SoundscapeTextPanel->SetVisible(true);
g_SoundscapeTextPanel->MoveToFront();
g_SoundscapeTextPanel->RequestFocus();
g_SoundscapeTextPanel->Set(m_KeyValues);
return;
}


//store vector
//check for new soundscape
auto& vec = m_SoundscapesList->m_MenuButtons;
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);


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


//move everything down
//check for reset soundscape
m_SoundscapesList->m_iCurrentY = m_SoundscapesList->m_iCurrentY - 22;
else if (!Q_strcmp(pszCommand, RESET_BUTTON_COMMAND))
{
m_kvCurrSelected = nullptr;


for (int i = index; i < vec.Count(); i++)
//stop all soundscapes before deleting the old soundscapes
{
if (g_IsPlayingSoundscape)
//move everything down
PlaySelectedSoundscape();
int x, y = 0;
vec[i]->GetPos(x, y);
vec[i]->SetPos(x, y - 22);
}


if (vec.Count() >= m_SoundscapesList->m_iMax)
m_KeyValues->deleteThis();
{
m_KeyValues = new KeyValues("Empty Soundscape");
m_SoundscapesList->OnMouseWheeled(1);


int min, max;
//reset title
m_SoundscapesList->m_pSideSlider->GetRange(min, max);
SetTitle("Soundscape Maker (New File)", true);
m_SoundscapesList->m_pSideSlider->SetRange(0, max - 1);
}


//reset everything
LoadFile(m_KeyValues);
m_DspEffects->SetText("");
return;
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();
//check for play sound
m_pSoundList->Clear();
else if (!Q_strcmp(pszCommand, SOUNDS_LIST_BUTTON_COMMAND))
{
//initalize the sounds
if (!g_SoundPanelInitalized)
{
g_SoundPanelInitalized = true;
g_SoundPanel->InitalizeSounds();
}


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


//go to next soundscape
//look for item with same name
if (!prev)
for (int i = 0; i < g_SoundDirectories.Count(); i++)
{
if (!Q_strcmp(buf, g_SoundDirectories[i]))
{
{
//restart soundscape
//select item
PlaySelectedSoundscape();
g_SoundPanel->m_SoundsList->ActivateItem(i);
return;
g_SoundPanel->m_SoundsList->SetText(buf);
 
break;
}
}
if (prev->GetNextTrueSubKey())
OnCommand(prev->GetNextTrueSubKey()->GetName());
else
OnCommand(prev->GetName());
}
}


//restart soundscape
g_SoundPanel->SetVisible(true);
PlaySelectedSoundscape();
g_SoundPanel->MoveToFront();
g_SoundPanel->RequestFocus();
return;
return;
}
}


//check for "playrandom", "playsoundscape" or "playlooping"
//check for play soundscape
if (Q_stristr(pszCommand, "$playrandom") == pszCommand)
else if (!Q_strcmp(pszCommand, PLAY_SOUNDSCAPE_COMMAND))
{
{
//get the selected number
if (m_PlaySoundscapeButton->IsSelected())
char* str_number = (char*)(pszCommand + 11);
{
int number = atoi(str_number);
//enable the reset soundscape button
if (number != 0)
m_ResetSoundscapeButton->SetEnabled(true);
 
//play the soundscape
PlaySelectedSoundscape();
}
else
{
{
//look for button with same command
//disable the reset soundscape button
auto& vec = m_pDataList->m_MenuButtons;
m_ResetSoundscapeButton->SetEnabled(false);
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;
}


g_IsPlayingSoundscape = false;


//clear the m_pSoundList
//stop all sounds and soundscapes
m_pSoundList->Clear();
enginesound->StopAllSounds(true);
m_pSoundList->m_Keyvalues = nullptr;
g_SoundscapeSystem.StartNewSoundscape(nullptr);
}


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


//get subkey
//check for play soundscape
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, sounds)
else if (!Q_strcmp(pszCommand, RESET_SOUNDSCAPE_BUTTON_COMMAND))
{
{
if (Q_strcasecmp(sounds->GetName(), "playrandom"))
PlaySelectedSoundscape();
continue;
return;
}
if (++curr == number)
{
data = sounds;
break;
}
}


//no data
//check for delete item
if (!data)
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;
return;


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


//set the random times
FOR_EACH_VALUE(m_kvCurrRndwave, keyvalues)
m_TimeTextEntry->SetText(data->GetString("time", "10,20"));
{
m_VolumeTextEntry->SetText(data->GetString("volume", "0.5,0.8"));
if (++curr == m_iCurrRndWave)
m_PitchTextEntry->SetText(data->GetString("pitch", "100"));
{
m_PositionTextEntry->SetText(data->GetString("position", ""));
//delete
m_SoundNameTextEntry->SetText("");
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;
}


//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
prev = keyvalues;
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
//reset everything
m_SoundLevels->ActivateItem(index);
m_SoundNameTextEntry->SetText("");
m_SoundNameTextEntry->SetEnabled(false);
m_SoundNamePlay->SetEnabled(false);


//enable the text entries
//store vector
m_TimeTextEntry->SetEnabled(true);
auto& vec = m_pSoundList->m_MenuButtons;
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);
//remove it
g_SoundPanel->SetVisible(false);
delete vec[curr];
vec.Remove(curr);


//check for randomwave subkey
//move everything down
if ((data = data->FindKey("rndwave")) == nullptr)
m_pSoundList->m_iCurrentY = m_pSoundList->m_iCurrentY - 22;
return;
m_pSoundList->m_Keyvalues = m_kvCurrRndwave;


m_kvCurrRndwave = data;
if (vec.Count() >= m_pSoundList->m_iMax)
m_pSoundList->m_Keyvalues = data;
 
//add all the data
int i = 0;
FOR_EACH_VALUE(data, sound)
{
{
const char* name = sound->GetName();
m_pSoundList->OnMouseWheeled(1);


//get real text
int min, max;
const char* text = sound->GetString();
m_pSoundList->m_pSideSlider->GetRange(min, max);
m_pSoundList->m_pSideSlider->SetRange(0, max - 1);
}


//get last / or \ and make the string be that + 1
for (int i = curr; i < vec.Count(); i++)
char* fslash = Q_strrchr(text, '/');
{
char* bslash = Q_strrchr(text, '\\');
//move everything down
int x, y = 0;
vec[i]->GetPos(x, y);
vec[i]->SetPos(x, y - 22);
}


//no forward slash and no back slash
//reset every command
if (!fslash && !bslash)
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)
{
{
text = text;
WaveAmount++;
vec[i]->SetCommand(CFmtStr("$rndwave%d", WaveAmount));
}
}
else
}
{
 
if (fslash > bslash)
//bounds check
text = fslash + 1;
if (vec.Count() <= 0)
{
m_kvCurrRndwave = nullptr;
m_pSoundList->m_Keyvalues = nullptr;


else if (bslash > fslash)
//restart soundscape
text = bslash + 1;
PlaySelectedSoundscape();
}


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


m_iSoundscapeMode = SoundscapeMode::Mode_Random;
//select next item
return;
if (m_iCurrRndWave <= vec.Count())
OnCommand(CFmtStr("$rndwave%d", curr + 1));
else
OnCommand(CFmtStr("$rndwave%d", curr));
}
}
}
else if (m_kvCurrSound)
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
//find keyvalue with same pointer and get the index
auto& vec = m_pDataList->m_MenuButtons;
int tmpindex = 0;
for (int i = 0; i < vec.Count(); i++)
int index = -1;
 
KeyValues* prev = nullptr;
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, keyvalues)
{
{
//if the button doesnt have the same command then de-select it. else select it
if (m_kvCurrSound == keyvalues)
if (!Q_strcmp(vec[i]->GetCommand()->GetString("command"), pszCommand))
{
vec[i]->m_bIsSelected = true;
//remove it
else
if (prev)
vec[i]->m_bIsSelected = false;
prev->SetNextKey(keyvalues->GetNextTrueSubKey());
}
else
m_kvCurrSelected->m_pSub = keyvalues->GetNextTrueSubKey();
 
keyvalues->SetNextKey(nullptr);
keyvalues->deleteThis();


//get index
index = tmpindex;
break;
}


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


//store variables
//increment
KeyValues* data = nullptr;
tmpindex++;
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
//error
if (!data)
if (index == -1)
return;
return;


m_kvCurrSound = data;
//store vector
m_kvCurrRndwave = nullptr;
auto& vec = m_pDataList->m_MenuButtons;


//set the random times
//remove it
m_TimeTextEntry->SetText("");
delete vec[index];
m_VolumeTextEntry->SetText(data->GetString("volume", "1"));
vec.Remove(index);
m_PitchTextEntry->SetText(data->GetString("pitch", "100"));
m_PositionTextEntry->SetText(data->GetString("position", ""));
m_SoundNameTextEntry->SetText(data->GetString("wave", ""));


//get snd level index
//move everything down
int index = 8; //8 = SNDLVL_NORM
m_pDataList->m_iCurrentY = m_pDataList->m_iCurrentY - 22;
const char* name = data->GetString("soundlevel", nullptr);
m_pDataList->m_Keyvalues = m_kvCurrSelected;


//check for the name
for (int i = index; i < vec.Count(); i++)
if (name)
{
//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);


//loop through the sound levels to find the right one
int min, max;
for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
m_pDataList->m_pSideSlider->GetRange(min, max);
{
if (!Q_strcmp(name, g_SoundLevels[i]))
if (max > 0)
{
m_pDataList->m_pSideSlider->SetRange(0, max - 1);
index = i;
else
break;
m_pDataList->m_pSideSlider->SetRange(0, 0);
}
}
}
}


//select the index
//reset the names of each button
m_SoundLevels->ActivateItem(index);
int RandomNum = 0;
int LoopingNum = 0;
int SoundscapeNum = 0;


//enable the text entries
//change the commands of the buttons
m_TimeTextEntry->SetEnabled(false);
for (int i = 0; i < vec.Count(); i++)
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
//store data name
if (!Q_strcmp(vec[i]->GetCommand()->GetString("command"), pszCommand))
const char* name = vec[i]->GetCommand()->GetString("command");
vec[i]->m_bIsSelected = true;
else
vec[i]->m_bIsSelected = false;
}


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


//clear the m_pSoundList
if (Q_stristr(name, "$playlooping") == name)
m_pSoundList->Clear();
{
m_pSoundList->m_Keyvalues = nullptr;
LoopingNum++;
vec[i]->SetCommand(CFmtStr("$playlooping%d", LoopingNum));
}


//store variables
if (Q_stristr(name, "$playsoundscape") == name)
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;
SoundscapeNum++;
break;
vec[i]->SetCommand(CFmtStr("$playsoundscape%d", SoundscapeNum));
}
}
}
}


//no data
//reset everything
if (!data)
m_SoundLevels->SetText("");
return;
m_SoundNameTextEntry->SetText("");
 
m_kvCurrSound = data;
m_kvCurrRndwave = nullptr;
 
//set the random times
m_TimeTextEntry->SetText("");
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("");
m_PitchTextEntry->SetText("");
m_PositionTextEntry->SetText("");
m_VolumeTextEntry->SetText("");


//get snd level index
m_SoundLevels->SetEnabled(false);
int index = 8; //8 = SNDLVL_NORM
m_SoundNameTextEntry->SetEnabled(false);
const char* name = data->GetString("soundlevel", nullptr);
m_TimeTextEntry->SetEnabled(false);
m_PitchTextEntry->SetEnabled(false);
m_PositionTextEntry->SetEnabled(false);
m_VolumeTextEntry->SetEnabled(false);
m_SoundNamePlay->SetEnabled(false);


//check for the name
m_pSoundList->Clear();
if (name)
 
m_kvCurrSound = nullptr;
m_pSoundList->m_Keyvalues = nullptr;
 
//bounds checking
if (index >= vec.Count())
index = vec.Count() - 1; // fix bounds more safely
 
//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");


//loop through the sound levels to find the right one
//show an error
for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
vgui::QueryBox* popup = new vgui::QueryBox("Error", "Can not delete base soundscape!", this);
{
popup->SetOKButtonText("Ok");
if (!Q_strcmp(name, g_SoundLevels[i]))
popup->SetCancelButtonVisible(false);
{
popup->AddActionSignalTarget(this);
index = i;
popup->DoModal(this);
break;
 
}
return;
}
}
}


//select the index
//find keyvalue with same pointer and get the index
m_SoundLevels->ActivateItem(index);
int tmpindex = 0;
int index = -1;


//enable the text entries
KeyValues* prev = nullptr;
m_TimeTextEntry->SetEnabled(true);
for (KeyValues* keyvalues = m_KeyValues; keyvalues != nullptr; keyvalues = keyvalues->GetNextTrueSubKey())
m_VolumeTextEntry->SetEnabled(true);
{
m_PitchTextEntry->SetEnabled(false);
if (m_kvCurrSelected == keyvalues)
m_PositionTextEntry->SetEnabled(true);
{
m_SoundLevels->SetEnabled(true);
//remove it
m_SoundNameTextEntry->SetEnabled(true);
if (!prev)
m_TimeTextEntry->SetEnabled(false);
break;
m_SoundNamePlay->SetEnabled(false);
 
prev->SetNextKey(keyvalues->GetNextTrueSubKey());
keyvalues->SetNextKey(nullptr);
keyvalues->deleteThis();


g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
//get index
g_SoundPanel->SetVisible(false);
index = tmpindex;
break;
}


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


//get the selected number
//increment
char* str_number = (char*)(pszCommand + 8);
tmpindex++;
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;
}
}


//error
if (index == -1)
return;
//store vector
auto& vec = m_SoundscapesList->m_MenuButtons;


int i = 0;
//remove it
delete vec[index];
vec.Remove(index);
 
//move everything down
m_SoundscapesList->m_iCurrentY = m_SoundscapesList->m_iCurrentY - 22;


//get value
for (int i = index; i < vec.Count(); i++)
KeyValues* curr = nullptr;
FOR_EACH_VALUE(m_kvCurrRndwave, wave)
{
{
if (++i == m_iCurrRndWave)
//move everything down
{
int x, y = 0;
curr = wave;
vec[i]->GetPos(x, y);
break;
vec[i]->SetPos(x, y - 22);
}
}
}


//if no curr then throw an error
if (vec.Count() >= m_SoundscapesList->m_iMax)
if (!curr)
{
{
//play an error sound
m_SoundscapesList->OnMouseWheeled(1);
vgui::surface()->PlaySound("resource/warning.wav");


//show error
int min, max;
char buf[1028];
m_SoundscapesList->m_pSideSlider->GetRange(min, max);
Q_snprintf(buf, sizeof(buf), "Failed to get rndwave '%d' for subkey \"%s\"\nfor current soundscape file!", i, m_kvCurrSelected->GetName());
m_SoundscapesList->m_pSideSlider->SetRange(0, max - 1);
 
//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);
//reset everything
m_SoundNameTextEntry->SetText(curr->GetString());
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_SoundNamePlay->SetEnabled(true);
m_pDataList->Clear();
m_pSoundList->Clear();


m_iSoundscapeMode = SoundscapeMode::Mode_Random;
m_kvCurrSound = nullptr;
return;
m_pDataList->m_Keyvalues = nullptr;
}
}


//look for button with the same name as the command
//go to next soundscape
{
if (!prev)
//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
//restart soundscape
m_pCurrentSelected = array[i];
PlaySelectedSoundscape();
break;
return;
}
}
if (prev->GetNextTrueSubKey())
OnCommand(prev->GetNextTrueSubKey()->GetName());
else
OnCommand(prev->GetName());
}
}


//find selected keyvalue
//restart soundscape
PlaySelectedSoundscape();
return;
}


//set needed stuff
//check for "playrandom", "playsoundscape" or "playlooping"
if (m_pCurrentSelected)
if (Q_stristr(pszCommand, "$playrandom") == pszCommand)
{
//get the selected number
char* str_number = (char*)(pszCommand + 11);
int number = atoi(str_number);
if (number != 0)
{
{
//select button
//look for button with same command
m_pCurrentSelected->m_bIsSelected = true;
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;
}


m_DeleteCurrentButton->SetEnabled(false);


//reset the selected kv
//clear the m_pSoundList
m_kvCurrSelected = nullptr;
m_pSoundList->Clear();
m_pSoundList->m_Keyvalues = nullptr;


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


for (KeyValues* kv = m_KeyValues; kv != nullptr; kv = kv->GetNextTrueSubKey())
//get subkey
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, sounds)
{
{
if (!Q_strcmp(kv->GetName(), pszCommand))
if (Q_strcasecmp(sounds->GetName(), "playrandom"))
continue;
if (++curr == number)
{
{
m_kvCurrSelected = kv;
data = sounds;
break;
break;
}
}
}
}


//set
//no data
m_kvCurrSound = nullptr;
if (!data)
return;
 
m_kvCurrSound = data;
m_kvCurrRndwave = nullptr;
m_kvCurrRndwave = nullptr;


m_TimeTextEntry->SetEnabled(false);
//set the random times
m_TimeTextEntry->SetText("");
m_TimeTextEntry->SetText(data->GetString("time", "10,20"));
 
m_VolumeTextEntry->SetText(data->GetString("volume", "0.5,0.8"));
m_VolumeTextEntry->SetEnabled(false);
m_PitchTextEntry->SetText(data->GetString("pitch", "100"));
m_VolumeTextEntry->SetText("");
m_PositionTextEntry->SetText(data->GetString("position", ""));
 
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_SoundNameTextEntry->SetText("");


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


if (g_SoundPanel)
//check for the name
if (name)
{
{
g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
g_SoundPanel->SetVisible(false);
}


//check for current keyvalues. should never bee nullptr but could be
//loop through the sound levels to find the right one
if (!m_kvCurrSelected)
for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
{
{
//play an error sound
if (!Q_strcmp(name, g_SoundLevels[i]))
vgui::surface()->PlaySound("resource/warning.wav");
{
index = i;
break;
}
}
}


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


//show an error
//enable the text entries
vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
m_TimeTextEntry->SetEnabled(true);
popup->SetOKButtonText("Ok");
m_VolumeTextEntry->SetEnabled(true);
popup->SetCancelButtonVisible(false);
m_PitchTextEntry->SetEnabled(true);
popup->AddActionSignalTarget(this);
m_PositionTextEntry->SetEnabled(true);
popup->DoModal(this);
m_SoundLevels->SetEnabled(true);
m_SoundNameTextEntry->SetEnabled(false);
m_SoundNamePlay->SetEnabled(false);


//reset vars
g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
m_pCurrentSelected = nullptr;
g_SoundPanel->SetVisible(false);


m_TextEntryName->SetEnabled(false);
//check for randomwave subkey
m_TextEntryName->SetText("");
if ((data = data->FindKey("rndwave")) == nullptr)
 
m_DspEffects->SetEnabled(false);
m_DspEffects->SetText("");
return;
return;
}


if (g_IsPlayingSoundscape)
m_kvCurrRndwave = data;
PlaySelectedSoundscape();
m_pSoundList->m_Keyvalues = data;


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


//set current soundscape name
//get real text
m_TextEntryName->SetText(pszCommand);
const char* text = sound->GetString();
m_TextEntryName->SetEnabled(true);
m_pDataList->m_Keyvalues = m_kvCurrSelected;


//set dsp effect
//get last / or \ and make the string be that + 1
int dsp = Clamp<int>(m_kvCurrSelected->GetInt("dsp"), 0, 29);
char* fslash = Q_strrchr(text, '/');
char* bslash = Q_strrchr(text, '\\');


m_PlaySoundscapeButton->SetEnabled(true);
//no forward slash and no back slash
if (!fslash && !bslash)
{
text = text;
}
else
{
if (fslash > bslash)
text = fslash + 1;


m_DspEffects->SetEnabled(true);
else if (bslash > fslash)
m_DspEffects->ActivateItem(dsp);
text = bslash + 1;
}


//clear these
m_pSoundList->AddButton(name, text, CFmtStr("$rndwave%d", ++i), this);
m_pDataList->Clear();
}
m_pSoundList->Clear();
m_pSoundList->m_Keyvalues = nullptr;


//set variables
m_iSoundscapeMode = SoundscapeMode::Mode_Random;
int RandomNum = 0;
return;
int LoopingNum = 0;
}
int SoundscapeNum = 0;
}
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;


FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, data)
//get subkey
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, sounds)
{
{
//store data name
if (Q_strcasecmp(sounds->GetName(), "playlooping"))
const char* name = data->GetName();
continue;


//increment variables based on name
if (++curr == number)
if (!Q_strcasecmp(name, "playrandom"))
{
{
RandomNum++;
data = sounds;
m_pDataList->AddButton(data->GetName(), data->GetName(), CFmtStr("$playrandom%d", RandomNum), this);
break;
}
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);
//no data
}
if (!data)
return;


//-----------------------------------------------------------------------------
m_kvCurrSound = data;
// Purpose: Function to recursivly write keyvalues to keyvalue files. the keyvalues
m_kvCurrRndwave = nullptr;
// 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
//set the random times
buffer.PutChar('"');
m_TimeTextEntry->SetText("");
buffer.PutString(prev->GetName());
m_VolumeTextEntry->SetText(data->GetString("volume", "1"));
buffer.PutString("\"\n");
m_PitchTextEntry->SetText(data->GetString("pitch", "100"));
m_PositionTextEntry->SetText(data->GetString("position", ""));
m_SoundNameTextEntry->SetText(data->GetString("wave", ""));


//write {
//get snd level index
for (int i = 0; i < indent; i++)
int index = 8; //8 = SNDLVL_NORM
buffer.PutChar('\t');
const char* name = data->GetString("soundlevel", nullptr);


buffer.PutString("{\n");
//check for the name
if (name)
{


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


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


//write name and value
//enable the text entries
buffer.PutChar('"');
m_TimeTextEntry->SetEnabled(false);
buffer.PutString(value->GetName());
m_VolumeTextEntry->SetEnabled(true);
buffer.PutString("\"\t");
m_PitchTextEntry->SetEnabled(true);
m_PositionTextEntry->SetEnabled(true);
buffer.PutChar('"');
m_SoundLevels->SetEnabled(true);
buffer.PutString(value->GetString());
m_SoundNameTextEntry->SetEnabled(true);
buffer.PutString("\"\n");
m_SoundNamePlay->SetEnabled(true);
g_SoundPanel->SetVisible(false);
 
m_iSoundscapeMode = SoundscapeMode::Mode_Looping;
return;
}
}
}
else if (Q_stristr(pszCommand, "$playsoundscape") == pszCommand)
//write all the subkeys now
FOR_EACH_TRUE_SUBKEY(prev, value)
{
{
//increment indent
//get the selected number
RecursivlyWriteKeyvalues(value, buffer, indent);
char* str_number = (char*)(pszCommand + 15);
int number = atoi(str_number);
if (value->GetNextTrueSubKey())
if (number != 0)
buffer.PutChar('\n');
{
}
//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;
}


//decrement indent
indent--;


//write ending }
//clear the m_pSoundList
for (int i = 0; i < indent; i++)
m_pSoundList->Clear();
buffer.PutChar('\t');
m_pSoundList->m_Keyvalues = nullptr;
 
//store variables
KeyValues* data = nullptr;
int curr = 0;


buffer.PutString("}\n");
//get subkey
}
FOR_EACH_TRUE_SUBKEY(m_kvCurrSelected, sounds)
{
if (Q_strcasecmp(sounds->GetName(), "playsoundscape"))
continue;


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


//check for file save
//no data
if (!m_bWasFileLoad)
if (!data)
{
return;
//save the file
 
if (m_KeyValues)
m_kvCurrSound = data;
{
m_kvCurrRndwave = nullptr;
//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
//set the random times
KeyValues* pCurrent = m_KeyValues;
m_TimeTextEntry->SetText("");
while (pCurrent)
m_VolumeTextEntry->SetText(data->GetString("volume", "1"));
{
m_PositionTextEntry->SetText(data->GetString("positionoverride", ""));
int indent = 0;
m_SoundNameTextEntry->SetText(data->GetString("name", ""));
RecursivlyWriteKeyvalues(pCurrent, buf, indent);
m_PitchTextEntry->SetText("");
pCurrent = pCurrent->GetNextTrueSubKey();


//put a newline
//get snd level index
buf.PutChar('\n');
int index = 8; //8 = SNDLVL_NORM
}
const char* name = data->GetString("soundlevel", nullptr);


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


//get the error first
//loop through the sound levels to find the right one
char buf[1028];
for (int i = 0; i < sizeof(g_SoundLevels) / sizeof(g_SoundLevels[i]); i++)
Q_snprintf(buf, sizeof(buf), "Failed to save soundscape to file \"%s\"", pszFileName);
{
 
if (!Q_strcmp(name, g_SoundLevels[i]))
//show an error
{
vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
index = i;
popup->SetOKButtonText("Ok");
break;
popup->SetCancelButtonVisible(false);
}
popup->AddActionSignalTarget(this);
}
popup->DoModal(this);
return;
}
}
}


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


//store vars
//enable the text entries
const char* last = pszFileName;
m_TimeTextEntry->SetEnabled(true);
const char* tmp = nullptr;
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);


//get the last /
g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
while ((last = Q_strstr(last, "\\")) != nullptr)
g_SoundPanel->SetVisible(false);
tmp = ++last; //move past the backslash


//check tmp
m_iSoundscapeMode = SoundscapeMode::Mode_Soundscape;
if (!tmp || !*tmp)
return;
tmp = pszFileName;
}
 
}
//set new title
else if (Q_stristr(pszCommand, "$rndwave") == pszCommand)
char buf[1028];
{
Q_snprintf(buf, sizeof(buf), "Soundscape Maker (%s)", tmp);
if (!m_kvCurrRndwave)
return;


SetTitle(buf, true);
//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;
}


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


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


//append 'soundscapes_manifest.txt'
//get value
lastSlash[1] = '\0';
KeyValues* curr = nullptr;
strcat(manifest, "soundscapes_manifest.txt");
FOR_EACH_VALUE(m_kvCurrRndwave, wave)
 
{
//see if we can open manifest file
if (++i == m_iCurrRndWave)
KeyValues* man_file = new KeyValues("manifest");
{
if (!man_file->LoadFromFile(g_pFullFileSystem, manifest))
curr = wave;
{
break;
//cant open manifest file
}
man_file->deleteThis();
}
return;
}


//get real filename
//if no curr then throw an error
pszFileName = Q_strrchr(pszFileName, '\\');
if (!curr)
if (!pszFileName || !*pszFileName)
{
{
//play an error sound
man_file->deleteThis();
vgui::surface()->PlaySound("resource/warning.wav");
return;
}


pszFileName = pszFileName + 1;
//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());


//create name to be added to the manifest file
//show an error
char add_file[1028];
vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
Q_snprintf(add_file, sizeof(add_file), "scripts/%s", pszFileName);
popup->SetOKButtonText("Ok");
popup->SetCancelButtonVisible(false);
popup->AddActionSignalTarget(this);
popup->DoModal(this);
return;
}


//add filename to manifest file if not found
m_SoundNameTextEntry->SetEnabled(true);
FOR_EACH_VALUE(man_file, value)
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++)
{
{
if (!Q_strcmp(value->GetString(), add_file))
//check button name
if (!Q_strcmp(array[i]->GetCommand()->GetString("command"), pszCommand))
{
{
man_file->deleteThis();
//found it
return;
m_pCurrentSelected = array[i];
break;
}
}
}
}


//find selected keyvalue


//add to manifest file
//set needed stuff
KeyValues* kv = new KeyValues("file");
if (m_pCurrentSelected)
kv->SetString(nullptr, add_file);
{
man_file->AddSubKey(kv);
//select button
m_pCurrentSelected->m_bIsSelected = true;


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


man_file->deleteThis();
//reset the selected kv
return;
m_kvCurrSelected = nullptr;
}


//try and load the keyvalues file first
//find selected keyvalues
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
for (KeyValues* kv = m_KeyValues; kv != nullptr; kv = kv->GetNextTrueSubKey())
vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
{
popup->SetOKButtonText("Ok");
if (!Q_strcmp(kv->GetName(), pszCommand))
popup->SetCancelButtonVisible(false);
{
popup->AddActionSignalTarget(this);
m_kvCurrSelected = kv;
popup->DoModal(this);
break;
}
}


temp->deleteThis();
//set
return;
m_kvCurrSound = nullptr;
}
m_kvCurrRndwave = nullptr;


//set the new title
m_TimeTextEntry->SetEnabled(false);
{
m_TimeTextEntry->SetText("");
//store vars
const char* last = pszFileName;
const char* tmp = nullptr;


//get the last /
m_VolumeTextEntry->SetEnabled(false);
while ((last = Q_strstr(last, "\\")) != nullptr)
m_VolumeTextEntry->SetText("");
tmp = ++last; //move past the backslash


//check tmp
m_PitchTextEntry->SetEnabled(false);
if (!tmp || !*tmp)
m_PitchTextEntry->SetText("");
tmp = pszFileName;


//create the new new title
m_PositionTextEntry->SetEnabled(false);
char buf[1028];
m_PositionTextEntry->SetText("");
Q_snprintf(buf, sizeof(buf), "Soundscape Maker (%s)", tmp);
m_SoundLevels->SetEnabled(false);
m_SoundLevels->SetText("");


SetTitle(buf, true);
m_SoundNameTextEntry->SetEnabled(false);
}
m_SoundNameTextEntry->SetText("");


//stop all soundscapes before deleting the old soundscapes
m_SoundNamePlay->SetEnabled(false);
m_kvCurrSelected = nullptr;


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


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


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


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


//-----------------------------------------------------------------------------
//reset vars
// Purpose: Called when a text thing changes
m_pCurrentSelected = nullptr;
//-----------------------------------------------------------------------------
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
m_TextEntryName->SetEnabled(false);
if (m_TextEntryName->HasFocus())
m_TextEntryName->SetText("");
{
//get text
char buf[50];
m_TextEntryName->GetText(buf, sizeof(buf));


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


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


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


m_kvCurrSound->SetString("time", buf);
//set current soundscape name
return;
m_TextEntryName->SetText(pszCommand);
}
m_TextEntryName->SetEnabled(true);
else if (m_VolumeTextEntry->HasFocus())
m_pDataList->m_Keyvalues = m_kvCurrSelected;
{
//get text
char buf[38];
m_VolumeTextEntry->GetText(buf, sizeof(buf));


m_kvCurrSound->SetString("volume", buf);
//set dsp effect
return;
int dsp = Clamp<int>(m_kvCurrSelected->GetInt("dsp"), 0, 29);
}
else if (m_PitchTextEntry->HasFocus())
{
//dont add to soundscaep
if (m_iSoundscapeMode == SoundscapeMode::Mode_Soundscape)
return;


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


m_kvCurrSound->SetString("pitch", buf);
m_DspEffects->SetEnabled(true);
return;
m_DspEffects->ActivateItem(dsp);
}
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
//clear these
if (!buf[0])
m_pDataList->Clear();
{
m_pSoundList->Clear();
if (m_iSoundscapeMode == SoundscapeMode::Mode_Soundscape)
m_pSoundList->m_Keyvalues = nullptr;
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);


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


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


//get the sound level amount
//increment variables based on name
int sndlevel = Clamp<int>(m_SoundLevels->GetActiveItem(), 0, 20);
if (!Q_strcasecmp(name, "playrandom"))
m_kvCurrSound->SetString("soundlevel", g_SoundLevels[sndlevel]);
{
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);
}
}
}
}


//set soundscape name/wave
BaseClass::OnCommand(pszCommand);
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)
//-----------------------------------------------------------------------------
{
// Purpose: Function to recursivly write keyvalues to keyvalue files. the keyvalues
if (++i == m_iCurrRndWave)
// 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
wave->SetStringValue(buf);
// 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");


//set text on the sounds panel
//write {
vgui::Button* button = m_pSoundList->m_MenuButtons[i - 1];
for (int i = 0; i < indent; i++)
if (button)
buffer.PutChar('\t');
{
//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
buffer.PutString("{\n");
if (!fslash && !bslash)
{
button->SetText(buf);
return;
}


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


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


return;
//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: Loads the keyvalues
// Purpose: Called when a file gets opened/closed
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CSoundscapeMaker::LoadFile(KeyValues* file)
void CSoundscapeMaker::OnFileSelected(const char* pszFileName)
{
{
//clear all the text's
//check for null or empty string
m_TextEntryName->SetEnabled(false);
if (!pszFileName || pszFileName[0] == '\0')
m_TextEntryName->SetText("");
return;


m_DspEffects->SetEnabled(false);
//check for file save
m_DspEffects->SetText("");
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");


m_TimeTextEntry->SetEnabled(false);
//now write the keyvalues
m_TimeTextEntry->SetText("");
KeyValues* pCurrent = m_KeyValues;
while (pCurrent)
m_VolumeTextEntry->SetEnabled(false);
{
m_VolumeTextEntry->SetText("");
int indent = 0;
RecursivlyWriteKeyvalues(pCurrent, buf, indent);
m_PitchTextEntry->SetEnabled(false);
m_PitchTextEntry->SetText("");
//put a newline
if (pCurrent->GetNextTrueSubKey())
m_PositionTextEntry->SetEnabled(false);
buf.PutChar('\n');
m_PositionTextEntry->SetText("");
m_SoundNameTextEntry->SetEnabled(false);
m_SoundNameTextEntry->SetText("");


m_SoundNamePlay->SetEnabled(false);
//get next
pCurrent = pCurrent->GetNextTrueSubKey();
if (g_SoundPanel)
}  
{
g_SoundPanel->OnCommand(SOUND_LIST_STOP_COMMAND);
g_SoundPanel->SetVisible(false);
}


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


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


//clear current file
//show an error
m_pCurrentSelected = nullptr;
vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
m_kvCurrSelected = nullptr;
popup->SetOKButtonText("Ok");
m_kvCurrSound = nullptr;
popup->SetCancelButtonVisible(false);
m_kvCurrRndwave = nullptr;
popup->AddActionSignalTarget(this);
popup->DoModal(this);
return;
}
}


//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;
//store vars
const char* last = pszFileName;
const char* tmp = nullptr;


//temp soundscapes list
//get the last /
CUtlVector<const char*> Added;
while ((last = Q_strstr(last, "\\")) != nullptr)
tmp = ++last; //move past the backslash


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


//check for the soundscape first
//set new title
if (Added.Find(name) != Added.InvalidIndex())
char buf[1028];
{
Q_snprintf(buf, sizeof(buf), "Soundscape Maker (%s)", tmp);
ConWarning("CSoundscapePanel: Failed to add repeated soundscape '%s'\n", name);
continue;
}


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


//
//create copy of pszFileName
OnCommand(file->GetName());
char manifest[1028];
}
Q_strncpy(manifest, pszFileName, sizeof(manifest));


//-----------------------------------------------------------------------------
//get last /
// Purpose: Sets the sounds text
char* lastSlash = Q_strrchr(manifest, '\\');
//-----------------------------------------------------------------------------
if (lastSlash == nullptr || *lastSlash == '\0')  
void CSoundscapeMaker::SetSoundText(const char* text)
return;
{
m_SoundNameTextEntry->SetText(text);


//set soundscape name/wave
//append 'soundscapes_manifest.txt'
if (m_iSoundscapeMode != SoundscapeMode::Mode_Random)
lastSlash[1] = '\0';
{
strcat(manifest, "soundscapes_manifest.txt");
m_kvCurrSound->SetString("wave", text);
}
else
{
//get value
int i = 0;


FOR_EACH_VALUE(m_kvCurrRndwave, wave)
//see if we can open manifest file
KeyValues* man_file = new KeyValues("manifest");
if (!man_file->LoadFromFile(g_pFullFileSystem, manifest))
{
{
if (++i == m_iCurrRndWave)
//cant open manifest file
{
man_file->deleteThis();
wave->SetStringValue(text);
return;
}


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


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


if (fslash > bslash)
//create name to be added to the manifest file
{
char add_file[1028];
button->SetText(fslash + 1);
Q_snprintf(add_file, sizeof(add_file), "scripts/%s", pszFileName);
return;
}


else if (bslash > fslash)
//add filename to manifest file if not found
{
FOR_EACH_VALUE(man_file, value)
button->SetText(bslash + 1);
{
return;
if (!Q_strcmp(value->GetString(), add_file))
}
{
}
man_file->deleteThis();
 
return;
break;
}
}
}
}
}


return;
}


//-----------------------------------------------------------------------------
//add to manifest file
// Purpose: Called when a keyboard key is pressed
KeyValues* kv = new KeyValues("file");
//-----------------------------------------------------------------------------
kv->SetString(nullptr, add_file);
void CSoundscapeMaker::OnKeyCodePressed(vgui::KeyCode code)
man_file->AddSubKey(kv);
{
//check for ctrl o or ctrl s
if (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LCONTROL) ||
vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RCONTROL))
{
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);
else if (code == vgui::KeyCode::KEY_P)
{
//show settings
g_SettingsPanel->SetVisible(true);
g_SettingsPanel->RequestFocus();
g_SettingsPanel->MoveToFront();
}
else if (code == vgui::KeyCode::KEY_D)
OnCommand(DELETE_CURRENT_ITEM_COMMAND);


//check for ctrl+alt+a
//write to file
else if (code == vgui::KeyCode::KEY_A && (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LALT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RALT)) && m_pSoundList && m_pSoundList->m_Keyvalues)
man_file->SaveToFile(g_pFullFileSystem, manifest);
m_pSoundList->OnCommand(NEW_RNDWAVE_WAVE_COMMAND);
 
//check for just ctrl+shift+a
else if (code == vgui::KeyCode::KEY_A && (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LSHIFT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RSHIFT)) && m_SoundscapesList)
m_SoundscapesList->OnCommand(ADD_SOUNDSCAPE_COMMAND);


man_file->deleteThis();
return;
return;
}
}


//get key bound to this
//try and load the keyvalues file first
const char* key = engine->Key_LookupBinding("modbase_soundscape_panel");
KeyValues* temp = new KeyValues("SoundscapeFile");
if (!key)
if (!temp->LoadFromFile(filesystem, pszFileName))
return;
{
//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);


//convert the key to a keyboard code
//show an error
const char* keystring = KeyCodeToString(code);
vgui::QueryBox* popup = new vgui::QueryBox("Error", buf, this);
popup->SetOKButtonText("Ok");
//remove the KEY_ if found
popup->SetCancelButtonVisible(false);
if (Q_strstr(keystring, "KEY_") == keystring)
popup->AddActionSignalTarget(this);
keystring = keystring + 4;
popup->DoModal(this);


//check both strings
temp->deleteThis();
if (!Q_strcasecmp(key, keystring))
return;
OnClose();
}
}
 
//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;


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


//-----------------------------------------------------------------------------
//delete and set the old keyvalues
// Purpose: Destructor for soundscape maker panel
//-----------------------------------------------------------------------------
CSoundscapeMaker::~CSoundscapeMaker()
{
//delete the keyvalue files if needed
if (m_KeyValues)
if (m_KeyValues)
m_KeyValues->deleteThis();
m_KeyValues->deleteThis();
m_KeyValues = temp;
//load the file
LoadFile(m_KeyValues);
}
}


//static panel instance
//-----------------------------------------------------------------------------
static CSoundscapeMaker* g_SSMakerPanel = nullptr;
// 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;


//interface class
//set the curr sound and stuff
class CSoundscapeMakerInterface : public ISoundscapeMaker
if (m_TimeTextEntry->HasFocus())
{
{
public:
//get text
void Create(vgui::VPANEL parent)
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) ||
vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RCONTROL))
{
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);
else if (code == vgui::KeyCode::KEY_P)
{
//show settings
g_SettingsPanel->SetVisible(true);
g_SettingsPanel->RequestFocus();
g_SettingsPanel->MoveToFront();
}
else if (code == vgui::KeyCode::KEY_D)
OnCommand(DELETE_CURRENT_ITEM_COMMAND);
 
//check for ctrl+alt+a
else if (code == vgui::KeyCode::KEY_A && (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LALT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RALT)) && m_pSoundList && m_pSoundList->m_Keyvalues)
m_pSoundList->OnCommand(NEW_RNDWAVE_WAVE_COMMAND);
 
//check for just ctrl+shift+a
else if (code == vgui::KeyCode::KEY_A && (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LSHIFT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RSHIFT)) && m_SoundscapesList)
m_SoundscapesList->OnCommand(ADD_SOUNDSCAPE_COMMAND);
 
return;
}
 
//check for arrow keys
if (code == KEY_DOWN || code == KEY_UP)
{
if (m_kvCurrRndwave)
{
m_pSoundList->OnKeyCodePressed(code);
}
else if (m_kvCurrSelected && m_pDataList->m_MenuButtons.Count())
{
m_pDataList->OnKeyCodePressed(code);
}
else
{
m_SoundscapesList->OnKeyCodePressed(code);
}
 
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: Sets keyvalues from text
//-----------------------------------------------------------------------------
void CSoundscapeMaker::Set(const char* buffer)
{
CUtlBuffer buf(0, 0, CUtlBuffer::TEXT_BUFFER);
buf.PutString(buffer);
 
//try and load the keyvalues file first
KeyValues* temp = new KeyValues("SoundscapeFile");
if (!temp->LoadFromBuffer("Text Editor Panel Buffer", buf))
{
//play an error sound
vgui::surface()->PlaySound("resource/warning.wav");
 
//show an error
vgui::QueryBox* popup = new vgui::QueryBox("Error", "Failed to open keyvalues data from \"Text Editor Panel\"", this);
popup->SetOKButtonText("Ok");
popup->SetCancelButtonVisible(false);
popup->AddActionSignalTarget(this);
popup->DoModal(this);
 
temp->deleteThis();
return;
}
 
//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: 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_SSMakerPanel = new CSoundscapeMaker(parent);
g_SoundPanel = new CSoundListPanel(parent, "SoundListPanel");
g_SoundPanel = new CSoundListPanel(parent, "SoundscapeSoundListPanel");
g_SettingsPanel = new CSoundscapeSettingsPanel(parent, "SettingsPanel");
g_SettingsPanel = new CSoundscapeSettingsPanel(parent, "SoundscapeSettingsPanel");
}
g_SoundscapeTextPanel = new CSoundscapeTextPanel(parent, "SoundscapeTextPanel");
}
 
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();
 
if (g_SoundscapeTextPanel)
g_SoundscapeTextPanel->DeletePanel();
 
g_SSMakerPanel = nullptr;
g_SoundPanel = nullptr;
g_SettingsPanel = nullptr;
g_SoundscapeTextPanel = 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);


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


void Destroy()
void SetBuffer(const char* text)
{
{
if (g_SSMakerPanel)
if (g_SSMakerPanel)
g_SSMakerPanel->DeletePanel();
g_SSMakerPanel->Set(text);
 
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);
}
}
};
};

Revision as of 05:30, 17 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 <vgui_controls/RichText.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"
};

//-----------------------------------------------------------------------------
// Purpose: Helper funciton to compare vector and string
//-----------------------------------------------------------------------------
int Q_vecstr(const CUtlVector<wchar_t>& vec, int startindex, int endindex, const char* substr)
{
	//check for null substring
	if (!substr || !*substr)
		return -1;
	
	//store variables
	int substrLen = Q_strlen(substr);

	//search for match
	for (int i = startindex; i <= endindex; ++i)
	{
		bool match = true;
		for (int j = 0; j < substrLen; ++j)
		{
			wchar_t wc = vec[i + j];
			char ch = substr[j];
			if (wc != ch)
			{
				match = false;
				break;
			}
		}

		//found match
		if (match)
			return i;
	}

	//didnt find match
	return -1;
}

//-----------------------------------------------------------------------------
// Purpose: Helper funciton to compare vector and string but reversed
//-----------------------------------------------------------------------------
int Q_vecrstr(const CUtlVector<wchar_t>& vec, int startindex, int endindex, const char* substr)
{
	//check for null substring
	if (!substr || !*substr)
		return -1;
	
	//store variables
	int substrLen = Q_strlen(substr);

	//search for match
	for (int i = endindex - substrLen + 1; i >= startindex; --i)
	{
		bool match = true;
		for (int j = 0; j < substrLen; ++j)
		{
			wchar_t wc = vec[i + j];
			char ch = substr[j];
			if (wc != ch)
			{
				match = false;
				break;
			}
		}

		//found match
		if (match)
			return i;
	}

	//didnt find match
	return -1;
}

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


//text entry for text edit panel


class CTextPanelTextEntry : public vgui::TextEntry
{
public:
	DECLARE_CLASS_SIMPLE(CTextPanelTextEntry, vgui::TextEntry)

	//constructor
	CTextPanelTextEntry(vgui::Panel* parent, const char* panelName)
		: TextEntry(parent, panelName)
	{
		SetMultiline(true);
	}

	//called on keycode typed
	virtual void OnKeyCodeTyped(vgui::KeyCode code)
	{
		//check for enter or enter
		if (code == KEY_ENTER || code == KEY_PAD_ENTER)
			InsertString("\n");

		//check for tab
		else if (code == KEY_TAB)
			InsertString("    ");
		
		//do other key code
		else
			BaseClass::OnKeyCodeTyped(code);
	}

	//called on keycode pressed
	void OnKeyCodePressed(vgui::KeyCode code)
	{
		if (code == KEY_ENTER || code == KEY_PAD_ENTER
			|| code == KEY_TAB)
			return;

		BaseClass::OnKeyCodePressed(code);
	}

	//called on keycode insert
	void OnKeyTyped(wchar_t c)
	{
		//if (c == '{')
		//{
		//	//insert:
		//	//{
		//	//
		//	//}
		//	//and set cursor in the middle
		//	BaseClass::OnKeyTyped(c);
		//	InsertString("\n\n}    ");
		//	GotoLeft();
		//	GotoUp();
		//	SelectNoText();
		//}
		if (c == '"')
		{		
			//check next item
			if (_cursorPos < m_TextStream.Count())
			{

				//check for " so you dont insert string inside string
				if (m_TextStream[_cursorPos] == '"')
				{
					GotoRight();
					SelectNone();
					return;
				}

			}

			//insert:
			//""
			//and set cursor in the middle
			BaseClass::OnKeyTyped(c);
			InsertString("\"");
			GotoLeft();
			SelectNone();
		}
		else
		{
			BaseClass::OnKeyTyped(c);
		}
	}
};


//soundscape maker text editor panel
#define TEXT_PANEL_WIDTH 760
#define TEXT_PANEL_HEIGHT 630

#define TEXT_PANEL_COMMAND_SET "Set"
#define TEXT_PANEL_COMMAND_SET_OK "SetOk"
#define TEXT_PANEL_COMMAND_FIND "FInd"

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

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

	//sets the keyvalues
	void Set(KeyValues* keyvalues);
	void RecursiveSetText(KeyValues* keyvalues, CUtlBuffer& buffer, int indent);

	//other
	void OnCommand(const char* pszCommand);
	void PerformLayout();
	void OnClose() { BaseClass::OnClose(); }

private:
	CTextPanelTextEntry* m_Text;
	vgui::Button* m_SetButton;
	vgui::TextEntry* m_FindTextEntry;
	vgui::Button* m_FindButton;
};

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSoundscapeTextPanel::CSoundscapeTextPanel(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(true);
	SetMoveable(true);
	SetVisible(false);
	SetMinimumSize(575, 120);

	int ScreenWide, ScreenTall;
	vgui::surface()->GetScreenSize(ScreenWide, ScreenTall);

	SetTitle("Soundscape Text Editor", true);
	SetSize(TEXT_PANEL_WIDTH, TEXT_PANEL_HEIGHT);
	SetPos((ScreenWide - TEXT_PANEL_WIDTH) / 2, (ScreenTall - TEXT_PANEL_HEIGHT) / 2);

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

	//make text entry
	m_Text = new CTextPanelTextEntry(this, "EditBox");
	m_Text->SetBounds(5, 25, TEXT_PANEL_WIDTH - 10, TEXT_PANEL_HEIGHT - 55);
	m_Text->SetEnabled(true);
	m_Text->SetMultiline(true);
	m_Text->SetVerticalScrollbar(true);

	//make set button
	m_SetButton = new vgui::Button(this, "SetButton", "Apply Changes To Keyvalue Maker");
	m_SetButton->SetBounds(5, TEXT_PANEL_HEIGHT - 27, 250, 25);
	m_SetButton->SetCommand(TEXT_PANEL_COMMAND_SET);

	//make find text entry
	m_FindTextEntry = new vgui::TextEntry(this, "FindTextEntry");
	m_FindTextEntry->SetBounds(450, TEXT_PANEL_HEIGHT - 27, 200, 25);

	//make find button
	m_FindButton = new vgui::Button(this, "FindButton", "Find String");
	m_FindButton->SetBounds(655, TEXT_PANEL_HEIGHT - 27, 100, 25);
	m_FindButton->SetCommand(TEXT_PANEL_COMMAND_FIND);
}

//-----------------------------------------------------------------------------
// Purpose: Sets the keyvalues
//-----------------------------------------------------------------------------
void CSoundscapeTextPanel::Set(KeyValues* keyvalues)
{
	//write everything into a buffer
	CUtlBuffer buf(0, 0, CUtlBuffer::TEXT_BUFFER);

	//now write the keyvalues
	KeyValues* pCurrent = keyvalues;
	while (pCurrent)
	{
		RecursiveSetText(pCurrent, buf, 0);

		//put a newline
		if (pCurrent->GetNextTrueSubKey())
			buf.PutChar('\n');
		
		//get next
		pCurrent = pCurrent->GetNextTrueSubKey();
	}

	//write that to the m_Text
	m_Text->SetText((const char*)buf.Base());
}

//-----------------------------------------------------------------------------
// Purpose: Recursively writes to a util buffer
//-----------------------------------------------------------------------------
void CSoundscapeTextPanel::RecursiveSetText(KeyValues* keyvalues, CUtlBuffer& buffer, int indent)
{
	//write \t indent
	for (int i = 0; i < indent; i++)
		buffer.PutString("    ");

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

	//write {
	for (int i = 0; i < indent; i++)
		buffer.PutString("    ");

	buffer.PutString("{\n");

	//increment indent
	indent++;

	//write all the keys first
	FOR_EACH_VALUE(keyvalues, value)
	{
		for (int i = 0; i < indent; i++)
			buffer.PutString("    ");

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

		buffer.PutChar('"');
		buffer.PutString(value->GetString());
		buffer.PutString("\"\n");
	}

	//write all the subkeys now
	FOR_EACH_TRUE_SUBKEY(keyvalues, value)
	{
		//increment indent
		RecursiveSetText(value, buffer, indent);

		if (value->GetNextTrueSubKey())
			buffer.PutChar('\n');
	}

	//decrement indent
	indent--;

	//write ending }
	for (int i = 0; i < indent; i++)
		buffer.PutString("    ");

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

//-----------------------------------------------------------------------------
// Purpose: Called on command
//-----------------------------------------------------------------------------
void CSoundscapeTextPanel::OnCommand(const char* pszCommand)
{
	if (!Q_strcmp(pszCommand, TEXT_PANEL_COMMAND_SET))
	{		
		//play sound
		vgui::surface()->PlaySound("ui/buttonclickrelease.wav");

		//check first incase you accidentally press it
		vgui::QueryBox* popup = new vgui::QueryBox("Set File?", "Are you sure you want to set the current keyvalues for the keyvalue maker?\nIf there are errors then this could break the keyvalue file.", this);
		popup->SetOKCommand(new KeyValues("Command", "command", TEXT_PANEL_COMMAND_SET_OK));
		popup->SetCancelButtonVisible(false);
		popup->AddActionSignalTarget(this);
		popup->DoModal(this);
		return;
	}

	//set text
	if (!Q_strcmp(pszCommand, TEXT_PANEL_COMMAND_SET_OK))
	{
		//get string
		int len = m_Text->GetTextLength() + 1;

		char* buf = new char[len];
		m_Text->GetText(buf, len);

		g_SoundscapeMaker->SetBuffer(buf);

		//delete string
		delete[] buf;
		
		//hide this
		SetVisible(false);
		return;
	}

	//find text
	if (!Q_strcmp(pszCommand, TEXT_PANEL_COMMAND_FIND))
	{
		//get buffer
		char buf[128];
		m_FindTextEntry->GetText(buf, sizeof(buf));

		int index = m_Text->_cursorPos + 1;
		int find = -1;
		
		//go in reversed order if holding shift
		if (vgui::input()->IsKeyDown(KEY_LSHIFT) || vgui::input()->IsKeyDown(KEY_RSHIFT))
		{

			//see if we find index
			find = Q_vecrstr(m_Text->m_TextStream, 0, index - 2, buf);
			if (find == -1)
			
				//look again
				find = Q_vecrstr(m_Text->m_TextStream, index, m_Text->m_TextStream.Count() - 1, buf);

		}
		else
		{

			//see if we find index
			find = Q_vecstr(m_Text->m_TextStream, index, m_Text->m_TextStream.Count(), buf);
			if (find == -1)

				//look again
				find = Q_vecstr(m_Text->m_TextStream, 0, index, buf);

		}

		//check for invalid index
		if (find == -1)
		{
			//play an error sound
			vgui::surface()->PlaySound("resource/warning.wav");

			//get text
			char error[512];
			Q_snprintf(error, sizeof(error), "Couldnt find any instances of '%s'", buf);

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

			return;
		}

		//get number of newlines
		/*int newline = 0;
		int column = 0;
		for (int i = 0; i < find; i++)
		{
			if (m_Text->m_TextStream[i] == '\n')
			{
				newline++;
				column = 0;
			}
			else
			{
				column++;
			}
		}*/

		//select that
		m_Text->_cursorPos = find;
		m_Text->_select[0] = find;
		m_Text->_select[1] = find + Q_strlen(buf);
		m_Text->LayoutVerticalScrollBarSlider();
		m_Text->Repaint();
		m_Text->RequestFocus();

		return;
	}
	 
	BaseClass::OnCommand(pszCommand);
}

//-----------------------------------------------------------------------------
// Purpose: Called on panel size changed
//-----------------------------------------------------------------------------
void CSoundscapeTextPanel::PerformLayout()
{
	BaseClass::PerformLayout();

	int wide, tall;
	GetSize(wide, tall);

	if (m_Text)
		m_Text->SetBounds(5, 25, wide - 10, tall - 55);

	if (m_SetButton)
		m_SetButton->SetBounds(5, tall - 27, 250, 25);

	if (m_FindTextEntry)
		m_FindTextEntry->SetBounds(wide - 310, tall - 27, 200, 25);

	if (m_FindButton)
		m_FindButton->SetBounds(wide - 105, tall - 27, 100, 25);
}

//soundscape settings panel
static CSoundscapeTextPanel* g_SoundscapeTextPanel = nullptr;


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



//should the soundscape's show
bool g_SSMakerShowMessages = false;

#define SETTINGS_PANEL_WIDTH 350
#define SETTINGS_PANEL_HEIGHT 275

#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 SETTINGS_PANEL_COMMAND_DEBUG "Debug"

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

	~CSoundscapeSettingsPanel();

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;
	vgui::CheckButton* m_ShowSoundscapeDebug;

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

	//load settings
	KeyValues* settings = new KeyValues("settings");
	if (!settings->LoadFromFile(filesystem, "cfg/soundscape_maker.txt", "MOD"))
		ConWarning("Failed to load settings for 'cfg/soundscape_maker.txt'. Using default settings.");

	//get positions
	const char* pos0 = settings->GetString("Position0", "0 0 0");
	const char* pos1 = settings->GetString("Position1", "0 0 0");
	const char* pos2 = settings->GetString("Position2", "0 0 0");
	const char* pos3 = settings->GetString("Position3", "0 0 0");
	const char* pos4 = settings->GetString("Position4", "0 0 0");
	const char* pos5 = settings->GetString("Position5", "0 0 0");
	const char* pos6 = settings->GetString("Position6", "0 0 0");
	const char* pos7 = settings->GetString("Position7", "0 0 0");

	//create position text 1
	m_TextEntryPos0 = new vgui::TextEntry(this, "PosTextEntry0");
	m_TextEntryPos0->SetEnabled(true);
	m_TextEntryPos0->SetText(pos0 ? pos0 : "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(pos1 ? pos1 : "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(pos2 ? pos2 : "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(pos3 ? pos3 : "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(pos4 ? pos4 : "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(pos5 ? pos5 : "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(pos6 ? pos6 : "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(pos7 ? pos7 : "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);
	m_ShowSoundscapePositions->SetSelected(settings->GetBool("ShowSoundscapes", false));

	//set convar value
	ConVar* cv = cvar->FindVar("__ss_draw");
	if (cv)
		cv->SetValue(m_ShowSoundscapePositions->IsSelected());

	//create divider
	vgui::Divider* div = new vgui::Divider(this, "Divider");
	div->SetBounds(-2, 247, SETTINGS_PANEL_WIDTH + 4, 2);

	//create debug thing
	bool bDebugSelected = settings->GetBool("PrintDebug");

	m_ShowSoundscapeDebug = new vgui::CheckButton(this, "DebugInfo", "Print Soundscape Debug Info");
	m_ShowSoundscapeDebug->SetBounds(73, 250, 200, 20);
	m_ShowSoundscapeDebug->SetCommand(SETTINGS_PANEL_COMMAND_DEBUG);
	m_ShowSoundscapeDebug->SetSelected(bDebugSelected);

	if (bDebugSelected)
		OnCommand(SETTINGS_PANEL_COMMAND_DEBUG);

	//set server positions
	ConCommand* cc = cvar->FindCommand("__ss_maker_set");
	if (cc)
	{
		CCommand args;

		//do pos 0
		if (pos0)
		{
			args.Tokenize(CFmtStr("ssmaker 0 %s 1", pos0));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[0].Base(), pos0);
		}

		//do pos 1
		if (pos1)
		{
			args.Tokenize(CFmtStr("ssmaker 1 %s 1", pos1));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[1].Base(), pos1);
		}

		//do pos 2
		if (pos2)
		{
			args.Tokenize(CFmtStr("ssmaker 2 %s 1", pos2));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[2].Base(), pos2);
		}

		//do pos 3
		if (pos3)
		{
			args.Tokenize(CFmtStr("ssmaker 3 %s 1", pos3));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[3].Base(), pos3);
		}

		//do pos 4
		if (pos4)
		{
			args.Tokenize(CFmtStr("ssmaker 4 %s 1", pos4));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[4].Base(), pos4);
		}

		//do pos 5
		if (pos5)
		{
			args.Tokenize(CFmtStr("ssmaker 5 %s 1", pos5));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[5].Base(), pos5);
		}

		//do pos 6
		if (pos6)
		{
			args.Tokenize(CFmtStr("ssmaker 6 %s 1", pos6));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[6].Base(), pos6);
		}

		//do pos 7
		if (pos7)
		{
			args.Tokenize(CFmtStr("ssmaker 7 %s", pos7));
			cc->Dispatch(args);

			UTIL_StringToVector(g_SoundscapePositions[7].Base(), pos7);
		}
	}

	//delete settings
	settings->deleteThis();
}

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

	//handle debug thing
	else if (!Q_strcmp(pszCommand, SETTINGS_PANEL_COMMAND_DEBUG))
	{
		//get vars
		static ConVar* con_filter_enable = cvar->FindVar("con_filter_enable");
		static ConVar* con_filter_text = cvar->FindVar("con_filter_text");

		//set g_SSMakerShowMessages
		g_SSMakerShowMessages = m_ShowSoundscapeDebug->IsSelected();
		
		if (g_SSMakerShowMessages)
			developer.SetValue(1);
		else
			developer.SetValue(0);
	}

	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 1", 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 1", 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 1", 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 1", 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 1", 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 1", 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 1", 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 1", buf));
			cc->Dispatch(args);
		}

		return;
	}

}

//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CSoundscapeSettingsPanel::~CSoundscapeSettingsPanel()
{
	//save everything
	KeyValues* settings = new KeyValues("settings");

	//get text's
	char text0[64];
	char text1[64];
	char text2[64];
	char text3[64];
	char text4[64];
	char text5[64];
	char text6[64];
	char text7[64];

	m_TextEntryPos0->GetText(text0, sizeof(text0));
	m_TextEntryPos1->GetText(text1, sizeof(text1));
	m_TextEntryPos2->GetText(text2, sizeof(text2));
	m_TextEntryPos3->GetText(text3, sizeof(text3));
	m_TextEntryPos4->GetText(text4, sizeof(text4));
	m_TextEntryPos5->GetText(text5, sizeof(text5));
	m_TextEntryPos6->GetText(text6, sizeof(text6));
	m_TextEntryPos7->GetText(text7, sizeof(text7));

	//save text entries
	settings->SetString("Position0", text0);
	settings->SetString("Position1", text1);
	settings->SetString("Position2", text2);
	settings->SetString("Position3", text3);
	settings->SetString("Position4", text4);
	settings->SetString("Position5", text5);
	settings->SetString("Position6", text6);
	settings->SetString("Position7", text7);

	//save check buttons
	settings->SetBool("ShowSoundscapes", m_ShowSoundscapePositions->IsSelected());
	settings->SetBool("PrintDebug", m_ShowSoundscapeDebug->IsSelected());

	//save to file
	settings->SaveToFile(filesystem, "cfg/soundscape_maker.txt", "MOD");
	settings->deleteThis();
}

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

		//check for shift key
		bool shift = (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LSHIFT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RSHIFT));
		
		if (shift)
		{
			//start from current index - 1
			int start = m_SoundsList->GetMenu()->GetActiveItem() - 1;

			//look for sound with same name starting from the start first and going down
			for (int i = start; i >= 0; 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 the g_SoundDirectories to the start
			for (int i = g_SoundDirectories.Count() - 1; 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;
				}
			}
		}
		else
		{
			//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();

	virtual void OnKeyCodePressed(vgui::KeyCode code);

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

protected:
	friend class CSoundscapeMaker;

	//keyvalue list.
	KeyValues* m_Keyvalues = nullptr;

	//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 keyboard code pressed
//-----------------------------------------------------------------------------
void CSoundscapeList::OnKeyCodePressed(vgui::KeyCode code)
{
	//check for arrow
	if (code == KEY_UP)
	{
		//find selected item
		for (int i = 0; i < m_MenuButtons.Count(); i++)
		{
			if (m_MenuButtons[i]->m_bIsSelected)
			{
				//check for size and to see if we can select item
				if (i - 1 < 0)
					return;

				//select that item
				GetParent()->OnCommand(m_MenuButtons[i-1]->GetCommand()->GetString("command"));
				return;
			}
		}
	}
	
	//check for arrow
	if (code == KEY_DOWN)
	{
		//find selected item
		for (int i = 0; i < m_MenuButtons.Count(); i++)
		{
			if (m_MenuButtons[i]->m_bIsSelected)
			{
				//check for size and to see if we can select item
				if (i + 1 >= m_MenuButtons.Count())
					return;

				//select that item
				GetParent()->OnCommand(m_MenuButtons[i+1]->GetCommand()->GetString("command"));
				return;
			}
		}
	}
}

//-----------------------------------------------------------------------------
// 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) && m_Keyvalues)
	{
		//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 EDIT_BUTTON_COMMAND "$Edit"
#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;
bool g_bSSMHack = 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();

	//sets the keyvalue file
	void Set(const char* buffer);

	//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;
	vgui::Button* m_ButtonOptions = nullptr;
	vgui::Button* m_EditButton = 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(7, 600, 145, 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(157, 600, 145, 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(307, 600, 145, 25);
	m_ButtonLoad->SetCommand(LOAD_BUTTON_COMMAND);
	m_ButtonLoad->SetDepressedSound("ui/buttonclickrelease.wav");
	
	m_ButtonOptions = new vgui::Button(this, "OptionsButton", "Show Options Panel");
	m_ButtonOptions->SetVisible(true);
	m_ButtonOptions->SetBounds(457, 600, 145, 25);
	m_ButtonOptions->SetCommand(OPTIONS_BUTTON_COMMAND);
	m_ButtonOptions->SetDepressedSound("ui/buttonclickrelease.wav");
	
	m_EditButton = new vgui::Button(this, "EditButton", "Show Text Editor");
	m_EditButton->SetVisible(true);
	m_EditButton->SetBounds(607, 600, 145, 25);
	m_EditButton->SetCommand(EDIT_BUTTON_COMMAND);
	m_EditButton->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_SoundscapeTextPanel->OnClose();

	g_ShowSoundscapePanel = false;
}

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

	//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_bSSMHack = false;
}

//-----------------------------------------------------------------------------
// 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 edit panel button
	else if (!Q_strcmp(pszCommand, EDIT_BUTTON_COMMAND))
	{
		g_SoundscapeTextPanel->SetVisible(true);
		g_SoundscapeTextPanel->MoveToFront();
		g_SoundscapeTextPanel->RequestFocus();
		g_SoundscapeTextPanel->Set(m_KeyValues);
		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");

		//reset title
		SetTitle("Soundscape Maker (New File)", true);

		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)
			{
				m_kvCurrRndwave = nullptr;
				m_pSoundList->m_Keyvalues = nullptr;

				//restart soundscape
				PlaySelectedSoundscape();

				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)
		{
			//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);
				
				if (max > 0)
					m_pDataList->m_pSideSlider->SetRange(0, max - 1);
				else
					m_pDataList->m_pSideSlider->SetRange(0, 0);
			}

			//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 = vec.Count() - 1; // fix bounds more safely

			//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)
			{
				//restart soundscape
				PlaySelectedSoundscape();
				return;
			}

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

		//restart soundscape
		PlaySelectedSoundscape();
		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();

				//get real text
				const char* text = sound->GetString();

				//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)
				{
					text = text;
				}
				else
				{
					if (fslash > bslash)
						text = fslash + 1;

					else if (bslash > fslash)
						text = bslash + 1;
				}

				m_pSoundList->AddButton(name, text, 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);
				
				//put a newline
				if (pCurrent->GetNextTrueSubKey())
					buf.PutChar('\n');

				//get next
				pCurrent = pCurrent->GetNextTrueSubKey();
			} 

			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) ||
		vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RCONTROL))
	{
		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);
		else if (code == vgui::KeyCode::KEY_P)
		{
			//show settings
			g_SettingsPanel->SetVisible(true);
			g_SettingsPanel->RequestFocus();
			g_SettingsPanel->MoveToFront();
		}
		else if (code == vgui::KeyCode::KEY_D)
			OnCommand(DELETE_CURRENT_ITEM_COMMAND);

		//check for ctrl+alt+a
		else if (code == vgui::KeyCode::KEY_A && (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LALT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RALT)) && m_pSoundList && m_pSoundList->m_Keyvalues)
			m_pSoundList->OnCommand(NEW_RNDWAVE_WAVE_COMMAND);

		//check for just ctrl+shift+a
		else if (code == vgui::KeyCode::KEY_A && (vgui::input()->IsKeyDown(vgui::KeyCode::KEY_LSHIFT) || vgui::input()->IsKeyDown(vgui::KeyCode::KEY_RSHIFT)) && m_SoundscapesList)
			m_SoundscapesList->OnCommand(ADD_SOUNDSCAPE_COMMAND);

		return;
	}

	//check for arrow keys
	if (code == KEY_DOWN || code == KEY_UP)
	{
		if (m_kvCurrRndwave)
		{
			m_pSoundList->OnKeyCodePressed(code);
		}
		else if (m_kvCurrSelected && m_pDataList->m_MenuButtons.Count())
		{
			m_pDataList->OnKeyCodePressed(code);
		}
		else
		{
			m_SoundscapesList->OnKeyCodePressed(code);
		}

		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: Sets keyvalues from text
//-----------------------------------------------------------------------------
void CSoundscapeMaker::Set(const char* buffer)
{
	CUtlBuffer buf(0, 0, CUtlBuffer::TEXT_BUFFER);
	buf.PutString(buffer);

	//try and load the keyvalues file first
	KeyValues* temp = new KeyValues("SoundscapeFile");
	if (!temp->LoadFromBuffer("Text Editor Panel Buffer", buf))
	{
		//play an error sound
		vgui::surface()->PlaySound("resource/warning.wav");

		//show an error
		vgui::QueryBox* popup = new vgui::QueryBox("Error", "Failed to open keyvalues data from \"Text Editor Panel\"", this);
		popup->SetOKButtonText("Ok");
		popup->SetCancelButtonVisible(false);
		popup->AddActionSignalTarget(this);
		popup->DoModal(this);

		temp->deleteThis();
		return;
	}

	//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: 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, "SoundscapeSoundListPanel");
		g_SettingsPanel = new CSoundscapeSettingsPanel(parent, "SoundscapeSettingsPanel");
		g_SoundscapeTextPanel = new CSoundscapeTextPanel(parent, "SoundscapeTextPanel");
	}

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

		if (g_SoundscapeTextPanel)
			g_SoundscapeTextPanel->DeletePanel();

		g_SSMakerPanel = nullptr;
		g_SoundPanel = nullptr;
		g_SettingsPanel = nullptr;
		g_SoundscapeTextPanel = 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);

		if (g_SoundscapeTextPanel)
			g_SoundscapeTextPanel->SetVisible(true);
	}

	void SetBuffer(const char* text)
	{
		if (g_SSMakerPanel)
			g_SSMakerPanel->Set(text);
	}
};

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