#include "gen_bot_header.h"
#include <ctype.h>

#define MAX_TAGS 22

char *tag1[MAX_TAGS]={
"-=","-[","-]","-}","-{","<[","<]","[-","]-","{-","}-","[[","[","{","]","}","<",">","-","|","=","+"};
char *tag2[MAX_TAGS]={
"=-","]-","[-","{-","}-","]>","[>","-]","-[","-}","-{","]]","]","}","[","{",">","<","-","|","=","+"};

CChatClass ChatClass;

// ===================================================
// Code of CChatClass::CChatSentence Start
// ===================================================

CChatClass::CChatSentence::CChatSentence(const char *szSentence, bool CM, byte UV, byte RCount,
										 byte TCount) : 
										 szText(new char[strlen(szSentence) + 1]), CanModify(CM),
										 UseValue(UV), RandomNameCount(RCount),
										 TargetNameCount(TCount)
{
	strcpy(szText, szSentence);
	szSenderName[0] = 0;
}

CChatClass::CChatSentence::~CChatSentence()
{
	if (szText)
	{
		delete[] szText;
		szText = NULL;
	}
}

// ===================================================
// Code of CChatClass::CChatSentence End
// ===================================================

// ===================================================
// Code of CChatClass::CChatNode Start
// ===================================================

CChatClass::CChatNode::CChatNode(const char *KW, EKeyType KT) : 
								pChatSentences(new TLinkedList<CChatSentence*>),
								szKeyStr(NULL), KeyType(KT), TotalValue(0),
								SentenceCount(0)
{
	if (KT == KEY_TYPE_KEYTOKEN)
	{
		szKeyStr = new char[2];
		szKeyStr[0] = KW[0];
		szKeyStr[1] = 0;
	}
	else
	{
		szKeyStr = new char[strlen(KW) + 1];
		strcpy(szKeyStr, KW);
	}
}

CChatClass::CChatNode::~CChatNode()
{
	if ((szKeyStr) && (*szKeyStr))
	{
		delete[] szKeyStr;
		szKeyStr = NULL;
	}

	if (pChatSentences)
	{
		while (pChatSentences->Empty() == false)
			delete pChatSentences->Pop();

		delete pChatSentences;
		pChatSentences = NULL;
	}
}

void CChatClass::CChatNode::AddSentence(const char *szSentence)
{
	short StartPos = 0;
	byte b;
	byte RCount = 0, TCount = 0;
	int UV = 50;
	bool CanModify = true;

	short StrLength = strlen(szSentence);

	while ((StartPos < StrLength) && (StartPos < MAX_CHAT_SENTENCE_LENGTH) && 
		   (szSentence[StartPos]))
	{
		if ((szSentence[StartPos] == ' ') || (szSentence[StartPos] == '\t'))
			StartPos++;
		else if (szSentence[StartPos] == '!')
		{
			CanModify = false;
			StartPos++;
		}
		else if (strnicmp(&szSentence[StartPos], "UV:", 3) == 0)
		{
			StartPos += 3; // Skip the 'UV:' part...

			// Get the Use Value...
			int pos = StartPos;

			while ((pos < StrLength) && (pos < MAX_CHAT_SENTENCE_LENGTH) && (szSentence[pos]) &&
				   ((szSentence[pos] == ' ') || (szSentence[pos] == '\t')))
				   pos++;
		
			if ((&szSentence[pos]) && (szSentence[pos]))
			{
				char szTemp[MAX_CHAT_SENTENCE_LENGTH] = "";
				strcpy(szTemp, szSentence);
				char *szUserVal = strtok(&szTemp[pos], " ");

				if ((szUserVal) && (*szUserVal))
				{
					UV = atoi(szUserVal);
					StartPos = pos + strlen(szUserVal) + 1;
				}
			}
		}
		else
		{
			break;
		}
	}
	
	StrLength = strlen(szSentence);
	for (b=0;b<(StrLength-1);b++)
	{
		if (szSentence[b] == '%')
		{
			if (szSentence[b + 1] == 'r')
				RCount++;
			else if (szSentence[b + 1] == 'n')
				TCount++;
		}
	}

	if (UV > 100)
		UV = 100;
	else if (UV < 0)
		UV = 0;

	pChatSentences->AddNode(new CChatSentence(&szSentence[StartPos], CanModify, UV, RCount,
											  TCount));
	SentenceCount++;
	TotalValue += UV;

/*
	if (CanModify == false)
		pChatSentences->AddNode(new CChatSentence(&szSentence[1], false, 50));
	else
		pChatSentences->AddNode(new CChatSentence(szSentence, true, 50));*/
}

int CChatClass::CChatNode::GetRegularVal()
{
	if (TotalValue && SentenceCount)
		return (TotalValue / SentenceCount);
	else
		return 0;
}

// ===================================================
// Code of CChatClass::CChatNode End
// ===================================================

// ===================================================
// Code of CChatClass Start
// ===================================================

CChatClass::CChatClass() : pWelcomeSentences(new CChatNode),
						   pNormalChatNodeList(new TLinkedList<CChatNode*>),
						   pTauntChatNodeList(new TLinkedList<CChatNode*>),
						   pWhineChatNodeList(new TLinkedList<CChatNode*>)
{
	memset(OldChatTexts, 0, sizeof(OldChatTexts));

	for (byte i=0;i<MAX_RECENT_USED_TEXTS;i++)
	{
		pRecentNormalChatTexts[i] = NULL;
		pRecentTauntChatTexts[i] = NULL;
		pRecentWhineChatTexts[i] = NULL;
	}
}

CChatClass::~CChatClass()
{
	if (pWelcomeSentences)
	{
		delete pWelcomeSentences;
		pWelcomeSentences = NULL;
	}

	if (pNormalChatNodeList)
	{
		while (pNormalChatNodeList->Empty() == false)
			delete pNormalChatNodeList->Pop();

		delete pNormalChatNodeList;
		pNormalChatNodeList = NULL;
	}

	if (pTauntChatNodeList)
	{
		while (pTauntChatNodeList->Empty() == false)
			delete pTauntChatNodeList->Pop();

		delete pTauntChatNodeList;
		pTauntChatNodeList = NULL;
	}

	if (pWhineChatNodeList)
	{
		while (pWhineChatNodeList->Empty() == false)
			delete pWhineChatNodeList->Pop();

		delete pWhineChatNodeList;
		pWhineChatNodeList = NULL;
	}
}

