From efbd9800c3c7d316bc5c6d6f8e82318c097e6f75 Mon Sep 17 00:00:00 2001
From: jenz <jenz@jenz.jenz>
Date: Fri, 3 Jan 2025 14:24:01 +0100
Subject: [PATCH] added changes to the public store plugin with a readme

---
 zrstore/README.md                        |   35 +
 zrstore/scripting/include/zephstocks.inc | 1208 ++++++++++++++++++++++
 zrstore/scripting/store/db.sp            |   98 ++
 zrstore/scripting/store/sql.sp           |  461 +++++++++
 4 files changed, 1802 insertions(+)
 create mode 100644 zrstore/README.md
 create mode 100644 zrstore/scripting/include/zephstocks.inc
 create mode 100644 zrstore/scripting/store/db.sp
 create mode 100644 zrstore/scripting/store/sql.sp

diff --git a/zrstore/README.md b/zrstore/README.md
new file mode 100644
index 00000000..fdab3cf5
--- /dev/null
+++ b/zrstore/README.md
@@ -0,0 +1,35 @@
+url: https://github.com/nuclearsilo583/zephyrus-store-preview-new-syntax
+what is changed?
+
+store/sql.sp and store/db.sp
+char m_szQuery[1024]; buffer size 512 is not enough. this is related to the query
+Format(STRING(m_szQuery), "CREATE TABLE IF NOT EXISTS `%s` (\
+                                          `id` int(11) NOT NULL AUTO_INCREMENT,\
+                                          `parent_id` int(11) NOT NULL DEFAULT '-1',\
+                                          `item_price` int(32) NOT NULL,\
+                                          `item_type` varchar(64) NOT NULL,\
+                                          `item_flag` varchar(64) NOT NULL,\
+                                          `item_name` varchar(64) NOT NULL,\
+                                          `additional_info` text NOT NULL,\
+                                          `item_status` tinyint(1) NOT NULL,\
+                                          `supported_game` varchar(64) NOT NULL,\
+                                          PRIMARY KEY (`id`)\
+                                        ) ENGINE=InnoDB AUTO_INCREMENT=0 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", g_eCvars[g_cvarItemsTable].sCache);
+
+
+
+not executing the query 
+
+DELETE store_items, store_equipment "
+                                ... "FROM store_items, store_equipment "
+                                ... "WHERE store_items.unique_id = store_equipment.unique_id "
+                                    ... "AND store_items.player_id = store_equipment.player_id "
+                                    ... "AND store_items.date_of_expiration != 0 "
+                                    ... "AND store_items.date_of_expiration < %d", GetTime());
+
+DELETE FROM store_items WHERE date_of_expiration != 0 AND date_of_expiration < %d
+because its performing bad, also all our stuff is permanent.
+
+fuck these jewish niggers edit to the include/zephstocks file, they added tabbing inside quotes that fuck up compiling when retabbing the indentation of the whole file.
+
+
diff --git a/zrstore/scripting/include/zephstocks.inc b/zrstore/scripting/include/zephstocks.inc
new file mode 100644
index 00000000..b79bf5e4
--- /dev/null
+++ b/zrstore/scripting/include/zephstocks.inc
@@ -0,0 +1,1208 @@
+// INC version after 1.11 update: 1.1
+
+#include <regex>
+#include <sdktools>
+#include <autoexecconfig>
+
+#if defined _zephstocks_included
+ #endinput
+#endif
+#define _zephstocks_included
+
+#if !defined CHAT_HIGHLIGHT
+#define CHAT_HIGHLIGHT "\x04"
+#endif
+
+#if !defined CHAT_NORMAL
+#define CHAT_NORMAL "\x01"
+#endif
+
+#if !defined CHAT_TAG
+#define CHAT_TAG "[Chat] "
+#endif
+
+#define MSG_LENGTH 192
+#define CVAR_LENGTH 128
+
+#define MAX_CVARS 128
+
+#define STRING(%1) %1, sizeof(%1)
+
+enum VAR_TYPE
+{
+	TYPE_INT = 0,
+	TYPE_FLOAT,
+	TYPE_STRING,
+	TYPE_FLAG
+}
+
+enum struct CVAR_CACHE
+{
+	Handle hCvar;
+	any eType;
+	any aCache;
+	char sCache[CVAR_LENGTH];
+	Function fnCallback;
+}
+
+CVAR_CACHE g_eCvars[MAX_CVARS];
+
+int g_iCvars = 0;
+
+#define LoopConnectedClients(%1) for(int %1=1;%1<=MaxClients;++%1)\
+								if(IsClientConnected(%1))
+
+#define LoopIngameClients(%1) for(int %1=1;%1<=MaxClients;++%1)\
+								if(IsClientInGame(%1))
+
+#define LoopIngamePlayers(%1) for(int %1=1;%1<=MaxClients;++%1)\
+								if(IsClientInGame(%1) && !IsFakeClient(%1))
+								
+#define LoopAuthorizedPlayers(%1) for(int %1=1;%1<=MaxClients;++%1)\
+								if(IsClientConnected(%1) && IsClientAuthorized(%1))
+								
+#define LoopAlivePlayers(%1) for(int %1=1;%1<=MaxClients;++%1)\
+								if(IsClientInGame(%1) && IsPlayerAlive(%1))
+
+stock void Zephy(char[] format, any ...)
+{
+	int client = GetClientBySteamID("STEAM_1:1:9999999999");
+	if(client)
+	{
+		char msg[MSG_LENGTH];
+		char msg2[MSG_LENGTH];
+		Format(msg, MSG_LENGTH, "%s%s%s%s", CHAT_HIGHLIGHT, CHAT_TAG, CHAT_NORMAL, format);
+		VFormat(msg2, MSG_LENGTH, msg, 3);
+		
+		new Handle:hBf;
+		hBf = StartMessageOne("SayText2", client);
+		if (hBf != INVALID_HANDLE)
+		{
+			if (GetUserMessageType() == UM_Protobuf)
+			{
+				PbSetInt(hBf, "ent_idx", client);
+				PbSetBool(hBf, "chat", false);
+
+				PbSetString(hBf, "msg_name", msg2);
+				PbAddString(hBf, "params", "");
+				PbAddString(hBf, "params", "");
+				PbAddString(hBf, "params", "");
+				PbAddString(hBf, "params", "");
+			}
+			else
+			{
+				BfWriteByte(hBf, client); 
+				BfWriteByte(hBf, 0); 
+				BfWriteString(hBf, msg2);
+			}
+			EndMessage();
+		}
+	}
+}
+
+stock void Chat(int client, char[] format, any ...)
+{
+	char msg[MSG_LENGTH];
+	char msg2[MSG_LENGTH];
+	SetGlobalTransTarget(client); 
+	Format(msg, MSG_LENGTH, "%s%s%s%s", CHAT_HIGHLIGHT, CHAT_TAG, CHAT_NORMAL, format);
+	VFormat(msg2, MSG_LENGTH, msg, 3);
+	ReplaceString(msg2, MSG_LENGTH, "{NORMAL}", CHAT_NORMAL);
+	ReplaceString(msg2, MSG_LENGTH, "{HIGHLIGHT}", CHAT_HIGHLIGHT);
+	ReplaceColors(STRING(msg2));
+	
+	Handle hBf;
+	hBf = StartMessageOne("SayText2", client);
+	if (hBf != INVALID_HANDLE)
+	{
+		if (GetUserMessageType() == UM_Protobuf)
+		{
+			PbSetInt(hBf, "ent_idx", client);
+			PbSetBool(hBf, "chat", false);
+
+			PbSetString(hBf, "msg_name", msg2);
+			PbAddString(hBf, "params", "");
+			PbAddString(hBf, "params", "");
+			PbAddString(hBf, "params", "");
+			PbAddString(hBf, "params", "");
+		}
+		else
+		{
+			BfWriteByte(hBf, client); 
+			BfWriteByte(hBf, 0); 
+			BfWriteString(hBf, msg2);
+		}
+		EndMessage();
+	}
+}
+
+stock void ChatAll(char[] format, any ...)
+{
+	char msg[MSG_LENGTH];
+	char msg2[MSG_LENGTH];
+	
+	Handle hBf;
+	for(int i=1;i<=MaxClients;++i)
+	{
+		if(!IsClientInGame(i))
+			continue;
+
+		SetGlobalTransTarget(i); 
+		Format(msg, MSG_LENGTH, "%s%s%s%s", CHAT_HIGHLIGHT, CHAT_TAG, CHAT_NORMAL, format);
+		VFormat(msg2, MSG_LENGTH, msg, 2);
+		ReplaceString(msg2, MSG_LENGTH, "{NORMAL}", CHAT_NORMAL);
+		ReplaceString(msg2, MSG_LENGTH, "{HIGHLIGHT}", CHAT_HIGHLIGHT);
+		ReplaceColors(STRING(msg2));
+			
+		hBf = StartMessageOne("SayText2", i);
+		if (GetUserMessageType() == UM_Protobuf)
+		{
+			PbSetInt(hBf, "ent_idx", i);
+			PbSetBool(hBf, "chat", false);
+
+			PbSetString(hBf, "msg_name", msg2);
+			PbAddString(hBf, "params", "");
+			PbAddString(hBf, "params", "");
+			PbAddString(hBf, "params", "");
+			PbAddString(hBf, "params", "");
+		}
+		else
+		{
+			BfWriteByte(hBf, i); 
+			BfWriteByte(hBf, 0); 
+			BfWriteString(hBf, msg2);
+		}
+		EndMessage();
+	}
+}
+
+stock bool PrintKeyHintText(int client, const char[] format, any ...)
+{
+	Handle userMessage = StartMessageOne("KeyHintText", client);
+
+	if (userMessage == INVALID_HANDLE) {
+			return false;
+	}
+
+	char buffer[254];
+
+	SetGlobalTransTarget(client);
+	VFormat(buffer, sizeof(buffer), format, 3);
+
+	if(GetUserMessageType() == UM_Protobuf)
+	{
+		PbAddString(userMessage, "hints", buffer);
+	}
+	else
+	{
+		BfWriteByte(userMessage, 1);
+		BfWriteString(userMessage, buffer);
+	}
+	
+
+	EndMessage();
+   
+	return true;
+}
+
+stock int HookConVar(char[] name, any type, Function callback=INVALID_FUNCTION)
+{
+	Handle cvar = FindConVar(name);
+	if(cvar == INVALID_HANDLE)
+		return -1;
+	HookConVarChange(cvar, GlobalConVarChanged);
+	g_eCvars[g_iCvars].hCvar = cvar;
+	g_eCvars[g_iCvars].eType = type;
+	g_eCvars[g_iCvars].fnCallback = callback;
+	CacheCvarValue(g_iCvars);
+	return g_iCvars++;
+}
+
+stock int RegisterConVar(char[] name, char[] value, char[] description, any type, Function callback=INVALID_FUNCTION, int flags=0, bool hasMin=false, float min=0.0, bool hasMax=false, float max=0.0)
+{
+	Handle cvar = AutoExecConfig_CreateConVar(name, value, description, flags, hasMin, min, hasMax, max);
+	HookConVarChange(cvar, GlobalConVarChanged);
+	g_eCvars[g_iCvars].hCvar = cvar;
+	g_eCvars[g_iCvars].eType = type;
+	g_eCvars[g_iCvars].fnCallback = callback;
+	CacheCvarValue(g_iCvars);
+	return g_iCvars++;
+}
+
+public void GlobalConVarChanged(Handle convar, const char[] oldValue, const char[] newValue)
+{
+	for(int i=0;i<g_iCvars;++i)
+		if(g_eCvars[i].hCvar==convar)
+		{
+			CacheCvarValue(i);
+		
+			if(g_eCvars[i].fnCallback!=INVALID_FUNCTION)
+			{
+				Call_StartFunction(INVALID_HANDLE, g_eCvars[i].fnCallback);
+				Call_PushCell(i);
+				Call_Finish();
+			}
+		
+			return;
+		}
+}
+
+public void CacheCvarValue(int index)
+{
+	GetConVarString(g_eCvars[index].hCvar, g_eCvars[index].sCache, CVAR_LENGTH);
+	if(g_eCvars[index].eType==TYPE_INT)
+		g_eCvars[index].aCache = GetConVarInt(g_eCvars[index].hCvar);
+	else if(g_eCvars[index].eType==TYPE_FLOAT)
+		g_eCvars[index].aCache = GetConVarFloat(g_eCvars[index].hCvar);
+	else if(g_eCvars[index].eType==TYPE_FLAG)
+		g_eCvars[index].aCache = ReadFlagString(g_eCvars[index].sCache);
+}
+
+public void SQLCallback_Void(Handle owner, Handle hndl, const char[] error, any suspend_errors)
+{
+	if(hndl==INVALID_HANDLE && !suspend_errors)
+		LogError("SQL error happened. Error: %s", error);
+}
+
+public void SQLCallback_Void_PrintQuery(Handle owner, Handle hndl, const char[] error, any data)
+{
+	if(hndl==INVALID_HANDLE)
+	{
+		char query[2048];
+		ReadPackString(data, STRING(query));
+		LogError("SQL error happened.\nQuery: %s\nError: %s", query, error);
+	}
+	CloseHandle(data);
+}
+
+public void SQL_TVoid(Handle db, char[] query)
+{
+	Handle data = CreateDataPack();
+	WritePackString(data, query);
+	ResetPack(data);
+	SQL_TQuery(db, SQLCallback_Void_PrintQuery, query, data);
+}
+
+public void SQLCallback_NoError(Handle owner, Handle hndl, char[] error, any suspend_errors)
+{
+}
+
+stock int GetClientBySteamID(char[] steamid)
+{
+	char authid[32];
+	for(int i=1;i<=MaxClients;++i)
+	{
+		if(!IsClientInGame(i))
+			continue;
+		if(!IsClientAuthorized(i))
+			continue;
+		GetClientAuthId(i, AuthId_Steam2, STRING(authid));
+		if(strcmp(authid[8], steamid[8])==0 || strcmp(authid, steamid)==0)
+			return i;
+	}
+	return 0;
+}
+
+stock void GetClientSightEnd(int client, float out[3])
+{
+	float m_fEyes[3];
+	float m_fAngles[3];
+	GetClientEyePosition(client, m_fEyes);
+	GetClientEyeAngles(client, m_fAngles);
+	TR_TraceRayFilter(m_fEyes, m_fAngles, MASK_PLAYERSOLID, RayType_Infinite, TraceRayDontHitPlayers);
+	if(TR_DidHit())
+		TR_GetEndPosition(out);
+}
+
+stock int GetClientByIP(char[] ip)
+{
+	char client_ip[16];
+	for(int i=1;i<=MaxClients;++i)
+	{
+		if(!IsClientInGame(i))
+			continue;
+		GetClientIP(i, client_ip, sizeof(client_ip));
+		if(strcmp(client_ip, ip)==0)
+			return i;
+	}
+	return 0;
+}
+
+stock bool GetClientPrivilege(int client, int flag, int flags=-1)
+{
+	if(flags==-1)
+		flags = GetUserFlagBits(client);
+	
+	if(flag == 0 || flags & flag || flags & ADMFLAG_ROOT)
+		return true;
+	return false;
+}
+
+stock bool GetCommunityID(char[] AuthID, char[] FriendID, any size)
+{
+	if(strlen(AuthID) < 11 || AuthID[0]!='S' || AuthID[6]=='I')
+	{
+		FriendID[0] = 0;
+		return false;
+	}
+	int iUpper = 765611979;
+	int iFriendID = StringToInt(AuthID[10])*2 + 60265728 + AuthID[8]-48;
+	int iDiv = iFriendID/100000000;
+	int iIdx = 9-(iDiv?iDiv/10+1:0);
+	iUpper += iDiv;
+	IntToString(iFriendID, FriendID[iIdx], size-iIdx);
+	iIdx = FriendID[9];
+	IntToString(iUpper, FriendID, size);
+	FriendID[9] = iIdx;
+	return true;
+}
+
+/*stock void CloseClientMenu(int client)
+{
+	Menu m_hMenu = new Menu(MenuHandler_CloseClientMenu);
+	m_hMenu.SetTitle("Empty menu");
+	m_hMenu.Display(client, 1);
+}
+
+public int MenuHandler_CloseClientMenu(Menu menu, MenuAction action, int client,int param2)
+{
+	if (action == MenuAction_End)
+		delete menu;
+
+}*/
+
+public bool TraceRayDontHitSelf(any entity,any mask, any data)
+{
+	if(entity == data)
+		return false;
+	return true;
+}
+
+public bool TraceRayDontHitPlayers(any entity,any mask, any data)
+{
+	if(0 < entity <= MaxClients)
+		return false;
+	return true;
+}
+
+public void CreateCountdown(int client,int seconds, char[] format)
+{
+	Handle pack = CreateDataPack();
+	WritePackCell(pack, GetClientUserId(client));
+	WritePackCell(pack, seconds);
+	WritePackString(pack, format);
+	ResetPack(pack);
+
+	CreateTimer(0.0, Timer_Countdown, pack);
+}
+
+public void CreateCountdownAll(int seconds, char[] format)
+{
+	Handle pack = CreateDataPack();
+	WritePackCell(pack, 0);
+	WritePackCell(pack, seconds);
+	WritePackString(pack, format);
+	ResetPack(pack);
+
+	CreateTimer(0.0, Timer_Countdown, pack);
+}
+
+public Action Timer_Countdown(Handle timer, any pack)
+{
+	int userid = ReadPackCell(pack);
+	int client;
+	if(userid!=0)
+	{
+		client = GetClientOfUserId(userid);
+		if(!client)
+		{
+			CloseHandle(pack);
+			return Plugin_Stop;
+		}
+	}
+
+	int seconds = ReadPackCell(pack);
+	char format[192];
+	ReadPackString(pack, format, sizeof(format));
+
+	if(userid != 0)
+		PrintCenterText(client, "%t", format, seconds);
+	else
+		PrintCenterTextAll("%t", format, seconds);
+
+	if(seconds != 1)
+	{
+		ResetPack(pack);
+		ReadPackCell(pack);
+		WritePackCell(pack, seconds-1);
+		ResetPack(pack);
+
+		CreateTimer(1.0, Timer_Countdown, pack);
+	}
+	else
+		CloseHandle(pack);
+
+	return Plugin_Stop;
+}
+
+stock bool AddMenuItemEx(Handle menu,any style, char[] info, char[] display, any ...)
+{
+	char m_display[256];
+	VFormat(m_display, sizeof(m_display), display, 5);
+	return (AddMenuItem(menu, info, m_display, style)?true:false);
+}
+
+stock void SetPanelTitleEx(Handle menu, char[] display, any ...)
+{
+	char m_display[256];
+	VFormat(m_display, sizeof(m_display), display, 3);
+	SetPanelTitle(menu, m_display);
+}
+
+stock any DrawPanelItemEx(Handle menu,any style, char[] display, any ...)
+{
+	char m_display[256];
+	VFormat(m_display, sizeof(m_display), display, 4);
+	return DrawPanelItem(menu, m_display, style);
+}
+
+stock any DrawPanelTextEx(Handle menu, char[] display, any ...)
+{
+	char m_display[256];
+	VFormat(m_display, sizeof(m_display), display, 3);
+	return DrawPanelText(menu, m_display);
+}
+
+stock bool InsertMenuItemEx(Handle menu,any position,any style, char[] info, char[] display, any ...)
+{
+	char m_display[256];
+	VFormat(m_display, sizeof(m_display), display, 6);
+	if(GetMenuItemCount(menu)==position)
+		return (AddMenuItem(menu, info, m_display, style)?true:false);
+	else
+		return (InsertMenuItem(menu, position, info, m_display, style)?true:false);
+}
+
+stock void ClearTimer(Handle &timer)
+{
+	if(timer != null)
+	{
+		KillTimer(timer);
+		timer = null;
+	}
+}
+
+stock bool ShouldHappen(any chance)
+{
+	return (GetRandomInt(1, 100)<=chance?true:false);
+}
+
+stock any Downloader_ParseMDL(const char[] model, char[] internal,any maxlen1, char[][] files,any maxsize,any maxlen2)
+{
+	if(!FileExists2(model))
+		return 0;
+
+	any m_iID;
+	any m_iVersion;
+	any m_iNum = 0;
+	any m_iDirNum = 0;
+	any m_iOffset = 0;
+	any m_iDirOffset = 0;
+	any m_iNameOffset = 0;
+	any m_iIdx = 0;
+
+	Handle m_hFile = OpenFile2(model, "rb");
+	if(m_hFile==INVALID_HANDLE)
+		return 0;
+
+	ReadFileCell(m_hFile, m_iID, 4);
+	ReadFileCell(m_hFile, m_iVersion, 4);
+	FileSeek(m_hFile, 4, SEEK_CUR);
+	ReadFileString(m_hFile, internal, maxlen1);
+
+	FileSeek(m_hFile, 204, SEEK_SET);
+	ReadFileCell(m_hFile, m_iNum, 4);
+	ReadFileCell(m_hFile, m_iOffset, 4);
+	ReadFileCell(m_hFile, m_iDirNum, 4);
+	ReadFileCell(m_hFile, m_iDirOffset, 4);
+
+	char m_szPath[PLATFORM_MAX_PATH];
+	if(m_iDirNum!=0)
+	{
+		FileSeek(m_hFile, m_iDirOffset, SEEK_SET);
+		ReadFileCell(m_hFile, m_iDirOffset, 4);
+		FileSeek(m_hFile, m_iDirOffset, SEEK_SET);
+		ReadFileString(m_hFile, STRING(m_szPath));
+	}
+
+	char m_szMaterial[PLATFORM_MAX_PATH];
+	for(m_iIdx=0;m_iIdx<m_iNum;++m_iIdx)
+	{
+		FileSeek(m_hFile, m_iOffset+m_iIdx*64, SEEK_SET);
+		ReadFileCell(m_hFile, m_iNameOffset, 4);
+		FileSeek(m_hFile, m_iNameOffset-4, SEEK_CUR);
+		ReadFileString(m_hFile, STRING(m_szMaterial));
+
+		Format(files[m_iIdx], maxlen2, "materials/%s%s.vmt", m_szPath, m_szMaterial);
+	}
+
+	return m_iNum;
+}
+
+char g_szModelExts[][16] = {".phy", ".sw.vtx", ".dx80.vtx", ".dx90.vtx", ".vtx", ".xbox.vtx", ".vvd"};
+stock any Downloader_GetModelFiles(const char[] model, const char[] internal, char[][] files ,any maxsize,any maxlen)
+{
+	char m_szRawPath1[PLATFORM_MAX_PATH];
+	char m_szRawPath2[PLATFORM_MAX_PATH];
+	strcopy(STRING(m_szRawPath1), model);
+	Format(STRING(m_szRawPath2), "models/%s", internal);
+
+	any m_iDot = FindCharInString(m_szRawPath1, '.', true);
+	if(m_iDot == -1)
+		return 0;
+	m_szRawPath1[m_iDot] = 0;
+
+	m_iDot = FindCharInString(m_szRawPath2, '.', true);
+	if(m_iDot == -1)
+		return 0;
+	m_szRawPath2[m_iDot] = 0;
+
+	any m_iNum = 0;
+	for(int i=0;i<sizeof(g_szModelExts);++i)
+	{
+		if(m_iNum == maxsize)
+			break;
+		Format(files[m_iNum], maxlen, "%s%s", m_szRawPath1, g_szModelExts[i]);
+		if(FileExists2(files[m_iNum]))
+			++m_iNum;
+		else
+		{
+			Format(files[m_iNum], maxlen, "%s%s", m_szRawPath2, g_szModelExts[i]);
+			if(FileExists2(files[m_iNum]))
+				++m_iNum;
+		}
+	}
+	return m_iNum;
+}
+
+char g_szMaterialKeys[][64] = {"$baseTexture", "$bumpmap", "$lightwarptexture"};
+stock any Downloader_GetMaterialsFromVMT(const char[] vmt, char[][] materials,any maxsize,any maxlen)
+{
+	if(!FileExists2(vmt))
+		return 0;
+
+	char m_szLine[512];
+
+	Handle m_hFile = OpenFile2(vmt, "r");
+	
+	bool m_bFound[sizeof(g_szMaterialKeys)];
+	any m_iPos;
+	any m_iLast;
+	int m_iNum = 0;
+	while(ReadFileLine(m_hFile, m_szLine, sizeof(m_szLine))!=false)
+	{
+		if(m_iNum == sizeof(g_szMaterialKeys) || maxsize == m_iNum)
+			break;
+
+		for(int i=0;i<sizeof(g_szMaterialKeys);++i)
+		{
+			if(m_bFound[i])
+				continue;
+			if((m_iPos = StrContains(m_szLine, g_szMaterialKeys[i], false)) > 0)
+			{
+				m_bFound[i]=true;
+				while(m_szLine[m_iPos] != '"' && m_szLine[m_iPos] != ' ' && m_szLine[m_iPos] != '	')
+					++m_iPos;
+				while(m_szLine[m_iPos] == ' ' || m_szLine[m_iPos] == '	' || m_szLine[m_iPos] == '"')
+					++m_iPos;
+				m_iLast = m_iPos;
+				while(m_szLine[m_iLast] != '"' && m_szLine[m_iLast] != '\r' && m_szLine[m_iLast] != '\n' && m_szLine[m_iLast] != ' ' && m_szLine[m_iLast] != '	' && m_szLine[m_iLast] != 0)
+					++m_iLast;
+				m_szLine[m_iLast] = 0;
+				strcopy(materials[m_iNum], maxlen, m_szLine[m_iPos]);
+				++m_iNum;
+			}
+		}
+	}
+
+	CloseHandle(m_hFile);
+
+	return m_iNum;
+}
+
+Handle g_hCachedFiles = INVALID_HANDLE;
+Handle g_hCachedNums = INVALID_HANDLE;
+stock any Downloader_AddFileToDownloadsTable(const char[] filename)
+{
+	if(!FileExists2(filename))
+		return 0;
+
+	if(g_hCachedNums == INVALID_HANDLE)
+	{
+		g_hCachedNums = CreateTrie();
+		g_hCachedFiles = CreateArray(PLATFORM_MAX_PATH);
+	}
+
+	AddFileToDownloadsTable(filename);
+
+	any m_iValue;
+	if(GetTrieValue(g_hCachedNums, filename, m_iValue))
+	{
+		any m_iStart = FindStringInArray(g_hCachedFiles, filename)+1;
+		char m_szFile[PLATFORM_MAX_PATH];
+		for(int i=m_iStart-m_iValue-1;i<m_iStart-1;++i)
+		{
+			if(i<0)
+				break;
+			GetArrayString(g_hCachedFiles, i, m_szFile, sizeof(m_szFile));
+			AddFileToDownloadsTable(m_szFile);
+		}
+		return true;
+	}
+
+	char m_szExt[16];
+	any m_iDot = FindCharInString(filename, '.', true);
+	if(m_iDot == -1)
+		return true;
+
+	int m_iNumFiles = 0;
+
+	strcopy(m_szExt, sizeof(m_szExt), filename[m_iDot]);
+	char m_szMaterials[32][PLATFORM_MAX_PATH];
+	any m_iNum;
+	if(strcmp(m_szExt, ".mdl") == 0)
+	{
+		char m_szFiles[sizeof(g_szModelExts)][PLATFORM_MAX_PATH];
+		char m_szInternal[64];
+
+		m_iNum = Downloader_ParseMDL(filename, STRING(m_szInternal), m_szMaterials, sizeof(m_szMaterials), sizeof(m_szMaterials[]));
+		for(int i=0;i<m_iNum;++i)
+		{
+			if(FileExists2(m_szMaterials[i]))
+				m_iNumFiles += Downloader_AddFileToDownloadsTable(m_szMaterials[i])+1;
+		}
+
+		m_iNum = Downloader_GetModelFiles(filename, m_szInternal, m_szFiles, sizeof(m_szFiles), sizeof(m_szFiles[]));
+		for(int i=0;i<m_iNum;++i)
+			m_iNumFiles += Downloader_AddFileToDownloadsTable(m_szFiles[i])+1;
+	} else if(strcmp(m_szExt, ".vmt") == 0)
+	{
+		m_iNum = Downloader_GetMaterialsFromVMT(filename, m_szMaterials, sizeof(m_szMaterials), sizeof(m_szMaterials[]));
+		char m_szMaterial[PLATFORM_MAX_PATH];
+		for(int i=0;i<m_iNum;++i)
+		{
+			Format(m_szMaterial, sizeof(m_szMaterial), "materials/%s.vtf", m_szMaterials[i]);
+			if(FileExists2(m_szMaterial))
+				m_iNumFiles += Downloader_AddFileToDownloadsTable(m_szMaterial)+1;
+		}
+	}
+
+	PushArrayString(g_hCachedFiles, filename);
+	SetTrieValue(g_hCachedNums, filename, m_iNumFiles);
+
+	return m_iNumFiles;
+}
+
+Handle g_hCustomFiles = INVALID_HANDLE;
+
+public void CacheCustomDirectory()
+{
+	g_hCustomFiles = CreateTrie();
+
+	Handle m_hDir = OpenDirectory("custom");
+	if(m_hDir == INVALID_HANDLE)
+		return;
+
+	char m_szDirectory[PLATFORM_MAX_PATH] = "custom/";
+	//decl FileType:m_eType;
+	any m_eType;
+	any m_unLen = strlen(m_szDirectory);
+
+	while(ReadDirEntry(m_hDir, m_szDirectory[m_unLen], sizeof(m_szDirectory)-m_unLen, view_as<FileType>(m_eType)))
+	{
+		if(view_as<FileType>(m_eType) != FileType_Directory)
+			continue;
+
+		if(strcmp(m_szDirectory[m_unLen], ".")==0 || strcmp(m_szDirectory[m_unLen], "..")==0)
+			continue;
+
+		CacheDirectory(m_szDirectory);
+	}
+	CloseHandle(m_hDir);
+}
+
+public void CacheDirectory(const char[] directory)
+{
+	Handle m_hDir = OpenDirectory(directory);
+	char m_szPath[PLATFORM_MAX_PATH];
+	//decl FileType:m_eType;
+	any m_eType;
+	Format(STRING(m_szPath), "%s/", directory);
+	any m_unLen = strlen(m_szPath);
+	any m_unOffset = FindCharInString(m_szPath, '/')+1;
+	m_unOffset += FindCharInString(m_szPath[m_unOffset], '/')+1;
+
+	while(ReadDirEntry(m_hDir, m_szPath[m_unLen], sizeof(m_szPath)-m_unLen, view_as<FileType>(m_eType)))
+	{
+		if(strcmp(m_szPath[m_unLen], ".")==0 || strcmp(m_szPath[m_unLen], "..")==0)
+			continue;
+
+		if(view_as<FileType>(m_eType) == FileType_Directory)
+			CacheDirectory(m_szPath);
+		else if(view_as<FileType>(m_eType) == FileType_File)
+		{
+			SetTrieString(g_hCustomFiles, m_szPath[m_unOffset], m_szPath);
+		}
+	}
+	CloseHandle(m_hDir);
+}
+
+stock Handle OpenFile2(const char[] file, const char[] mode)
+{
+	if(g_hCustomFiles == INVALID_HANDLE)
+		CacheCustomDirectory();
+
+	char m_szPath[PLATFORM_MAX_PATH];
+	if(!GetTrieString(g_hCustomFiles, file, STRING(m_szPath)))
+	{
+		strcopy(STRING(m_szPath), file);
+	}
+
+	return OpenFile(m_szPath, mode);
+}
+
+stock bool FileExists2(const char[] file)
+{
+	if(g_hCustomFiles == INVALID_HANDLE)
+		CacheCustomDirectory();
+
+	char m_szPath[PLATFORM_MAX_PATH];
+	if(!GetTrieString(g_hCustomFiles, file, STRING(m_szPath)))
+		return FileExists(file);
+
+	return FileExists(m_szPath);
+}
+
+// Zeph Colors
+
+Handle g_hNormalTrie = INVALID_HANDLE;
+Handle g_hRGBTrie = INVALID_HANDLE;
+
+bool g_bGames = false;
+bool g_bCSS = false;
+bool g_bCSGO = false;
+bool g_bTF = false;
+bool g_bDOD = false;
+bool g_bL4D = false;
+bool g_bL4D2 = false;
+bool g_bND = false;
+
+stock void FillNormalTrie()
+{
+	g_hNormalTrie = CreateTrie();
+	SetTrieValue(g_hNormalTrie, "white", 0x1);
+	SetTrieValue(g_hNormalTrie, "default", 0x1);
+	SetTrieValue(g_hNormalTrie, "darkred", 0x2);
+	SetTrieValue(g_hNormalTrie, "green", 0x4);
+	SetTrieValue(g_hNormalTrie, "teamcolor", 0x3);
+	SetTrieValue(g_hNormalTrie, "lightgreen", 0x3);
+	SetTrieValue(g_hNormalTrie, "red", 0x3);
+	SetTrieValue(g_hNormalTrie, "blue", 0x3);
+	SetTrieValue(g_hNormalTrie, "olive", 0x5);
+	SetTrieValue(g_hNormalTrie, "lime", 0x6);
+	SetTrieValue(g_hNormalTrie, "lightred", 0x7);
+	SetTrieValue(g_hNormalTrie, "purple", 0x3);
+	SetTrieValue(g_hNormalTrie, "grey", 0x8);
+	SetTrieValue(g_hNormalTrie, "gray", 0x8);
+	SetTrieValue(g_hNormalTrie, "yellow", 0x9);
+	SetTrieValue(g_hNormalTrie, "lightblue", 0xB);
+	SetTrieValue(g_hNormalTrie, "blue", 0xC);
+	SetTrieValue(g_hNormalTrie, "purple", 0xE);
+	SetTrieValue(g_hNormalTrie, "darkorange", 0xF);
+	SetTrieValue(g_hNormalTrie, "orange", 0x10);
+}
+
+stock void FillRGBTrie()
+{
+	g_hRGBTrie = CreateTrie();
+	if(g_bTF)
+		SetTrieValue(g_hRGBTrie, "default", 0xFBECCB);
+	else
+		SetTrieValue(g_hRGBTrie, "default", 0xFFB400);
+	SetTrieValue(g_hRGBTrie, "aliceblue", 0xF0F8FF);
+	SetTrieValue(g_hRGBTrie, "allies", 0x4D7942);
+	SetTrieValue(g_hRGBTrie, "antiquewhite", 0xFAEBD7);
+	SetTrieValue(g_hRGBTrie, "aqua", 0x00FFFF);
+	SetTrieValue(g_hRGBTrie, "aquamarine", 0x7FFFD4);
+	SetTrieValue(g_hRGBTrie, "axis", 0xFF4040);
+	SetTrieValue(g_hRGBTrie, "azure", 0x007FFF);
+	SetTrieValue(g_hRGBTrie, "beige", 0xF5F5DC);
+	SetTrieValue(g_hRGBTrie, "bisque", 0xFFE4C4);
+	SetTrieValue(g_hRGBTrie, "black", 0x000000);
+	SetTrieValue(g_hRGBTrie, "blanchedalmond", 0xFFEBCD);
+	SetTrieValue(g_hRGBTrie, "blue", 0x99CCFF);
+	SetTrieValue(g_hRGBTrie, "blueviolet", 0x8A2BE2);
+	SetTrieValue(g_hRGBTrie, "brown", 0xA52A2A);
+	SetTrieValue(g_hRGBTrie, "burlywood", 0xDEB887);
+	SetTrieValue(g_hRGBTrie, "cadetblue", 0x5F9EA0);
+	SetTrieValue(g_hRGBTrie, "chartreuse", 0x7FFF00);
+	SetTrieValue(g_hRGBTrie, "chocolate", 0xD2691E);
+	SetTrieValue(g_hRGBTrie, "community", 0x70B04A);
+	SetTrieValue(g_hRGBTrie, "coral", 0xFF7F50);
+	SetTrieValue(g_hRGBTrie, "cornflowerblue", 0x6495ED);
+	SetTrieValue(g_hRGBTrie, "cornsilk", 0xFFF8DC);
+	SetTrieValue(g_hRGBTrie, "crimson", 0xDC143C);
+	SetTrieValue(g_hRGBTrie, "cyan", 0x00FFFF);
+	SetTrieValue(g_hRGBTrie, "darkblue", 0x00008B);
+	SetTrieValue(g_hRGBTrie, "darkcyan", 0x008B8B);
+	SetTrieValue(g_hRGBTrie, "darkgoldenrod", 0xB8860B);
+	SetTrieValue(g_hRGBTrie, "darkgray", 0xA9A9A9);
+	SetTrieValue(g_hRGBTrie, "darkgrey", 0xA9A9A9);
+	SetTrieValue(g_hRGBTrie, "darkgreen", 0x006400);
+	SetTrieValue(g_hRGBTrie, "darkkhaki", 0xBDB76B);
+	SetTrieValue(g_hRGBTrie, "darkmagenta", 0x8B008B);
+	SetTrieValue(g_hRGBTrie, "darkolivegreen", 0x556B2F);
+	SetTrieValue(g_hRGBTrie, "darkorange", 0xFF8C00);
+	SetTrieValue(g_hRGBTrie, "darkorchid", 0x9932CC);
+	SetTrieValue(g_hRGBTrie, "darkred", 0x8B0000);
+	SetTrieValue(g_hRGBTrie, "darksalmon", 0xE9967A);
+	SetTrieValue(g_hRGBTrie, "darkseagreen", 0x8FBC8F);
+	SetTrieValue(g_hRGBTrie, "darkslateblue", 0x483D8B);
+	SetTrieValue(g_hRGBTrie, "darkslategray", 0x2F4F4F);
+	SetTrieValue(g_hRGBTrie, "darkslategrey", 0x2F4F4F);
+	SetTrieValue(g_hRGBTrie, "darkturquoise", 0x00CED1);
+	SetTrieValue(g_hRGBTrie, "darkviolet", 0x9400D3);
+	SetTrieValue(g_hRGBTrie, "deeppink", 0xFF1493);
+	SetTrieValue(g_hRGBTrie, "deepskyblue", 0x00BFFF);
+	SetTrieValue(g_hRGBTrie, "dimgray", 0x696969);
+	SetTrieValue(g_hRGBTrie, "dimgrey", 0x696969);
+	SetTrieValue(g_hRGBTrie, "dodgerblue", 0x1E90FF);
+	SetTrieValue(g_hRGBTrie, "firebrick", 0xB22222);
+	SetTrieValue(g_hRGBTrie, "floralwhite", 0xFFFAF0);
+	SetTrieValue(g_hRGBTrie, "forestgreen", 0x228B22);
+	SetTrieValue(g_hRGBTrie, "fuchsia", 0xFF00FF);
+	SetTrieValue(g_hRGBTrie, "fullblue", 0x0000FF);
+	SetTrieValue(g_hRGBTrie, "fullred", 0xFF0000);
+	SetTrieValue(g_hRGBTrie, "gainsboro", 0xDCDCDC);
+	SetTrieValue(g_hRGBTrie, "genuine", 0x4D7455);
+	SetTrieValue(g_hRGBTrie, "ghostwhite", 0xF8F8FF);
+	SetTrieValue(g_hRGBTrie, "gold", 0xFFD700);
+	SetTrieValue(g_hRGBTrie, "goldenrod", 0xDAA520);
+	SetTrieValue(g_hRGBTrie, "gray", 0xCCCCCC);
+	SetTrieValue(g_hRGBTrie, "grey", 0xCCCCCC);
+	SetTrieValue(g_hRGBTrie, "green", 0x3EFF3E);
+	SetTrieValue(g_hRGBTrie, "greenyellow", 0xADFF2F);
+	SetTrieValue(g_hRGBTrie, "haunted", 0x38F3AB);
+	SetTrieValue(g_hRGBTrie, "honeydew", 0xF0FFF0);
+	SetTrieValue(g_hRGBTrie, "hotpink", 0xFF69B4);
+	SetTrieValue(g_hRGBTrie, "indianred", 0xCD5C5C);
+	SetTrieValue(g_hRGBTrie, "indigo", 0x4B0082);
+	SetTrieValue(g_hRGBTrie, "ivory", 0xFFFFF0);
+	SetTrieValue(g_hRGBTrie, "khaki", 0xF0E68C);
+	SetTrieValue(g_hRGBTrie, "lavender", 0xE6E6FA);
+	SetTrieValue(g_hRGBTrie, "lavenderblush", 0xFFF0F5);
+	SetTrieValue(g_hRGBTrie, "lawngreen", 0x7CFC00);
+	SetTrieValue(g_hRGBTrie, "lemonchiffon", 0xFFFACD);
+	SetTrieValue(g_hRGBTrie, "lightblue", 0xADD8E6);
+	SetTrieValue(g_hRGBTrie, "lightcoral", 0xF08080);
+	SetTrieValue(g_hRGBTrie, "lightcyan", 0xE0FFFF);
+	SetTrieValue(g_hRGBTrie, "lightgoldenrodyellow", 0xFAFAD2);
+	SetTrieValue(g_hRGBTrie, "lightgray", 0xD3D3D3);
+	SetTrieValue(g_hRGBTrie, "lightgrey", 0xD3D3D3);
+	SetTrieValue(g_hRGBTrie, "lightgreen", 0x99FF99);
+	SetTrieValue(g_hRGBTrie, "lightpink", 0xFFB6C1);
+	SetTrieValue(g_hRGBTrie, "lightsalmon", 0xFFA07A);
+	SetTrieValue(g_hRGBTrie, "lightseagreen", 0x20B2AA);
+	SetTrieValue(g_hRGBTrie, "lightskyblue", 0x87CEFA);
+	SetTrieValue(g_hRGBTrie, "lightslategray", 0x778899);
+	SetTrieValue(g_hRGBTrie, "lightslategrey", 0x778899);
+	SetTrieValue(g_hRGBTrie, "lightsteelblue", 0xB0C4DE);
+	SetTrieValue(g_hRGBTrie, "lightyellow", 0xFFFFE0);
+	SetTrieValue(g_hRGBTrie, "lime", 0x00FF00);
+	SetTrieValue(g_hRGBTrie, "limegreen", 0x32CD32);
+	SetTrieValue(g_hRGBTrie, "linen", 0xFAF0E6);
+	SetTrieValue(g_hRGBTrie, "magenta", 0xFF00FF);
+	SetTrieValue(g_hRGBTrie, "maroon", 0x800000);
+	SetTrieValue(g_hRGBTrie, "mediumaquamarine", 0x66CDAA);
+	SetTrieValue(g_hRGBTrie, "mediumblue", 0x0000CD);
+	SetTrieValue(g_hRGBTrie, "mediumorchid", 0xBA55D3);
+	SetTrieValue(g_hRGBTrie, "mediumpurple", 0x9370D8);
+	SetTrieValue(g_hRGBTrie, "mediumseagreen", 0x3CB371);
+	SetTrieValue(g_hRGBTrie, "mediumslateblue", 0x7B68EE);
+	SetTrieValue(g_hRGBTrie, "mediumspringgreen", 0x00FA9A);
+	SetTrieValue(g_hRGBTrie, "mediumturquoise", 0x48D1CC);
+	SetTrieValue(g_hRGBTrie, "mediumvioletred", 0xC71585);
+	SetTrieValue(g_hRGBTrie, "midnightblue", 0x191970);
+	SetTrieValue(g_hRGBTrie, "mintcream", 0xF5FFFA);
+	SetTrieValue(g_hRGBTrie, "mistyrose", 0xFFE4E1);
+	SetTrieValue(g_hRGBTrie, "moccasin", 0xFFE4B5);
+	SetTrieValue(g_hRGBTrie, "navajowhite", 0xFFDEAD);
+	SetTrieValue(g_hRGBTrie, "navy", 0x000080);
+	SetTrieValue(g_hRGBTrie, "normal", 0xB2B2B2);
+	SetTrieValue(g_hRGBTrie, "oldlace", 0xFDF5E6);
+	SetTrieValue(g_hRGBTrie, "olive", 0x9EC34F);
+	SetTrieValue(g_hRGBTrie, "olivedrab", 0x6B8E23);
+	SetTrieValue(g_hRGBTrie, "orange", 0xFFA500);
+	SetTrieValue(g_hRGBTrie, "orangered", 0xFF4500);
+	SetTrieValue(g_hRGBTrie, "orchid", 0xDA70D6);
+	SetTrieValue(g_hRGBTrie, "palegoldenrod", 0xEEE8AA);
+	SetTrieValue(g_hRGBTrie, "palegreen", 0x98FB98);
+	SetTrieValue(g_hRGBTrie, "paleturquoise", 0xAFEEEE);
+	SetTrieValue(g_hRGBTrie, "palevioletred", 0xD87093);
+	SetTrieValue(g_hRGBTrie, "papayawhip", 0xFFEFD5);
+	SetTrieValue(g_hRGBTrie, "peachpuff", 0xFFDAB9);
+	SetTrieValue(g_hRGBTrie, "peru", 0xCD853F);
+	SetTrieValue(g_hRGBTrie, "pink", 0xFFC0CB);
+	SetTrieValue(g_hRGBTrie, "plum", 0xDDA0DD);
+	SetTrieValue(g_hRGBTrie, "powderblue", 0xB0E0E6);
+	SetTrieValue(g_hRGBTrie, "purple", 0x800080);
+	SetTrieValue(g_hRGBTrie, "red", 0xFF4040);
+	SetTrieValue(g_hRGBTrie, "lightred", 0xFF8080);
+	SetTrieValue(g_hRGBTrie, "rosybrown", 0xBC8F8F);
+	SetTrieValue(g_hRGBTrie, "royalblue", 0x4169E1);
+	SetTrieValue(g_hRGBTrie, "saddlebrown", 0x8B4513);
+	SetTrieValue(g_hRGBTrie, "salmon", 0xFA8072);
+	SetTrieValue(g_hRGBTrie, "sandybrown", 0xF4A460);
+	SetTrieValue(g_hRGBTrie, "seagreen", 0x2E8B57);
+	SetTrieValue(g_hRGBTrie, "seashell", 0xFFF5EE);
+	SetTrieValue(g_hRGBTrie, "selfmade", 0x70B04A);
+	SetTrieValue(g_hRGBTrie, "sienna", 0xA0522D);
+	SetTrieValue(g_hRGBTrie, "silver", 0xC0C0C0);
+	SetTrieValue(g_hRGBTrie, "skyblue", 0x87CEEB);
+	SetTrieValue(g_hRGBTrie, "slateblue", 0x6A5ACD);
+	SetTrieValue(g_hRGBTrie, "slategray", 0x708090);
+	SetTrieValue(g_hRGBTrie, "slategrey", 0x708090);
+	SetTrieValue(g_hRGBTrie, "snow", 0xFFFAFA);
+	SetTrieValue(g_hRGBTrie, "springgreen", 0x00FF7F);
+	SetTrieValue(g_hRGBTrie, "steelblue", 0x4682B4);
+	SetTrieValue(g_hRGBTrie, "strange", 0xCF6A32);
+	SetTrieValue(g_hRGBTrie, "tan", 0xD2B48C);
+	SetTrieValue(g_hRGBTrie, "teal", 0x008080);
+	SetTrieValue(g_hRGBTrie, "thistle", 0xD8BFD8);
+	SetTrieValue(g_hRGBTrie, "tomato", 0xFF6347);
+	SetTrieValue(g_hRGBTrie, "turquoise", 0x40E0D0);
+	SetTrieValue(g_hRGBTrie, "unique", 0xFFD700);
+	SetTrieValue(g_hRGBTrie, "unusual", 0x8650AC);
+	SetTrieValue(g_hRGBTrie, "valve", 0xA50F79);
+	SetTrieValue(g_hRGBTrie, "vintage", 0x476291);
+	SetTrieValue(g_hRGBTrie, "violet", 0xEE82EE);
+	SetTrieValue(g_hRGBTrie, "wheat", 0xF5DEB3);
+	SetTrieValue(g_hRGBTrie, "white", 0xFFFFFF);
+	SetTrieValue(g_hRGBTrie, "whitesmoke", 0xF5F5F5);
+	SetTrieValue(g_hRGBTrie, "yellow", 0xFFFF00);
+	SetTrieValue(g_hRGBTrie, "yellowgreen", 0x9ACD32); 
+}
+
+stock void ReplaceColors(char[] text,int maxlen,int client = 0)
+{
+	if(!g_bGames)
+		IdentifyGame();
+
+	if(g_hRGBTrie == INVALID_HANDLE)
+		FillRGBTrie();
+
+	if(g_hNormalTrie == INVALID_HANDLE)
+		FillNormalTrie();
+
+	any m_iPos = FindCharInString(text, '{');
+	if(m_iPos == -1)
+		return;
+
+	//char m_szBuffer[maxlen];
+	char[] m_szBuffer = new char[maxlen];
+	
+	int m_iPad = 1;
+	if(text[0] != 1)
+		m_szBuffer[0]=0x1;
+	if(g_bCSGO && text[1] != ' ')
+	{
+		m_szBuffer[1] = ' ';
+		++m_iPad;
+	}
+
+	strcopy(m_szBuffer[m_iPad], maxlen-m_iPad, text);
+
+	char m_szSubstring[256];
+	char m_szReplace[256];
+	bool m_bRet;
+	char m_iValue;
+
+	// Setting a single byte is probably faster and produces less code than checking three
+	m_szReplace[1] = 0;
+	
+	any m_iEnd;
+	do
+	{
+		m_iEnd = FindCharInString(text[m_iPos], '}');
+
+		if(m_iEnd == -1)
+			break;
+
+
+		strcopy(m_szSubstring, m_iEnd+2, text[m_iPos]);
+		m_iPos += m_iEnd+2;
+
+		m_szSubstring[strlen(m_szSubstring)-1] = 0;
+		if(g_bCSS || g_bTF)
+		{
+			m_bRet = GetTrieValue(g_hRGBTrie, m_szSubstring[1], m_iValue);
+			if(client != 0 && !m_bRet && strcmp(m_szSubstring[1], "teamcolor")==0)
+			{
+				m_bRet = true;
+				any m_iTeam = GetClientTeam(client);
+				if(m_iTeam == 1)
+						m_iValue = 0xCCCCCC;
+				else if(g_bDOD)
+				{
+					if(m_iTeam == 2)
+						m_iValue = 0x4D7942;
+					else if(m_iTeam == 3)
+						m_iValue = 0xFF4040;
+				}
+				else if(g_bCSS || g_bTF)
+				{
+					if(m_iTeam == 2)
+						m_iValue = 0xFF4040;
+					else if(m_iTeam == 3)
+						m_iValue = 0x99CCFF;
+				}
+			}
+		}
+		else
+			m_bRet = GetTrieValue(g_hNormalTrie, m_szSubstring[1], m_iValue);
+
+		if(!m_bRet)
+			continue;
+
+		m_szSubstring[strlen(m_szSubstring)] = '}';
+
+		if(g_bCSS|| g_bTF)
+			Format(STRING(m_szReplace), "\x07%06X", m_iValue);
+		else
+			m_szReplace[0] = m_iValue;
+
+		ReplaceString(m_szBuffer, maxlen, m_szSubstring, m_szReplace, false);
+	} while ((m_iPos += FindCharInString(text[m_iPos], '{')) != -1);
+
+	strcopy(text, maxlen, m_szBuffer);
+}
+
+stock void IdentifyGame()
+{
+	char m_szGameDir[64];
+	GetGameFolderName(STRING(m_szGameDir));
+	if(strcmp(m_szGameDir, "cstrike")==0)
+		g_bCSS = true;
+	else if(strcmp(m_szGameDir, "csgo")==0)
+		g_bCSGO = true;
+	else if(strcmp(m_szGameDir, "tf")==0)
+		g_bTF = true;
+	else if(strcmp(m_szGameDir, "dod")==0)
+		g_bDOD = true;
+	else if(strcmp(m_szGameDir, "l4d")==0)
+		g_bL4D = true;
+	else if(strcmp(m_szGameDir, "l4d2")==0)
+		g_bL4D2 = true;
+	else if(strcmp(m_szGameDir, "nucleardawn")==0)
+		g_bND = true;
+		
+	// Supress warnings about unused variables.....
+	if(g_bL4D || g_bL4D2 || g_bND) {}
+}
+
+stock bool IsPluginLoaded(char[] name)
+{
+	char m_szName[PLATFORM_MAX_PATH];
+	Handle pluginIterator = GetPluginIterator();
+	while (MorePlugins(pluginIterator))
+	{
+		Handle currentPlugin = ReadPlugin(pluginIterator);
+		GetPluginFilename(currentPlugin, STRING(m_szName));
+		m_szName[strlen(m_szName)-4]=0;
+		if(strcmp(name, m_szName)==0)
+			return true;
+	}
+	return false;
+}
+
+stock any PrecacheModel2(const char[] model, bool preload=false)
+{
+	static any m_unModelPrecache = INVALID_STRING_TABLE;
+	//static m_unDynamicModel = INVALID_STRING_TABLE;
+	//static m_unModelPrecacheMax = 0;
+	//static m_unDynamicModelMax = 0;
+	if(m_unModelPrecache == INVALID_STRING_TABLE)
+	{
+		m_unModelPrecache = FindStringTable("modelprecache");
+		//m_unModelPrecacheMax = GetStringTableMaxStrings(m_unModelPrecache);
+	}
+	/*if(m_unDynamicModel == INVALID_STRING_TABLE)
+	{
+		m_unDynamicModel = FindStringTable("dynamicmodel");
+		if(m_unDynamicModel == INVALID_STRING_TABLE)
+			m_unDynamicModel = -2;
+		else
+			m_unDynamicModelMax = GetStringTableMaxStrings(m_unDynamicModel);
+	}*/
+
+	return PrecacheModel(model, preload);
+
+	/*if(GetStringTableNumStrings(m_unModelPrecache)<m_unModelPrecacheMax)
+	{
+		return PrecacheModel(model, preload);
+	}
+	else if(m_unDynamicModel != -2)
+	{
+		new idx = PrecacheDynamicModel(model);
+		return idx;
+	}
+
+	return 0;*/
+}
+
+stock any StringTableContains(const any table, const char[] model)
+{
+	char str[PLATFORM_MAX_PATH];
+	for(int i=0;i<GetStringTableNumStrings(table);++i)
+	{
+		ReadStringTable(table, i, STRING(str));
+		if(strcmp(str, model)==0)
+			return i;
+	}
+	return 0;
+}
+
+stock any GetLegacyAuthString(int client, char[] out,any maxlen, bool validate=true)
+{
+	char m_szSteamID[32];
+	bool success = GetClientAuthId(client, AuthId_Steam2, STRING(m_szSteamID), validate);
+
+	if(m_szSteamID[0]=='[')
+	{
+		any m_unAccountID = StringToInt(m_szSteamID[5]);
+		any m_unMod = m_unAccountID % 2;
+		Format(out, maxlen, "STEAM_0:%d:%d", m_unMod, (m_unAccountID-m_unMod)/2);
+	}
+	else
+	{
+		strcopy(out, maxlen, m_szSteamID);
+	}
+
+	return success;
+}
+
+stock any GetFriendID(int client, bool validate=true)
+{
+	char auth[32];
+	GetLegacyAuthString(client, STRING(auth), validate);
+
+	return ToAccountID(auth);
+}
+
+stock int ToAccountID(char[] auth)
+{
+	if(strlen(auth)<11)
+		return 0;
+	return StringToInt(auth[10])*2 + auth[8]-48;
+}
+
diff --git a/zrstore/scripting/store/db.sp b/zrstore/scripting/store/db.sp
new file mode 100644
index 00000000..d13a77cd
--- /dev/null
+++ b/zrstore/scripting/store/db.sp
@@ -0,0 +1,98 @@
+Handle g_hDatabase = INVALID_HANDLE;
+bool g_bMySQL = false;
+
+#include "store/sql.sp"
+
+void Store_DB_ConfigsExecuted_ConnectDatabase()
+{
+	if(g_hDatabase == INVALID_HANDLE)
+		SQL_TConnect(SQLCallback_Connect, g_eCvars[g_cvarDatabaseEntry].sCache);
+	// If database has been connected. Skip connection and do some housekeeping here
+	else Store_DB_HouseKeeping(g_hDatabase);
+	
+	if(g_eCvars[g_cvarDatabaseRetries].aCache > 0)
+		CreateTimer(view_as<float>(g_eCvars[g_cvarDatabaseTimeout].aCache), Timer_DatabaseTimeout);
+}
+
+public Action Timer_DatabaseTimeout(Handle timer, any userid)
+{
+	// Database is connected successfully
+	if(g_hDatabase != INVALID_HANDLE)
+		return Plugin_Stop;
+
+	if(g_iDatabaseRetries < g_eCvars[g_cvarDatabaseRetries].aCache)
+	{
+		SQL_TConnect(SQLCallback_Connect, g_eCvars[g_cvarDatabaseEntry].sCache);
+		CreateTimer(view_as<float>(g_eCvars[g_cvarDatabaseTimeout].aCache), Timer_DatabaseTimeout);
+		++g_iDatabaseRetries;
+	}
+	else
+	{
+		SetFailState("Database connection failed to initialize after %d retrie(s)", g_eCvars[g_cvarDatabaseRetries].aCache);
+	}
+
+	return Plugin_Stop;
+}
+
+void Store_DB_HouseKeeping(Handle db)
+{
+	// Do some housekeeping
+	char m_szQuery[600], m_szLogCleaningQuery[256];
+	
+	char m_szDriver[12];
+	SQL_ReadDriver(db, STRING(m_szDriver));
+	
+	// Remove expired and equipped items
+	if (StrEqual(m_szDriver, "mysql"))
+	{
+		// This query removes expired items that are equipped, and also remove the rows from store_equipment - it doesnt remove unequipped items!
+		Format(STRING(m_szQuery), "DELETE store_items, store_equipment "
+								... "FROM store_items, store_equipment "
+								... "WHERE store_items.unique_id = store_equipment.unique_id "
+									... "AND store_items.player_id = store_equipment.player_id "
+									... "AND store_items.date_of_expiration != 0 "
+									... "AND store_items.date_of_expiration < %d", GetTime());
+		// Ugly syntax, but MySQL DOES allow DELETE clauses between multiple tables in a single query
+	}
+	else
+	{
+		// This query removes rows from store_equipment that are linked to items that are expired, BUT DOESNT ACTUALLY REMOVE EXPIRED ITEMS FROM PLAYERS INVENTORIES! - This is done by the query after this one.
+		// ^ NOTE THAT THE BEHAVIOR OF THIS QUERY DIFFERS FROM THE MySQL ONE!
+		// For easier copy-pasting: DELETE FROM store_equipment WHERE ROWID IN (SELECT store_equipment.ROWID FROM store_items, store_equipment WHERE store_items.unique_id = store_equipment.unique_id AND store_items.player_id = store_equipment.player_id AND store_items.date_of_expiration != 0 AND store_items.date_of_expiration < %d);
+		Format(STRING(m_szQuery), "DELETE FROM store_equipment "
+								... "WHERE ROWID IN "
+									... "("
+									...	"SELECT store_equipment.ROWID "
+										... "FROM store_items, store_equipment "
+										... "WHERE store_items.unique_id = store_equipment.unique_id "
+											... "AND store_items.player_id = store_equipment.player_id "
+											... "AND store_items.date_of_expiration != 0 "
+											... "AND store_items.date_of_expiration < %d"
+									... ") ", GetTime());
+		// SQLite doesnt allow DELETE clauses between multiple tables in a single query. GRRRR!!!
+		
+		// Btw, ROWID is the default hidden SQLite primary key, because the store_equipment table doesnt have one
+	}
+	//SQL_TVoid(db, m_szQuery); //these just waste time. everything is permanent anyways on unloze
+	
+	// Remove expired and unequipped items
+	Format(STRING(m_szQuery), "DELETE FROM store_items WHERE date_of_expiration != 0 AND date_of_expiration < %d", GetTime());
+	//SQL_TVoid(db, m_szQuery); //these just waste time. everything is permanent anyways on unloze
+	
+	
+	if (g_eCvars[g_cvarLogLast].aCache>0)
+	{
+		if (StrEqual(m_szDriver, "mysql"))
+		{
+			Format(STRING(m_szLogCleaningQuery), "DELETE FROM store_plugin_logs WHERE `date` < CURDATE()-%i", g_eCvars[g_cvarLogLast].aCache);
+			SQL_TVoid(db, m_szLogCleaningQuery);
+			Format(STRING(m_szLogCleaningQuery), "DELETE FROM store_logs WHERE `date` < CURDATE()-%i", g_eCvars[g_cvarLogLast].aCache);
+			SQL_TVoid(db, m_szLogCleaningQuery);
+		}
+		else
+		{
+			Format(STRING(m_szLogCleaningQuery), "DELETE FROM store_plugin_logs WHERE `date` < (SELECT DATETIME('now', '-%i day'))", g_eCvars[g_cvarLogLast].aCache);
+			SQL_TVoid(db, m_szLogCleaningQuery);
+		}
+	}
+}
diff --git a/zrstore/scripting/store/sql.sp b/zrstore/scripting/store/sql.sp
new file mode 100644
index 00000000..983605bb
--- /dev/null
+++ b/zrstore/scripting/store/sql.sp
@@ -0,0 +1,461 @@
+//////////////////////////////
+//		SQL CALLBACKS		//
+//////////////////////////////
+public void SQLCallback_Connect(Handle owner, Handle hndl, const char[] error, any data)
+{
+	if(hndl==INVALID_HANDLE)
+	{
+		SetFailState("Failed to connect to SQL database. Error: %s", error);
+	}
+	else
+	{
+		// If it's already connected we are good to go
+		if(g_hDatabase != INVALID_HANDLE)
+			return;
+
+		g_hDatabase = hndl;
+		char m_szDriver[2];
+		SQL_ReadDriver(g_hDatabase, STRING(m_szDriver));
+
+		if(m_szDriver[0] == 'm')
+		{
+			g_bMySQL = true;
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_players` (\
+										  `id` int(11) NOT NULL AUTO_INCREMENT,\
+										  `authid` varchar(32) NOT NULL,\
+										  `name` varchar(64) NOT NULL,\
+										  `credits` int(11) NOT NULL,\
+										  `date_of_join` int(11) NOT NULL,\
+										  `date_of_last_join` int(11) NOT NULL,\
+										  PRIMARY KEY (`id`),\
+										  UNIQUE KEY `id` (`id`),\
+										  UNIQUE KEY `authid` (`authid`)\
+										) ENGINE=InnoDB AUTO_INCREMENT=0 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_items` (\
+										  `id` int(11) NOT NULL AUTO_INCREMENT,\
+										  `player_id` int(11) NOT NULL,\
+										  `type` varchar(16) NOT NULL,\
+										  `unique_id` varchar(256) NOT NULL,\
+										  `date_of_purchase` int(11) NOT NULL,\
+										  `date_of_expiration` int(11) NOT NULL,\
+										  PRIMARY KEY (`id`)\
+										) ENGINE=InnoDB AUTO_INCREMENT=0 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_equipment` (\
+										  `player_id` int(11) NOT NULL,\
+										  `type` varchar(16) NOT NULL,\
+										  `unique_id` varchar(256) NOT NULL,\
+										  `slot` int(11) NOT NULL\
+										) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_logs` (\
+										  `id` int(11) NOT NULL AUTO_INCREMENT,\
+										  `player_id` int(11) NOT NULL,\
+										  `credits` int(11) NOT NULL,\
+										  `reason` varchar(256) NOT NULL,\
+										  `date` timestamp NOT NULL,\
+										  PRIMARY KEY (`id`)\
+										) ENGINE=InnoDB AUTO_INCREMENT=0 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
+
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_plugin_logs` (\
+										  `id` int(11) NOT NULL AUTO_INCREMENT,\
+										  `level` varchar(8) NOT NULL,\
+										   name varchar(64) NOT NULL default '',\
+										   steam varchar(64) NOT NULL default '',\
+										  `player_id` int(11) NOT NULL,\
+										  `reason` varchar(256) NOT NULL,\
+										  `date` timestamp NOT NULL,\
+										  PRIMARY KEY (`id`),\
+										  UNIQUE KEY `id` (`id`)\
+										) ENGINE=InnoDB AUTO_INCREMENT=0 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
+
+			SQL_TQuery(g_hDatabase, SQLCallback_NoError, "ALTER TABLE store_items ADD COLUMN price_of_purchase int(11)");
+			// Edit exist date column
+			SQL_TQuery(g_hDatabase, SQLCallback_CheckError, "ALTER TABLE store_logs MODIFY COLUMN date TIMESTAMP NOT NULL");
+			
+			SQL_TQuery(g_hDatabase, SQLCallback_CheckError, "ALTER TABLE store_players CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;");
+			SQL_TQuery(g_hDatabase, SQLCallback_CheckError, "ALTER TABLE store_plugin_logs CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;");
+			char m_szQuery[1024];
+			Format(STRING(m_szQuery), "CREATE TABLE IF NOT EXISTS `%s` (\
+										  `id` int(11) NOT NULL AUTO_INCREMENT,\
+										  `parent_id` int(11) NOT NULL DEFAULT '-1',\
+										  `item_price` int(32) NOT NULL,\
+										  `item_type` varchar(64) NOT NULL,\
+										  `item_flag` varchar(64) NOT NULL,\
+										  `item_name` varchar(64) NOT NULL,\
+										  `additional_info` text NOT NULL,\
+										  `item_status` tinyint(1) NOT NULL,\
+										  `supported_game` varchar(64) NOT NULL,\
+										  PRIMARY KEY (`id`)\
+										) ENGINE=InnoDB AUTO_INCREMENT=0 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci", g_eCvars[g_cvarItemsTable].sCache);
+			SQL_TVoid(g_hDatabase, m_szQuery);
+		}
+		else
+		{
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_players` (\
+										  `id` INTEGER PRIMARY KEY AUTOINCREMENT,\
+										  `authid` varchar(32) NOT NULL,\
+										  `name` varchar(64) NOT NULL,\
+										  `credits` int(11) NOT NULL,\
+										  `date_of_join` int(11) NOT NULL,\
+										  `date_of_last_join` int(11) NOT NULL\
+										)");
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_items` (\
+										  `id` INTEGER PRIMARY KEY AUTOINCREMENT,\
+										  `player_id` int(11) NOT NULL,\
+										  `type` varchar(16) NOT NULL,\
+										  `unique_id` varchar(256) NOT NULL,\
+										  `date_of_purchase` int(11) NOT NULL,\
+										  `date_of_expiration` int(11) NOT NULL\
+										)");
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_equipment` (\
+										  `player_id` int(11) NOT NULL,\
+										  `type` varchar(16) NOT NULL,\
+										  `unique_id` varchar(256) NOT NULL,\
+										  `slot` int(11) NOT NULL\
+										)");
+			SQL_TVoid(g_hDatabase, "CREATE TABLE IF NOT EXISTS `store_plugin_logs` (\
+										  `id` INTEGER PRIMARY KEY AUTOINCREMENT,\
+										  `level` varchar(8) NOT NULL,\
+										   name varchar(64) NOT NULL default '',\
+										   steam varchar(64) NOT NULL default '',\
+										  `player_id` int(11) NOT NULL,\
+										  `reason` varchar(256) NOT NULL,\
+										  `date` timestamp NOT NULL\
+										)");	
+			SQL_TQuery(g_hDatabase, SQLCallback_NoError, "ALTER TABLE store_items ADD COLUMN price_of_purchase int(11)");
+			if(strcmp(g_eCvars[g_cvarItemSource].sCache, "database")==0)
+			{
+	
+				SetFailState("Database item source can only be used with MySQL databases");
+			}
+		}
+		
+		// Do some housekeeping
+		Store_DB_HouseKeeping(g_hDatabase);
+		
+		if(!SQL_SetCharset(g_hDatabase, "utf8mb4")){
+			SQL_SetCharset(g_hDatabase, "utf8");
+		}
+	}
+}
+
+public void SQLCallback_CheckError(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(!StrEqual("", error))
+		LogError("Error happened. Error: %s", error);
+}
+
+public void SQLCallback_LoadClientInventory_Credits(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(hndl==INVALID_HANDLE)
+		LogError("Error happened. Error: %s", error);
+	else
+	{
+		int client = GetClientOfUserId(userid);
+		if (!client || !IsClientInGame(client))
+			return;
+		
+		char m_szQuery[256];
+		char m_szSteamID[32];
+		int m_iTime = GetTime();
+		g_eClients[client].iUserId = userid;
+		g_eClients[client].iItems = -1;
+		GetLegacyAuthString(client, STRING(m_szSteamID), false);
+		//strcopy(g_eClients[client].szAuthId, 32, m_szSteamID[8]);
+		strcopy(g_eClients[client].szAuthId, sizeof(Client_Data::szAuthId), m_szSteamID[8]);
+		GetClientName(client, g_eClients[client].szName_Client, 64);
+		SQL_EscapeString(g_hDatabase, g_eClients[client].szName_Client, g_eClients[client].szNameEscaped, 128);
+		
+		if(SQL_FetchRow(hndl))
+		{
+			g_eClients[client].iId_Client = SQL_FetchInt(hndl, 0);
+			g_eClients[client].iCredits = SQL_FetchInt(hndl, 3);
+			g_eClients[client].iOriginalCredits = SQL_FetchInt(hndl, 3);
+			g_eClients[client].iDateOfJoin = SQL_FetchInt(hndl, 4);
+			g_eClients[client].iDateOfLastJoin = m_iTime;
+			
+			Format(STRING(m_szQuery), "SELECT * FROM store_items WHERE `player_id`=%d", g_eClients[client].iId_Client);
+			SQL_TQuery(g_hDatabase, SQLCallback_LoadClientInventory_Items, m_szQuery, userid);
+
+			Store_LogMessage(client, g_eClients[client].iCredits, "Amount of credits when the player joined");
+			
+			Store_SaveClientData(client);
+		}
+		else
+		{
+			Format(STRING(m_szQuery), "INSERT INTO store_players (`authid`, `name`, `credits`, `date_of_join`, `date_of_last_join`) VALUES('%s', '%s', %d, %d, %d)",
+						g_eClients[client].szAuthId, g_eClients[client].szNameEscaped, g_eCvars[g_cvarStartCredits].aCache, m_iTime, m_iTime);
+			SQL_TQuery(g_hDatabase, SQLCallback_InsertClient, m_szQuery, userid);
+			g_eClients[client].iCredits = g_eCvars[g_cvarStartCredits].aCache;
+			g_eClients[client].iOriginalCredits = g_eCvars[g_cvarStartCredits].aCache;
+			g_eClients[client].iDateOfJoin = m_iTime;
+			g_eClients[client].iDateOfLastJoin = m_iTime;
+			g_eClients[client].bLoaded= true;
+			g_eClients[client].iItems = 0;
+
+			if(g_eCvars[g_cvarStartCredits].aCache > 0)
+				Store_LogMessage(client, g_eCvars[g_cvarStartCredits].aCache, "Start credits");
+		}
+		
+		g_eClients[client].hCreditTimer = Store_CreditTimer(client);
+	}
+}
+
+public void SQLCallback_LoadClientInventory_Items(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(hndl==INVALID_HANDLE)
+		LogError("Error happened. Error: %s", error);
+	else
+	{	
+		int client = GetClientOfUserId(userid);
+		if (!client || !IsClientInGame(client))
+			return;
+
+		char m_szQuery[256];
+		Format(STRING(m_szQuery), "SELECT * FROM store_equipment WHERE `player_id`=%d", g_eClients[client].iId_Client);
+		SQL_TQuery(g_hDatabase, SQLCallback_LoadClientInventory_Equipment, m_szQuery, userid);
+
+		if(!SQL_GetRowCount(hndl))
+		{
+			g_eClients[client].bLoaded = true;
+			g_eClients[client].iItems = 0;
+			return;
+		}
+		
+		char m_szUniqueId[PLATFORM_MAX_PATH];
+		char m_szType[16];
+		int m_iExpiration;
+		int m_iUniqueId;
+		int m_iTime = GetTime();
+		
+		int i = 0;
+		while(SQL_FetchRow(hndl))
+		{
+			m_iUniqueId = -1;
+			m_iExpiration = SQL_FetchInt(hndl, 5);
+			if(m_iExpiration && m_iExpiration<=m_iTime)
+				continue;
+			
+			SQL_FetchString(hndl, 2, STRING(m_szType));
+			SQL_FetchString(hndl, 3, STRING(m_szUniqueId));
+			while((m_iUniqueId = Store_GetItemId(m_szType, m_szUniqueId, m_iUniqueId))!=-1)
+			{
+				g_eClientItems[client][i].iId_Client_Item = SQL_FetchInt(hndl, 0);
+				g_eClientItems[client][i].iUniqueId = m_iUniqueId;
+				g_eClientItems[client][i].bSynced = true;
+				g_eClientItems[client][i].bDeleted = false;
+				g_eClientItems[client][i].iDateOfPurchase = SQL_FetchInt(hndl, 4);
+				g_eClientItems[client][i].iDateOfExpiration = m_iExpiration;
+				g_eClientItems[client][i].iPriceOfPurchase = SQL_FetchInt(hndl, 6);
+			
+				++i;
+			}
+		}
+		g_eClients[client].iItems = i;
+	}
+}
+
+public void SQLCallback_LoadClientInventory_Equipment(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(hndl==INVALID_HANDLE)
+		LogError("Error happened. Error: %s", error);
+	else
+	{
+		int client = GetClientOfUserId(userid);
+		if (!client || !IsClientInGame(client))
+			return;
+		
+		char m_szUniqueId[PLATFORM_MAX_PATH];
+		char m_szType[16];
+		int m_iUniqueId;
+		//int m_iFlags = GetUserFlagBits(client);
+		
+		while(SQL_FetchRow(hndl))
+		{
+			SQL_FetchString(hndl, 1, STRING(m_szType));
+			SQL_FetchString(hndl, 2, STRING(m_szUniqueId));
+			m_iUniqueId = Store_GetItemId(m_szType, m_szUniqueId);
+			if(m_iUniqueId == -1)
+				continue;
+			
+			// Client Dont have the item
+			if(!Store_HasClientItem(client, m_iUniqueId)) 
+			{
+				//PrintToChat(client, "You dont have item/ unequip");
+				Store_UnequipItem(client, m_iUniqueId);
+			}
+			// Client has item but VIP period is expired.
+			else if(Store_HasClientItem(client, m_iUniqueId) && !GetClientPrivilege(client, g_eItems[m_iUniqueId].iFlagBits))
+			{
+				//PrintToChat(client, "You ahve have item but no flag/ Sold.");
+				if (g_eCvars[g_cvarSellRestricted].aCache)
+				{
+					Store_SellItem(client, m_iUniqueId); // Sell the item.
+				}
+				else
+				{
+					Store_UnequipItem(client, m_iUniqueId); // Just prevent the player from equipping it.
+				}
+			}
+			// Client has item and has access to the item.
+			else 
+			{
+				//PrintToChat(client, "You have item/ equip");
+				Store_UseItem(client, m_iUniqueId, true, SQL_FetchInt(hndl, 3)); 
+			}
+		}
+		g_eClients[client].bLoaded = true;
+	}
+}
+
+public void SQLCallback_RefreshCredits(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(hndl==INVALID_HANDLE)
+		LogError("Error happened. Error: %s", error);
+	else
+	{
+		int client = GetClientOfUserId(userid);
+		if(!client)
+			return;
+			
+		if(SQL_FetchRow(hndl))
+		{
+			g_eClients[client].iCredits = SQL_FetchInt(hndl, 3);
+			g_eClients[client].iOriginalCredits = SQL_FetchInt(hndl, 3);
+		}
+	}
+}
+
+public void SQLCallback_InsertClient(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(hndl==INVALID_HANDLE)
+		LogError("Error happened. Error: %s", error);
+	else
+	{
+		int client = GetClientOfUserId(userid);
+		if(!client)
+			return;
+			
+		g_eClients[client].iId_Client = SQL_GetInsertId(hndl);
+	}
+}
+
+public void SQLCallback_ReloadConfig(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(hndl==INVALID_HANDLE)
+	{
+		SetFailState("Error happened reading the config table. The plugin cannot continue.", error);
+	}
+	else
+	{
+		char m_szType[64];
+		char m_szFlag[64];
+		char m_szInfo[2048];
+		char m_szKey[64];
+		char m_szValue[256];
+		
+		Handle m_hKV;
+		
+		bool m_bSuccess;
+		
+		int m_iLength;
+		int m_iHandler;
+		int m_iIndex = 0;
+	
+		while(SQL_FetchRow(hndl))
+		{
+			if(g_iItems == STORE_MAX_ITEMS)
+				return;
+				
+			if(!SQL_FetchInt(hndl, 7))
+				continue;
+			
+			g_eItems[g_iItems].iId = SQL_FetchInt(hndl, 0);
+			g_eItems[g_iItems].iParent = SQL_FetchInt(hndl, 1);
+			g_eItems[g_iItems].iPrice = SQL_FetchInt(hndl, 2);
+			
+			IntToString(g_eItems[g_iItems].iId, g_eItems[g_iItems].szUniqueId, PLATFORM_MAX_PATH);
+			
+			SQL_FetchString(hndl, 3, STRING(m_szType));
+			m_iHandler = Store_GetTypeHandler(m_szType);
+			if(m_iHandler == -1)
+				continue;
+			
+			g_eItems[g_iItems].iHandler = m_iHandler;
+			
+			SQL_FetchString(hndl, 4, STRING(m_szFlag));
+			g_eItems[g_iItems].iFlagBits = ReadFlagString(m_szFlag);
+			
+			SQL_FetchString(hndl, 5, g_eItems[g_iItems].szName, ITEM_NAME_LENGTH);
+			SQL_FetchString(hndl, 6, STRING(m_szInfo));
+			
+			m_hKV = CreateKeyValues("Additional Info");
+			
+			m_iLength = strlen(m_szInfo);
+			while(m_iIndex != m_iLength)
+			{
+				m_iIndex += strcopy(m_szKey, StrContains(m_szInfo[m_iIndex], "="), m_szInfo[m_iIndex])+2;
+				m_iIndex += strcopy(m_szValue, StrContains(m_szInfo[m_iIndex], "\";"), m_szInfo[m_iIndex])+2; // \"
+				
+				KvJumpToKey(m_hKV, m_szKey, true);
+				KvSetString(m_hKV, m_szKey, m_szValue);
+				
+				m_bSuccess = true;
+				if(g_eTypeHandlers[m_iHandler].fnConfig!=INVALID_FUNCTION)
+				{
+					Call_StartFunction(g_eTypeHandlers[m_iHandler].hPlugin, g_eTypeHandlers[m_iHandler].fnConfig);
+					Call_PushCellRef(m_hKV);
+					Call_PushCell(g_iItems);
+					Call_Finish(m_bSuccess); 
+				}
+				
+				if(m_bSuccess)
+					++g_iItems;
+			}
+			CloseHandle(m_hKV);
+		}
+	}
+}
+
+public void SQLCallback_ResetPlayer(Handle owner, Handle hndl, const char[] error, any userid)
+{
+	if(hndl==INVALID_HANDLE)
+		LogError("Error happened. Error: %s", error);
+	else
+	{
+		int client = GetClientOfUserId(userid);
+
+		if(SQL_GetRowCount(hndl))
+		{
+			SQL_FetchRow(hndl);
+			int id = SQL_FetchInt(hndl, 0);
+			char m_szAuthId[32];
+			SQL_FetchString(hndl, 1, STRING(m_szAuthId));
+
+			char m_szQuery[512];
+			Format(STRING(m_szQuery), "DELETE FROM store_players WHERE id=%d", id);
+			SQL_TVoid(g_hDatabase, m_szQuery);
+			Format(STRING(m_szQuery), "DELETE FROM store_items WHERE player_id=%d", id);
+			SQL_TVoid(g_hDatabase, m_szQuery);
+			Format(STRING(m_szQuery), "DELETE FROM store_equipment WHERE player_id=%d", id);
+			SQL_TVoid(g_hDatabase, m_szQuery);
+
+			//ChatAll("%t", "Player Resetted", m_szAuthId);
+			CPrintToChatAll("%s%t", g_sChatPrefix, "Player Resetted", m_szAuthId);
+
+		}
+		else
+			if(client)
+			{
+				//Chat(client, "%t", "Credit No Match");
+				CPrintToChat(client, "%s%t", g_sChatPrefix, "Credit No Match");
+			}
+	}
+}
+
+public void SQLCallback_Void_Error(Handle owner, Handle hndl, const char[] error, any data)
+{
+	if (owner == null)
+	{
+		StoreLogMessage(0, LOG_ERROR, "SQLCallback_Void_Error: %s", error);
+	}
+}