// debug function(s)
/*
void PrintChatSentenceNode(CChatClass::CChatSentence *pNode)
{
	clog << pNode->szText << "\n";
}

void PrintChatNode(CChatClass::CChatNode *pNode)
{
	clog << "\nKey word:\n";
	clog << pNode->szKeyWord << "\n";

	clog << "\nSentences:\n";
	pNode->pChatSentences->ForEach(PrintChatSentenceNode);
}
*/
void CChatClass::ReadChatFile()
{
	FILE *pChatFile;
	char FileName[256];
	char KeyWords[MAX_CHAT_KEYWORDS][64];
	char KeyTokens[MAX_CHAT_KEYTOKENS] = "";
	bool ActiveBlock = false;
	EChatCatagory Section = NONE_CHAT;
	EKeyType KeyType = KEY_TYPE_NONE;
	int i;

	byte WelcomeChatCount = 0, NormalChatCount = 0, WhineCount = 0, TauntCount = 0;

	for (i=0; i < 5; i++)
	{
		pRecentNormalChatTexts[i] = NULL;
		pRecentWhineChatTexts[i] = NULL;
		pRecentTauntChatTexts[i] = NULL;
    }

	// Reset all key words
	for (i=0; i < MAX_CHAT_KEYWORDS; i++)
	{
		KeyWords[i][0] = 0;
    }

	// Reset all key tokens
	for (i=0; i < MAX_CHAT_KEYTOKENS; i++)
	{
		KeyTokens[i] = 0;
	}

	BuildBotFileName(FileName, "esf_bot_chat.txt", NULL);

	(*g_engfuncs.pfnServerPrint) ("Reading bot_chat file... ");

	pChatFile = fopen(FileName, "r");

	if (pChatFile == NULL)
	{
		(*g_engfuncs.pfnServerPrint) ("file not found\n");
		return;
	}

	int ch;
	char cmd_line[256];
	int cmd_index;
	static char server_cmd[256];
	char cmd[256], *arg1, *arg2, *arg3, *arg4, *arg5, *arg6;
	char szSentence[MAX_CHAT_SENTENCE_LENGTH] = "";

	while (pChatFile != NULL)
	{
		cmd_index = 0;
		cmd_line[cmd_index] = 0;

		ch = fgetc(pChatFile);

		// skip any leading blanks
		while ((ch == ' ') || (ch == '\t'))
			ch = fgetc(pChatFile);

		while ((ch != EOF) && (ch != '\r') && (ch != '\n'))
   		{
			if (ch == '\t')  // convert tabs to spaces
				ch = ' ';

			cmd_line[cmd_index] = ch;

			ch = fgetc(pChatFile);

			// skip multiple spaces in input file
			while ((cmd_line[cmd_index] == ' ') && (ch == ' '))
				ch = fgetc(pChatFile);

		    cmd_index++;
   		}

		if (ch == '\r')  // is it a carriage return?
		{
		      ch = fgetc(pChatFile);  // skip the linefeed
   		}

		// if reached end of file, then close it
		if (ch == EOF)
   		{
			fclose(pChatFile);
			pChatFile = NULL;
		}

		cmd_line[cmd_index] = 0;  // terminate the command line

		// copy the command line to a server command buffer...
		strcpy(server_cmd, cmd_line);
		strcat(server_cmd, "\n");
		strcpy(cmd, cmd_line);

		cmd_index = 0;
		arg1 = arg2 = arg3 = arg4 = arg5 = arg6 = NULL;

		arg1 = strtok(cmd_line, " ,");
		arg1 = strtok(NULL, " ,"); // Do this twice so we skip the command
		arg2 = strtok(NULL, " ,");
		arg3 = strtok(NULL, " ,");
		arg4 = strtok(NULL, " ,");
		arg5 = strtok(NULL, " ,");
		arg6 = strtok(NULL, " ,");
/*
		// skip to blank or end of string...
		while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0) && 
			   (cmd_line[cmd_index] != ','))
			   cmd_index++;

		if ((cmd_line[cmd_index] == ' ') || (cmd_line[cmd_index] == ','))
		{
			cmd_line[cmd_index++] = 0;
			arg1 = &cmd_line[cmd_index];

		    // skip to blank or end of string...
		    while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0) && 
				   (cmd_line[cmd_index] != ','))
				   cmd_index++;

		    if ((cmd_line[cmd_index] == ' ') || (cmd_line[cmd_index] == ','))
			{
				cmd_line[cmd_index++] = 0;
		        arg2 = &cmd_line[cmd_index];

		        // skip to blank or end of string...
		        while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0) && 
			           (cmd_line[cmd_index] != ','))
					   cmd_index++;

		        if ((cmd_line[cmd_index] == ' ') || (cmd_line[cmd_index] == ','))
		        {
					cmd_line[cmd_index++] = 0;
		            arg3 = &cmd_line[cmd_index];

            		// skip to blank or end of string...
		            while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0) && 
			               (cmd_line[cmd_index] != ','))
						   cmd_index++;

		            if ((cmd_line[cmd_index] == ' ') || (cmd_line[cmd_index] == ','))
            		{
						cmd_line[cmd_index++] = 0;
		                arg4 = &cmd_line[cmd_index];

				        // skip to blank or end of string...
						while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0) && 
							   (cmd_line[cmd_index] != ','))
							   cmd_index++;

						if ((cmd_line[cmd_index] == ' ') || (cmd_line[cmd_index] == ','))
						{
							cmd_line[cmd_index++] = 0;
							arg5 = &cmd_line[cmd_index];

            				// skip to blank or end of string...
							while ((cmd_line[cmd_index] != ' ') && (cmd_line[cmd_index] != 0) && 
								   (cmd_line[cmd_index] != ','))
								   cmd_index++;

							if ((cmd_line[cmd_index] == ' ') || (cmd_line[cmd_index] == ','))
							{
								cmd_line[cmd_index++] = 0;
								arg6 = &cmd_line[cmd_index];
							}
						}
            		}
				}
			}
		}
*/
		if ((cmd[0] == '#') || (cmd[0] == 0))
		    continue;  // skip if comment or blank line

        if (strcmp(cmd, "[bot_welcome]") == 0)
		{
			Section = WELCOME_CHAT;
			continue;
		}

		if (strcmp(cmd, "[bot_chat]") == 0)
		{
			Section = NORMAL_CHAT;
			continue;
		}

		if (strcmp(cmd, "[bot_taunt]") == 0)
		{
			Section = TAUNT_CHAT;
			continue;
		}

        if (strcmp(cmd, "[bot_whine]") == 0)
		{
			Section = WHINE_CHAT;
			continue;
		}

		// skip if no section found yet
		if (Section == NONE_CHAT)
		{
			continue;
		}

		if (cmd[0] == '{')
		{
			ActiveBlock = true;
			continue;
		}

		if (cmd[0] == '}')
		{
			ActiveBlock = false;
			continue;
		}

		if ((strnicmp(cmd, "keyword", 7) == 0) || (strnicmp(cmd, "keyword2", 8) == 0))
		{
			// Reset all key words
			for (i=0; i < MAX_CHAT_KEYWORDS; i++)
			{
				KeyWords[i][0] = 0;
			}

			if (strnicmp(cmd, "keyword2", 8) == 0)
				KeyType = KEY_TYPE_KEYWORD2;
			else
				KeyType = KEY_TYPE_KEYWORD;

			// Set new keyword(s)...

			if ((arg1) && (*arg1))
			{
				strncpy(KeyWords[0], arg1, 63);
				KeyWords[0][63] = 0;
			}

			if ((arg2) && (*arg2))
			{
				strncpy(KeyWords[1], arg2, 63);
				KeyWords[1][63] = 0;
			}

			if ((arg3) && (*arg3))
			{
				strncpy(KeyWords[2], arg3, 63);
				KeyWords[2][63] = 0;
			}

			if ((arg4) && (*arg4))
			{
				strncpy(KeyWords[3], arg4, 63);
				KeyWords[3][63] = 0;
			}

			if ((arg5) && (*arg5))
			{
				strncpy(KeyWords[4], arg5, 63);
				KeyWords[4][63] = 0;
			}

			if ((arg6) && (*arg6))
			{
				strncpy(KeyWords[5], arg6, 63);
				KeyWords[5][63] = 0;
			}

			continue;
		}

		if (strnicmp(cmd, "keytoken", 8) == 0)
		{
			// Reset all key tokens
			for (i=0; i < MAX_CHAT_KEYTOKENS; i++)
			{
				KeyTokens[i] = 0;
			}

			KeyType = KEY_TYPE_KEYTOKEN;

			// Set new keytoken(s)...

			if ((arg1) && (*arg1))
			{
				KeyTokens[0] = arg1[0];
			}

			if ((arg2) && (*arg2))
			{
				KeyTokens[1] = arg2[0];
			}

			if ((arg3) && (*arg3))
			{
				KeyTokens[2] = arg3[0];
			}

			if ((arg4) && (*arg4))
			{
				KeyTokens[3] = arg4[0];
			}

			if ((arg5) && (*arg5))
			{
				KeyTokens[4] = arg5[0];
			}

			if ((arg6) && (*arg6))
			{
				KeyTokens[5] = arg6[0];
			}

			continue;
		}

		// Skip if outside brackets
		if (!ActiveBlock)// && (KeyType != KEY_TYPE_NONE) && (KeyType != KEY_TYPE_KEYWORD))
			continue;

		// If we get here we lickely need to add a new chat sentence...
		// So just in case the sentence is longer then MAX_CHAT_SENTENCE_LENGTH
		// we only take the first MAX_CHAT_SENTENCE_LENGTH chars...
		strncpy(szSentence, cmd, MAX_CHAT_SENTENCE_LENGTH - 1);
		szSentence[MAX_CHAT_SENTENCE_LENGTH - 1] = 0;

		int StrLength = strlen(szSentence);

		// If last char is a '\n'; remove it.
		if (szSentence[StrLength - 1] == '\n')
			szSentence[StrLength - 1] = 0;

		// If not in a keyword block and not in a keytoken block...
		if (KeyType == KEY_TYPE_NONE)
			KeyType = KEY_TYPE_KEYWORD;

		if ((Section == WELCOME_CHAT) && (WelcomeChatCount < MAX_BOT_CHAT))
		{
			AddWelcomeSentence(szSentence);
			WelcomeChatCount++;
		}
		else if ((Section == NORMAL_CHAT) && (NormalChatCount < MAX_BOT_CHAT))
		{
			if ((KeyType == KEY_TYPE_KEYWORD) || (KeyType == KEY_TYPE_KEYWORD2))
			{
				// No key word(s) specified?
				if (KeyWords[0][0] == 0)
					strcpy(KeyWords[0], "All");

				AddNormalChatSentence(szSentence, KeyWords[0], KeyType);

				for (i=1;i<MAX_CHAT_KEYWORDS;i++)
				{
					if (KeyWords[i][0] != 0)
						AddNormalChatSentence(szSentence, KeyWords[i], KeyType);
				}
			}
			else
			{
				// No key token(s) specified?
				if (KeyTokens[0] == 0)
					KeyTokens[0] = ' '; // Make it a space

				AddNormalChatSentence(szSentence, &KeyTokens[0], KeyType);

				for (i=1;i<MAX_CHAT_KEYWORDS;i++)
				{
					if (KeyTokens[i] != 0)
						AddNormalChatSentence(szSentence, &KeyTokens[i], KeyType);
				}
			}

			NormalChatCount++;
		}
        else if ((Section == TAUNT_CHAT) && (TauntCount < MAX_BOT_CHAT))
		{
			// No key word(s) specified?
			if (KeyWords[0][0] == 0)
				strcpy(KeyWords[0], "All");

			// .. For now DON'T use keywords for taunt sentences...
			AddTauntChatSentence(szSentence, "All", KeyType);

/*
			AddTauntChatSentence(szSentence, KeyWords[0], CanModify);

			for (i=1;i<MAX_CHAT_KEYWORDS;i++)
			{
				if (KeyWords[i][0] != 0)
					AddTauntChatSentence(szSentence, KeyWords[i], CanModify);
			}
*/
			TauntCount++;
		}
        else if ((Section == WHINE_CHAT) && (WhineCount < MAX_BOT_CHAT))
		{
			// No key word(s) specified?
			if (KeyWords[0][0] == 0)
				strcpy(KeyWords[0], "All");

			// .. For now DON'T use keywords for whine sentences...
			AddWhineChatSentence(szSentence, "All", KeyType);

//			AddWhineChatSentence(szSentence, KeyWords[0], CanModify);

/*
			for (i=1;i<MAX_CHAT_KEYWORDS;i++)
			{
				if (KeyWords[i][0] != 0)
					AddWhineChatSentence(szSentence, KeyWords[i], CanModify);
			}
*/
			WhineCount++;
		}
	}
    (*g_engfuncs.pfnServerPrint) ("done\n");

/*
	clog << "\nNormal Chat node list:\n\n";
	pNormalChatNodeList->ForEach(PrintChatNode);
	clog << "\nTaunt Chat node list:\n\n";
	pTauntChatNodeList->ForEach(PrintChatNode);
	clog << "\nWhine Chat node list:\n\n";
	pWhineChatNodeList->ForEach(PrintChatNode);
*/
}

void CChatClass::AddNormalChatSentence(const char *Sentence, const char *KeyWord, EKeyType KT)
{
	CChatNode *pChatNode = NULL;

	if (KT == KEY_TYPE_KEYTOKEN)
		pChatNode = GetChatNodeByKeyToken(pNormalChatNodeList, KeyWord[0]);
	else
		pChatNode = GetChatNodeByKeyWord(pNormalChatNodeList, KeyWord);

	if (!pChatNode)
	{
		pChatNode = new CChatNode(KeyWord, KT);
		pChatNode->AddSentence(Sentence);
		pNormalChatNodeList->AddNode(pChatNode);
	}
	else
		pChatNode->AddSentence(Sentence);
}

void CChatClass::AddTauntChatSentence(const char *Sentence, const char *KeyWord, EKeyType KT)
{
	CChatNode *pChatNode = GetChatNodeByKeyWord(pTauntChatNodeList, KeyWord);

	if (!pChatNode)
	{
		pChatNode = new CChatNode(KeyWord, KT);
		pChatNode->AddSentence(Sentence);
		pTauntChatNodeList->AddNode(pChatNode);
	}
	else
		pChatNode->AddSentence(Sentence);
}

void CChatClass::AddWhineChatSentence(const char *Sentence, const char *KeyWord, EKeyType KT)
{
	CChatNode *pChatNode = GetChatNodeByKeyWord(pWhineChatNodeList, KeyWord);

	if (!pChatNode)
	{
		pChatNode = new CChatNode(KeyWord, KT);
		pChatNode->AddSentence(Sentence);
		pWhineChatNodeList->AddNode(pChatNode);
	}
	else
		pChatNode->AddSentence(Sentence);
}

bool CChatClass::CreateResponseList(SOldChatText *pOldChatText,
									TMultiChoice<CChatSentence*> *pSentenceList)
{
	char TempSentence[MAX_CHAT_SENTENCE_LENGTH] = "";
	char *TempKeyWord = NULL;
	CChatNode *pChatNode = NULL;
	bool MadeResponse = false;
	/*modified by harSens
	TLinkedList<CChatSentence *>::node_s *pSentenceListNode;
	*/
	node_s<CChatSentence *> *pSentenceListNode;
	byte SentenceVal;
	bool bSkip;

	strcpy(TempSentence, pOldChatText->szText);

	TempKeyWord = strtok(TempSentence, " ,.;:[](){}-=+*-/\\<>?!@#$%%^&\n\r\t");

	// Examine all words in the sentence to find a keyword....
	while (TempKeyWord)
	{
		pChatNode = GetChatNodeByKeyWord(pNormalChatNodeList, (const char*)(TempKeyWord));
		// Is this word known as a key word?
		if (pChatNode)
		{
			if (!MadeResponse)
				MadeResponse = true;

			pSentenceListNode = pChatNode->pChatSentences->GetFirst();
			while(pSentenceListNode)
			{
				if (pSentenceListNode->Entry->RandomNameCount > (BotManager.m_bNumberOfPlayers - 1))
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}

				if (pSentenceListNode->Entry->TargetNameCount > BotManager.m_bNumberOfPlayers)
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}
				
				SentenceVal = pSentenceListNode->Entry->UseValue;

				bSkip = false;
				for (byte i=0;i<MAX_RECENT_USED_TEXTS;i++)
				{
					// Is this sentence recently used?
					if (pSentenceListNode->Entry == pRecentNormalChatTexts[i])
					{
						// For about 80% skip the message
						if (RANDOM_LONG(1, 100) <= 80)
						{
							bSkip = true;
						}
						else // else just lower the use value
							SentenceVal *= 0.25;

						break;
					}
				}

				if (bSkip)
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}

				pSentenceListNode->Entry->szSenderName[0] = 0;
				strcpy(pSentenceListNode->Entry->szSenderName, pOldChatText->szSenderName);
				pSentenceList->Insert(pSentenceListNode->Entry, SentenceVal);

				pSentenceListNode = pSentenceListNode->next;
			}
		}

		TempKeyWord = strtok(NULL, " ,.;:[](){}-=+*-/\\<>?!@#$%%^&\n\r\t");
	}

	strcpy(TempSentence, pOldChatText->szText);
	TempKeyWord = strtok(TempSentence, " \n\r\t");

	// Examine all words in the sentence to find a keyword(without token filtering)....
	while (TempKeyWord)
	{
		pChatNode = GetChatNodeByKeyWord(pNormalChatNodeList, (const char*)(TempKeyWord));

		// Is this word known as a key word?
		if (pChatNode)
		{
			if (!MadeResponse)
				MadeResponse = true;

			pSentenceListNode = pChatNode->pChatSentences->GetFirst();
			while(pSentenceListNode)
			{
				if (pSentenceListNode->Entry->RandomNameCount > (BotManager.m_bNumberOfPlayers - 1))
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}

				if (pSentenceListNode->Entry->TargetNameCount > BotManager.m_bNumberOfPlayers)
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}
				
				SentenceVal = pSentenceListNode->Entry->UseValue;

				bSkip = false;
				for (byte i=0;i<MAX_RECENT_USED_TEXTS;i++)
				{
					// Is this sentence recently used?
					if (pSentenceListNode->Entry == pRecentNormalChatTexts[i])
					{
						// For about 80% skip the message
						if (RANDOM_LONG(1, 100) <= 80)
						{
							bSkip = true;
						}
						else // else just lower the use value
							SentenceVal *= 0.25;

						break;
					}
				}

				if (bSkip)
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}

				pSentenceListNode->Entry->szSenderName[0] = 0;
				strcpy(pSentenceListNode->Entry->szSenderName, pOldChatText->szSenderName);
				pSentenceList->Insert(pSentenceListNode->Entry, SentenceVal);

				pSentenceListNode = pSentenceListNode->next;
			}
		}

		TempKeyWord = strtok(NULL, " \n\r\t");
	}

	short Index = 0;
	short SentenceLength = strlen(pOldChatText->szText);

	// Examine all tokens...
	while ((Index < SentenceLength) && (pOldChatText->szText[Index]))
	{
		pChatNode = GetChatNodeByKeyToken(pNormalChatNodeList, pOldChatText->szText[Index]);

		if (pChatNode)
		{
			if (!MadeResponse)
				MadeResponse = true;

			pSentenceListNode = pChatNode->pChatSentences->GetFirst();
			while(pSentenceListNode)
			{
				if (pSentenceListNode->Entry->RandomNameCount > (BotManager.m_bNumberOfPlayers - 1))
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}

				if (pSentenceListNode->Entry->TargetNameCount > BotManager.m_bNumberOfPlayers)
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}
				
				SentenceVal = pSentenceListNode->Entry->UseValue;

				bSkip = false;
				for (byte i=0;i<MAX_RECENT_USED_TEXTS;i++)
				{
					// Is this sentence recently used?
					if (pSentenceListNode->Entry == pRecentNormalChatTexts[i])
					{
						// For about 80% skip the message
						if (RANDOM_LONG(1, 100) <= 80)
						{
							bSkip = true;
						}
						else // else just lower the use value
							SentenceVal *= 0.25;

						break;
					}
				}

				if (bSkip)
				{
					pSentenceListNode = pSentenceListNode->next;
					continue;
				}

				pSentenceListNode->Entry->szSenderName[0] = 0;
				strcpy(pSentenceListNode->Entry->szSenderName, pOldChatText->szSenderName);
				pSentenceList->Insert(pSentenceListNode->Entry, SentenceVal);

				pSentenceListNode = pSentenceListNode->next;
			}
		}

		Index++;
	}

	return MadeResponse;
}

void CChatClass::LetBotSayAWelcomeSentence(CBot *pBot)
{
	// Pick a random sentence

	TMultiChoice<CChatSentence*> *pSentenceChoiceList = new TMultiChoice<CChatSentence*>;
	/*modified by harSens
	TLinkedList<CChatSentence *>::node_s *pSentenceListNode = pWelcomeSentences->pChatSentences->GetFirst();
	*/
	node_s <CChatSentence *>*pSentenceListNode = pWelcomeSentences->pChatSentences->GetFirst();

	while(pSentenceListNode)
	{
		if (pSentenceListNode->Entry->RandomNameCount > (BotManager.m_bNumberOfPlayers - 1))
		{
			pSentenceListNode = pSentenceListNode->next;
			continue;
		}

		if (pSentenceListNode->Entry->TargetNameCount > BotManager.m_bNumberOfPlayers)
		{
			pSentenceListNode = pSentenceListNode->next;
			continue;
		}
				
		pSentenceChoiceList->Insert(pSentenceListNode->Entry, pSentenceListNode->Entry->UseValue);
		pSentenceListNode = pSentenceListNode->next;
	}

	CChatSentence *pSentence = NULL;
	pSentenceChoiceList->GetSelection(pSentence);
	delete pSentenceChoiceList;
	if (pSentence)
	{
		pBot->m_bBotShouldSay = true;
		pBot->m_fBotSayTime = gpGlobals->time + 5.0 + RANDOM_FLOAT(0.0, 5.0);
			
		char PlayerName[33] = "";
		strcpy(PlayerName, STRING(pBot->pev->netname)); // make a 'dummy' name

		char ChatText[256] = "";

		if (pSentence->CanModify)
			MakeChatSentence(pBot->m_pPersonality,
							 pSentence->szText, ChatText);
		else
			strcpy(ChatText, pSentence->szText);

		FillInNames(pBot, ChatText, pBot->m_szBotSayMsg, PlayerName, STRING(pBot->pev->netname));
	}
}

void CChatClass::LetBotCheckForReply(CBot *pBot)
{
	TMultiChoice<CChatSentence*> SentenceChoiceList[MAX_OLD_TEXTS_SAVED];
	TMultiChoice<TMultiChoice<CChatSentence*>*> *pReplySentencesChoices = new TMultiChoice<TMultiChoice<CChatSentence*>*>;
	CChatSentence *pSentence = NULL;
	char BotName[33] = "";

	strcpy(BotName, STRING(pBot->pev->netname));

	// Look if the bot can reply to a sentence...

	// Are there are any msg's at all and if so aren't they to old?
	if ((OldChatTexts[0].szText) && (*OldChatTexts[0].szText) &&
		(OldChatTexts[0].flCreateTime > (gpGlobals->time - 5.0f)))
	{
		byte Counter;
		short s;
		CBasePlayer *pPlayer;
		char szPlayerName[33];

		for (Counter=0;Counter<MAX_OLD_TEXTS_SAVED;Counter++)
		{
			if ((OldChatTexts[Counter].szText) && (*OldChatTexts[Counter].szText) &&
				(OldChatTexts[Counter].flCreateTime > (gpGlobals->time - 5.0f)) &&
				(OldChatTexts[Counter].szSenderName) && 
				(*OldChatTexts[Counter].szSenderName) &&
				(strcmp(BotName, OldChatTexts[Counter].szSenderName) != 0))
			{
				byte UV = 50 - (10 * Counter);

				// Check if there are player names in the sentence...
				for (s=1;s<=gpGlobals->maxClients;s++)
				{
					pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(s);
					if (UTIL_IsValidPlayer(pPlayer, false, false) == false)
						continue;

					strcpy(szPlayerName, STRING(pPlayer->pev->netname));

					if (strstr(OldChatTexts[Counter].szText, szPlayerName))
						UV *= 0.1;
					else if (strstr(OldChatTexts[Counter].szText, BotName))
						UV *= 1.25;
				}

				if(CreateResponseList(&OldChatTexts[Counter], &SentenceChoiceList[Counter]))
					pReplySentencesChoices->Insert(&SentenceChoiceList[Counter], UV);
			}
		}
	}

	TMultiChoice<CChatSentence*> *pSentenceChoiceList = NULL;
	pReplySentencesChoices->GetSelection(pSentenceChoiceList);
	delete pReplySentencesChoices;

	pSentence = NULL;

	if (pSentenceChoiceList)
	{
		pSentenceChoiceList->GetSelection(pSentence);
	}

	if (pSentence)
	{
		StoreRecentUsedSentence(pRecentNormalChatTexts, pSentence);
		pBot->m_bBotShouldSay = true;
		pBot->m_fBotSayTime = gpGlobals->time + RANDOM_FLOAT(1.0, 2.5);
		pBot->m_fBotChatTime += RANDOM_FLOAT(10.0f, 20.0f);
			
		char PlayerName[33] = "";
		if (pSentence->szSenderName[0])
			strcpy(PlayerName, pSentence->szSenderName);
		else 
			strcpy(PlayerName, STRING(pBot->pev->netname)); // make a 'dummy' name

		char ChatText[256] = "";

		if (pSentence->CanModify)
			MakeChatSentence(pBot->m_pPersonality,
							 pSentence->szText, ChatText);
		else
			strcpy(ChatText, pSentence->szText);

		FillInNames(pBot, ChatText, pBot->m_szBotSayMsg, PlayerName, BotName);
	}
}

void CChatClass::LetBotSaySomething(CBot *pBot)
{
	TMultiChoice<CChatSentence*> *pSentenceChoiceList = new TMultiChoice<CChatSentence*>;
	/*modified by harSens
	TLinkedList<CChatSentence*>::node_s *pSentenceListNode;
	*/
	node_s<CChatSentence*>*pSentenceListNode;
	CChatSentence *pSentence = NULL;
	char BotName[33] = "";
	bool bSkip;

	strcpy(BotName, STRING(pBot->pev->netname));

	// Pick a random sentence
	CChatNode *pChatNode = GetChatNodeByKeyWord(pNormalChatNodeList, "All");
	if (pChatNode)
	{
		pSentenceListNode = pChatNode->pChatSentences->GetFirst();
		while(pSentenceListNode)
		{
			if (pSentenceListNode->Entry->RandomNameCount > (BotManager.m_bNumberOfPlayers - 1))
			{
				pSentenceListNode = pSentenceListNode->next;
				continue;
			}

			if (pSentenceListNode->Entry->TargetNameCount > BotManager.m_bNumberOfPlayers)
			{
				pSentenceListNode = pSentenceListNode->next;
				continue;
			}
				
			byte SentenceVal = pSentenceListNode->Entry->UseValue;
			bSkip = false;

			for (byte i=0;i<MAX_RECENT_USED_TEXTS;i++)
			{
				// Is this sentence recently used?
				if (pSentenceListNode->Entry == pRecentNormalChatTexts[i])
				{
					// For about 80% skip the message
					if (RANDOM_LONG(1, 100) <= 80)
					{
						bSkip = true;
					}
					else // else just lower the use value
						SentenceVal *= 0.25;

					break;
				}
			}

			if (!bSkip)
			{
				pSentenceChoiceList->Insert(pSentenceListNode->Entry, SentenceVal);
				pSentenceListNode = pSentenceListNode->next;
			}
		}
	}

	pSentenceChoiceList->GetSelection(pSentence);
	delete pSentenceChoiceList;

	if (pSentence)
	{
		StoreRecentUsedSentence(pRecentNormalChatTexts, pSentence);
		pBot->m_bBotShouldSay = true;
		pBot->m_fBotSayTime = gpGlobals->time + 5.0 + RANDOM_FLOAT(0.0, 5.0);
			
		char PlayerName[33] = "";
		if (pSentence->szSenderName[0])
			strcpy(PlayerName, pSentence->szSenderName);
		else 
			strcpy(PlayerName, STRING(pBot->pev->netname)); // make a 'dummy' name

		char ChatText[256] = "";

		if (pSentence->CanModify)
			MakeChatSentence(pBot->m_pPersonality,
							 pSentence->szText, ChatText);
		else
			strcpy(ChatText, pSentence->szText);

		FillInNames(pBot, ChatText, pBot->m_szBotSayMsg, PlayerName, BotName);
	}
}

void CChatClass::LetBotTaunt(CBot *pBot, CBasePlayer *pVictim)
{
	// Pick a random sentence
	CChatNode *pChatNode = GetChatNodeByKeyWord(pTauntChatNodeList, "All");
	/*modified by harSens
	TLinkedList<CChatSentence*>::node_s *pSentenceListNode;
	*/
	node_s<CChatSentence*> *pSentenceListNode;
	bool bSkip;

	if (pChatNode)
	{
		TMultiChoice<CChatSentence*> *pSentenceChoiceList = new TMultiChoice<CChatSentence*>;

		pSentenceListNode = pChatNode->pChatSentences->GetFirst();
		while(pSentenceListNode)
		{
			if (pSentenceListNode->Entry->RandomNameCount > (BotManager.m_bNumberOfPlayers - 1))
			{
				pSentenceListNode = pSentenceListNode->next;
				continue;
			}

			if (pSentenceListNode->Entry->TargetNameCount > BotManager.m_bNumberOfPlayers)
			{
				pSentenceListNode = pSentenceListNode->next;
				continue;
			}
				
			byte SentenceVal = pSentenceListNode->Entry->UseValue;
			bSkip = false;

			for (byte i=0;i<MAX_RECENT_USED_TEXTS;i++)
			{
				// Is this sentence recently used?
				if (pSentenceListNode->Entry == pRecentTauntChatTexts[i])
				{
					// For about 80% skip the message
					if (RANDOM_LONG(1, 100) <= 80)
					{
						bSkip = true;
					}
					else // else just lower the use value
						SentenceVal *= 0.25;

					break;
				}
			}

			if (!bSkip)
			{
				pSentenceChoiceList->Insert(pSentenceListNode->Entry, SentenceVal);
				pSentenceListNode = pSentenceListNode->next;
			}
		}
	
		CChatSentence *pSentence = NULL;
		pSentenceChoiceList->GetSelection(pSentence);
		delete pSentenceChoiceList;
		if (pSentence)
		{
			StoreRecentUsedSentence(pRecentTauntChatTexts, pSentence);
			pBot->m_bBotShouldSay = true;
			pBot->m_fBotSayTime = gpGlobals->time + 5.0 + RANDOM_FLOAT(0.0, 5.0);
				
			const char *BotName = STRING(pBot->pev->netname);
			char ChatText[256] = "";
			char VictimName[33] = "";

			HumanizeName(pBot->m_pPersonality, STRING(pVictim->pev->netname),
						 VictimName);

			if (pSentence->CanModify)
				MakeChatSentence(pBot->m_pPersonality, pSentence->szText, ChatText);
			else
				strcpy(ChatText, pSentence->szText);

			FillInNames(pBot, ChatText, pBot->m_szBotSayMsg, VictimName, BotName);
		}
	}
}

void CChatClass::LetBotWhine(CBot *pBot, CBasePlayer *pKiller)
{
	// Pick a random sentence
	CChatNode *pChatNode = GetChatNodeByKeyWord(pWhineChatNodeList, "All");
	/*modified by harSens
	TLinkedList<CChatSentence*>::node_s *pSentenceListNode;
	*/
	node_s<CChatSentence*> *pSentenceListNode;
	bool bSkip;

	if (pChatNode)
	{
		TMultiChoice<CChatSentence*> *pSentenceChoiceList = new TMultiChoice<CChatSentence*>;

		pSentenceListNode = pChatNode->pChatSentences->GetFirst();
		while(pSentenceListNode)
		{
			if (pSentenceListNode->Entry->RandomNameCount > (BotManager.m_bNumberOfPlayers - 1))
			{
				pSentenceListNode = pSentenceListNode->next;
				continue;
			}

			if (pSentenceListNode->Entry->TargetNameCount > BotManager.m_bNumberOfPlayers)
			{
				pSentenceListNode = pSentenceListNode->next;
				continue;
			}
				
			byte SentenceVal = pSentenceListNode->Entry->UseValue;
			bSkip = false;

			for (byte i=0;i<MAX_RECENT_USED_TEXTS;i++)
			{
				// Is this sentence recently used?
				if (pSentenceListNode->Entry == pRecentWhineChatTexts[i])
				{
					// For about 80% skip the message
					if (RANDOM_LONG(1, 100) <= 80)
					{
						bSkip = true;
					}
					else // else just lower the use value
						SentenceVal *= 0.25;

					break;
				}
			}

			if (!bSkip)
			{
				pSentenceChoiceList->Insert(pSentenceListNode->Entry, SentenceVal);
				pSentenceListNode = pSentenceListNode->next;
			}
		}

		CChatSentence *pSentence = NULL;
		pSentenceChoiceList->GetSelection(pSentence);
		delete pSentenceChoiceList;
		if (pSentence)
		{
			StoreRecentUsedSentence(pRecentWhineChatTexts, pSentence);
			pBot->m_bBotShouldSay = true;
			pBot->m_fBotSayTime = gpGlobals->time + 5.0 + RANDOM_FLOAT(0.0, 5.0);
				
			const char *BotName = STRING(pBot->pev->netname);
			char ChatText[256] = "";
			char KillerName[33] = "";

			HumanizeName(pBot->m_pPersonality, STRING(pKiller->pev->netname),
						 KillerName);

			if (pSentence->CanModify)
				MakeChatSentence(pBot->m_pPersonality, pSentence->szText, ChatText);
			else
				strcpy(ChatText, pSentence->szText);

			FillInNames(pBot, ChatText, pBot->m_szBotSayMsg, KillerName, BotName);
		}
	}
}

void CChatClass::MakeChatSentence(bot_personality_s *pPerso, 
								  const char *szSentence, char *szOutput)
{
	int pos;
    char temp_text[81];
    int count;

    strncpy(temp_text, szSentence, 79);
    temp_text[80] = 0;

    if (RANDOM_LONG(1, 100) <= pPerso->chat_drop_percent)
    {
		count = RANDOM_LONG(1, 3);

        while (count)
		{
			DropChars(temp_text, szOutput);
			strcpy(temp_text, szOutput);
			count--;
		}
    }

    if (RANDOM_LONG(1, 100) <= pPerso->chat_swap_percent)
    {
		count = RANDOM_LONG(1, 2);

		while (count)
		{
			SwapChars(temp_text, szOutput);
			strcpy(temp_text, szOutput);
			count--;
		}
    }

    if (RANDOM_LONG(1, 100) <= pPerso->chat_lower_percent)
    {
		pos = 0;
		while (temp_text[pos])
		{
			temp_text[pos] = tolower(temp_text[pos]);
			pos++;
		}
    }

    strcpy(szOutput, temp_text);
}

void CChatClass::FillInNames(CBot *pBot, const char *szSentence, char *szOutput,
							 const char *PlayerName, const char *BotName)
{
	int chat_index, say_index;
    const char *name_pos, *rand_pos;
    char random_name[64];
    int index, name_offset = 0, rand_offset = 0;  //EEKHOORN GAVE THESE A VALUE
    bool is_bad;
	char PlayerNames[32][33];
	CBasePlayer *pPlayer;

    chat_index = 0;
    say_index = 0;
    szOutput[0] = 0;

    name_pos = strstr(&szSentence[chat_index], "%n");
    rand_pos = strstr(&szSentence[chat_index], "%r");

    while ((name_pos != NULL) || (rand_pos != NULL))
    {
		if (name_pos != NULL)
			name_offset = name_pos - szSentence;
		if (rand_pos != NULL)
			rand_offset = rand_pos - szSentence;

		if ((rand_pos == NULL) ||
			((name_offset < rand_offset) && (name_pos != NULL)))
		{
			while (&szSentence[chat_index] < name_pos)
				szOutput[say_index++] = szSentence[chat_index++];

			szOutput[say_index] = 0;  // add null terminator

			chat_index += 2;  // skip the "%n"

			strcat(szOutput, PlayerName);
			say_index += strlen(PlayerName);

			szOutput[say_index] = 0;
		}
		else  // use random player name...
		{
			int count;
			int PlayerCount = 0;

			for (count = 1;count <= gpGlobals->maxClients;count++)
			{
				pPlayer = (CBasePlayer *)UTIL_PlayerByIndex(count);

				if (pPlayer == pBot)
					continue;

				if (pBot->m_bMadePlayerList)
				{
					if (!(pBot->m_lValidPlayers & (1<<(count-1))))
						continue;
				}
				else if (UTIL_IsValidPlayer(pPlayer, false, false) == false)
					continue;

				strcpy(PlayerNames[PlayerCount], STRING(pPlayer->pev->netname));
				PlayerCount++;
			}

			if (PlayerCount < 2)
				return; // Looks stupid if bot is talking to himself :)

			// pick a name at random from the list of players...

			index = RANDOM_LONG(0, PlayerCount-1);

			is_bad = (strcmp(PlayerNames[index], PlayerName) == 0) ||
				     (strcmp(PlayerNames[index], BotName) == 0);

			count = 0;
			while ((is_bad) && (count < 20))
			{
				index = RANDOM_LONG(0, PlayerCount-1);

				is_bad = (strcmp(PlayerNames[index], PlayerName) == 0) ||
					     (strcmp(PlayerNames[index], BotName) == 0);

				count++;
			}

			HumanizeName(pBot->m_pPersonality, PlayerNames[index], random_name);

			while (&szSentence[chat_index] < rand_pos)
				szOutput[say_index++] = szSentence[chat_index++];

			szOutput[say_index] = 0;  // add null terminator

			chat_index += 2;  // skip the "%r"

			strcat(szOutput, random_name);
			say_index += strlen(random_name);

			szOutput[say_index] = 0;
		}

		name_pos = strstr(&szSentence[chat_index], "%n");
		rand_pos = strstr(&szSentence[chat_index], "%r");
    }

    while (szSentence[chat_index])
		szOutput[say_index++] = szSentence[chat_index++];

    szOutput[say_index] = 0;  // add null terminator
}

void CChatClass::HumanizeName(bot_personality_s *pPerso, const char *szName, char *szOutput)
{
	int pos;

    if (RANDOM_LONG(1, 100) <= pPerso->chat_tag_percent)
    {
		char temp_name[80];

		strncpy(temp_name, szName, 31);
		temp_name[31] = 0;

		while (CutTags(temp_name, szOutput))
		{
			strcpy(temp_name, szOutput);
		}
    }
    else
    {
		strncpy(szOutput, szName, 31);
		szOutput[31] = 0;
    }

    if (RANDOM_LONG(1, 100) <= pPerso->chat_lower_percent)
    {
		pos = 0;
		while ((pos < 80) && (szOutput[pos]))
		{
			szOutput[pos] = tolower(szOutput[pos]);
			pos++;
		}
    }
}

int CChatClass::CutTags(const char *szName, char *szOutput)
{
	int i;
    char *pos1, *pos2, *src, *dest;
    char in_name[80];
    int result = 0;

    strncpy(in_name, szName, 31);
    in_name[32] = 0;

    for (i=0; i < MAX_TAGS; i++)
    {
		pos1=strstr(in_name, tag1[i]);
		if (pos1)
			pos2 = strstr(pos1+strlen(tag1[i]), tag2[i]);
		else
			pos2 = NULL;

		if (pos1 && pos2 && pos1 < pos2)
		{
			src = pos2+strlen(tag2[i]);
			dest = pos1;
			while (*src)
				*dest++ = *src++;
			*dest = *src;  // copy the null;

			result = 1;
		}
    }

    strcpy(szOutput, in_name);

    CutSpaces(szOutput, in_name);

    if (strlen(in_name) == 0)  // is name just a tag?
    {
		strncpy(in_name, szName, 31);
		in_name[32] = 0;

		// strip just the tag part...
		for (i=0; i < MAX_TAGS; i++)
		{
			pos1=strstr(in_name, tag1[i]);
			if (pos1)
				pos2 = strstr(pos1+strlen(tag1[i]), tag2[i]);
			else
				pos2 = NULL;

			if (pos1 && pos2 && pos1 < pos2)
			{
				src = pos1 + strlen(tag1[i]);
				dest = pos1;
				while (*src)
					*dest++ = *src++;
				*dest = *src;  // copy the null;

				src = pos2 - strlen(tag2[i]);
				*src = 0; // null out the rest of the string
			}
		}
	}

    CutSpaces(in_name, szOutput);

    szOutput[31] = 0;

    return (result);
}

void CChatClass::SwapChars(const char *szSentence, char *szOutput)
{
	int len, pos;
    int count = 0;
    char temp;
    bool is_bad;

    strcpy(szOutput, szSentence);

    len = strlen(szOutput);
    pos = RANDOM_LONG(1, len-2);  // don't swap position zero

    is_bad = !isalpha(szOutput[pos]) || !isalpha(szOutput[pos+1]) || 
		     (szOutput[pos-1] == '%');

    while ((is_bad) && (count < 20))
    {
		pos = RANDOM_LONG(1, len-2);
		is_bad = !isalpha(szOutput[pos]) || !isalpha(szOutput[pos+1]) ||
			     (szOutput[pos-1] == '%');
        count++;
    }

    if (count < 20)
    {
		temp = szOutput[pos];
		szOutput[pos] = szOutput[pos+1];
		szOutput[pos+1] = temp;
    }
}

void CChatClass::DropChars(const char *szSentence, char *szOutput)
{
	int len, pos;
    int count = 0;
    char *src, *dest;
    bool is_bad;

    strcpy(szOutput, szSentence);

    len = strlen(szOutput);
    pos = RANDOM_LONG(1, len-1);  // don't drop position zero

    is_bad = !isalpha(szOutput[pos]) || (szOutput[pos-1] == '%');

    while ((is_bad) && (count < 20))
    {
		pos = RANDOM_LONG(1, len-1);
		is_bad = !isalpha(szOutput[pos]) || (szOutput[pos-1] == '%');
		count++;
    }

    if (count < 20)
    {
		src = &szOutput[pos+1];
		dest = &szOutput[pos];
		while (*src)
			*dest++ = *src++;
		*dest = *src;  // copy the null;
    }
}

void CChatClass::CutSpaces(const char *szInput, char *szOutput)
{
	int i, Pos;
    char *szDest;

    Pos = 0;
    while ((Pos < 80) && (szInput[Pos] == ' '))  // skip leading blanks
		Pos++;

    szDest = &szOutput[0];

    while ((Pos < 80) && (szInput[Pos]))
    {
		*szDest++ = szInput[Pos];
		Pos++;
    }
    *szDest = 0;  // store the null

    i = strlen(szOutput) - 1;
    while ((i > 0) && (szOutput[i] == ' '))  // remove trailing blanks
    {
		szOutput[i] = 0;
		i--;
    }
}

void CChatClass::StoreChatMsg(edict_t *pEntity, const char *szMsgText)
{
	if ((szMsgText) && (*szMsgText))
	{
		if ((OldChatTexts[0].szText) && (*OldChatTexts[0].szText) &&
			(FStrEq(szMsgText, OldChatTexts[0].szText)))
			return; // Don't store if already exist

		for (short j=(MAX_OLD_TEXTS_SAVED-1);j>0;j--)
			OldChatTexts[j] = OldChatTexts[j-1];

		OldChatTexts[0].flCreateTime = gpGlobals->time;
		strcpy(OldChatTexts[0].szText, szMsgText);
		strcpy(OldChatTexts[0].szSenderName, STRING(pEntity->v.netname));
	}
}

void CChatClass::StoreRecentUsedSentence(CChatSentence *VarToStore[], CChatSentence *pSentence)
{
	for (byte i = (MAX_RECENT_USED_TEXTS - 1);i>0;i--)
		VarToStore[i] = VarToStore[i-1];

	VarToStore[0] = pSentence;
}

CChatClass::CChatNode *CChatClass::GetChatNodeByKeyWord(TLinkedList<CChatNode *> *pChatNodeList,
											const char *szKeyWord)
{
	/*modified by harSens
	TLinkedList<CChatNode *>::node_s *pNode = pChatNodeList->GetFirst();
	*/
	node_s<CChatNode *> *pNode = pChatNodeList->GetFirst();
	while(pNode)
	{
		if ((pNode->Entry->KeyType != KEY_TYPE_KEYTOKEN) &&
			(stricmp(szKeyWord, pNode->Entry->szKeyStr) == 0))
			return pNode->Entry;

		pNode = pNode->next;
	}

	return NULL;
}

CChatClass::CChatNode *CChatClass::GetChatNodeByKeyToken(TLinkedList<CChatNode *> *pChatNodeList,
											const char KeyToken)
{
	/*modified by harSens
	TLinkedList<CChatNode *>::node_s *pNode = pChatNodeList->GetFirst();
	*/
	node_s<CChatNode *> *pNode = pChatNodeList->GetFirst();
	while(pNode)
	{
		if ((pNode->Entry->KeyType == KEY_TYPE_KEYTOKEN) &&
			(KeyToken == pNode->Entry->szKeyStr[0]))
			return pNode->Entry;

		pNode = pNode->next;
	}

	return NULL;
}

// Debug function(s)

void CChatClass::LogPrevMessages()
{
	for (int i=0;i<MAX_OLD_TEXTS_SAVED;i++)
	{
//		clog << "Prev msg nr " << i << " msg: " << OldChatTexts[i].szText << "\n";
//		clog << "Sender: " << OldChatTexts[i].szSenderName << " SendTime: " << OldChatTexts[i].flCreateTime << "\n";
	}
}

void CChatClass::LogChatLists()
{/*
	clog << "Logging welcome sentences...\n\n";
	pWelcomeSentences->pChatSentences->ForEach(this, &CChatClass::LogChatSentences);
	clog << "\nEnd node\n";
	clog << "Logging normal chat list...\n\n";
	pNormalChatNodeList->ForEach(this, &CChatClass::LogChatNode);
	clog << "\n\nTaunt Chat node list:\n\n";
	pTauntChatNodeList->ForEach(this, &CChatClass::LogChatNode);
	clog << "\n\nWhine Chat node list:\n\n";
	pWhineChatNodeList->ForEach(this, &CChatClass::LogChatNode);*/
}

void CChatClass::LogChatNode(CChatNode *pNode)
{/*
	if (pNode->KeyType == KEY_TYPE_KEYWORD)
		clog << "Node using keyword: " << pNode->szKeyStr << "\n";
	else if (pNode->KeyType == KEY_TYPE_KEYWORD2)
		clog << "Node using keyword2: " << pNode->szKeyStr << "\n";
	else
		clog << "Node using key token: " << pNode->szKeyStr[0] << "\n";

	clog << "Sentences of this node: \n\n";
	pNode->pChatSentences->ForEach(this, &CChatClass::LogChatSentences);
	clog << "\nEnd node\n";*/
}

void CChatClass::LogChatSentences(CChatSentence *pSentence)
{
//	clog << "Sentence: " << pSentence->szText << " CanModify: " << pSentence->CanModify << 
//		    " UV: " << pSentence->UseValue << "\n";
}

void CChatClass::PrintChatSentences()
{/*
	cout << "Welcome sentences:\n\n";
	pWelcomeSentences->pChatSentences->ForEach(this, &CChatClass::PrintChatSentence);
	cout << "\n\nNormal sentences\n\n";
	pNormalChatNodeList->ForEach(this, &CChatClass::PrintChatNode);
	cout << "\n\nTaunt sentences\n\n";
	pTauntChatNodeList->ForEach(this, &CChatClass::PrintChatNode);
	cout << "\n\nWhine sentences\n\n";
	pWhineChatNodeList->ForEach(this, &CChatClass::PrintChatNode);*/
}

void CChatClass::PrintChatNode(CChatNode *pNode)
{/*
	if (pNode->KeyType == KEY_TYPE_KEYWORD)
		cout << "Node using keyword: " << pNode->szKeyStr << "\n";
	else if (pNode->KeyType == KEY_TYPE_KEYWORD2)
		cout << "Node using keyword2: " << pNode->szKeyStr << "\n";
	else
		cout << "Node using key token: " << pNode->szKeyStr[0] << "\n";

	cout << "Sentences of this node: \n\n";
	pNode->pChatSentences->ForEach(this, &CChatClass::PrintChatSentence);
	cout << "\nEnd node\n";*/
}

void CChatClass::PrintChatSentence(CChatSentence *pSentence)
{
	cout << "Sentence: " << pSentence->szText << " CanModify: " << pSentence->CanModify << 
		    " UV: " << pSentence->UseValue << "\n";
}

// ===================================================
// Code of CChatClass End
// ===================================================
