beautified the plugin #1
2 changed files with 969 additions and 70 deletions
876
scripting/include/autoexecconfig.inc
Normal file
876
scripting/include/autoexecconfig.inc
Normal file
|
@ -0,0 +1,876 @@
|
||||||
|
#if defined _autoexecconfig_included
|
||||||
|
#endinput
|
||||||
|
#endif
|
||||||
|
#define _autoexecconfig_included
|
||||||
|
|
||||||
|
|
||||||
|
#include <sourcemod>
|
||||||
|
|
||||||
|
|
||||||
|
// Append
|
||||||
|
#define AUTOEXEC_APPEND_BAD_FILENAME 0
|
||||||
|
#define AUTOEXEC_APPEND_FILE_NOT_FOUND 1
|
||||||
|
#define AUTOEXEC_APPEND_BAD_HANDLE 2
|
||||||
|
#define AUTOEXEC_APPEND_SUCCESS 3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Find
|
||||||
|
#define AUTOEXEC_FIND_BAD_FILENAME 10
|
||||||
|
#define AUTOEXEC_FIND_FILE_NOT_FOUND 11
|
||||||
|
#define AUTOEXEC_FIND_BAD_HANDLE 12
|
||||||
|
#define AUTOEXEC_FIND_NOT_FOUND 13
|
||||||
|
#define AUTOEXEC_FIND_SUCCESS 14
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Clean
|
||||||
|
#define AUTOEXEC_CLEAN_FILE_NOT_FOUND 20
|
||||||
|
#define AUTOEXEC_CLEAN_BAD_HANDLE 21
|
||||||
|
#define AUTOEXEC_CLEAN_SUCCESS 22
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// General
|
||||||
|
#define AUTOEXEC_NO_CONFIG 30
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Formatter
|
||||||
|
#define AUTOEXEC_FORMAT_BAD_FILENAME 40
|
||||||
|
#define AUTOEXEC_FORMAT_SUCCESS 41
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
static char g_sConfigFile[PLATFORM_MAX_PATH];
|
||||||
|
static char g_sRawFileName[PLATFORM_MAX_PATH];
|
||||||
|
static char g_sFolderPath[PLATFORM_MAX_PATH];
|
||||||
|
|
||||||
|
static StringMap g_hConvarTrie = null;
|
||||||
|
static bool g_bCacheEnabled = false;
|
||||||
|
|
||||||
|
static bool g_bCreateFile = false;
|
||||||
|
static Handle g_hPluginHandle = null;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Workaround for now
|
||||||
|
static int g_iLastFindResult;
|
||||||
|
static int g_iLastAppendResult;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last result from the parser.
|
||||||
|
*
|
||||||
|
* @return Returns one of the AUTOEXEC_FIND values or -1 if not set.
|
||||||
|
*/
|
||||||
|
stock int AutoExecConfig_GetFindResult()
|
||||||
|
{
|
||||||
|
return g_iLastFindResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last result from the appender.
|
||||||
|
*
|
||||||
|
* @return Returns one of the AUTOEXEC_APPEND values or -1 if not set.
|
||||||
|
*/
|
||||||
|
stock int AutoExecConfig_GetAppendResult()
|
||||||
|
{
|
||||||
|
return g_iLastAppendResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set if the config file should be created if it doesn't exist yet.
|
||||||
|
*
|
||||||
|
* @param create True if config file should be created, false otherwise.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
stock void AutoExecConfig_SetCreateFile(bool create)
|
||||||
|
{
|
||||||
|
g_bCreateFile = create;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the config file should be created if it doesn't exist.
|
||||||
|
*
|
||||||
|
* @return Returns true, if the config file should be created or false if it should not.
|
||||||
|
*/
|
||||||
|
stock bool AutoExecConfig_GetCreateFile()
|
||||||
|
{
|
||||||
|
return g_bCreateFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the plugin for which the config file should be created.
|
||||||
|
* Set to null to use the calling plugin.
|
||||||
|
* Used to print the correct filename in the top comment when creating the file.
|
||||||
|
*
|
||||||
|
* @param plugin The plugin to create convars for or null to use the calling plugin.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
stock void AutoExecConfig_SetPlugin(Handle plugin)
|
||||||
|
{
|
||||||
|
g_hPluginHandle = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the plugin for which the config file is created.
|
||||||
|
*
|
||||||
|
* @return The plugin handle
|
||||||
|
*/
|
||||||
|
stock Handle AutoExecConfig_GetPlugin()
|
||||||
|
{
|
||||||
|
return g_hPluginHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the global autoconfigfile used by functions of this file.
|
||||||
|
*
|
||||||
|
* @param file Name of the config file, path and .cfg extension is being added if not given.
|
||||||
|
* @param folder Folder under cfg/ to use. By default this is "sourcemod."
|
||||||
|
* @return True if formatter returned success, false otherwise.
|
||||||
|
*/
|
||||||
|
stock bool AutoExecConfig_SetFile(char[] file, char[] folder="sourcemod")
|
||||||
|
{
|
||||||
|
Format(g_sConfigFile, sizeof(g_sConfigFile), "%s", file);
|
||||||
|
|
||||||
|
// Global buffers for cfg execution
|
||||||
|
strcopy(g_sRawFileName, sizeof(g_sRawFileName), file);
|
||||||
|
strcopy(g_sFolderPath, sizeof(g_sFolderPath), folder);
|
||||||
|
|
||||||
|
|
||||||
|
// Format the filename
|
||||||
|
return AutoExecConfig_FormatFileName(g_sConfigFile, sizeof(g_sConfigFile), folder) == AUTOEXEC_FORMAT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the formatted autoconfigfile used by functions of this file.
|
||||||
|
*
|
||||||
|
* @param buffer String to format.
|
||||||
|
* @param size Maximum size of buffer
|
||||||
|
* @return True if filename was set, false otherwise.
|
||||||
|
*/
|
||||||
|
stock bool AutoExecConfig_GetFile(char[] buffer,int size)
|
||||||
|
{
|
||||||
|
if (strlen(g_sConfigFile) > 0)
|
||||||
|
{
|
||||||
|
strcopy(buffer, size, g_sConfigFile);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security for decl users
|
||||||
|
buffer[0] = '\0';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a convar and appends it to the autoconfigfile if not found.
|
||||||
|
* FCVAR_DONTRECORD will be skipped.
|
||||||
|
*
|
||||||
|
* @param name Name of new convar.
|
||||||
|
* @param defaultValue String containing the default value of new convar.
|
||||||
|
* @param description Optional description of the convar.
|
||||||
|
* @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details.
|
||||||
|
* @param hasMin Optional boolean that determines if the convar has a minimum value.
|
||||||
|
* @param min Minimum floating point value that the convar can have if hasMin is true.
|
||||||
|
* @param hasMax Optional boolean that determines if the convar has a maximum value.
|
||||||
|
* @param max Maximum floating point value that the convar can have if hasMax is true.
|
||||||
|
* @return A handle to the newly created convar. If the convar already exists, a handle to it will still be returned.
|
||||||
|
* @error Convar name is blank or is the same as an existing console command.
|
||||||
|
*/
|
||||||
|
stock ConVar AutoExecConfig_CreateConVar(const char[] name, const char[] defaultValue, const char[] description="", int flags=0, bool hasMin=false, float min=0.0, bool hasMax=false, float max=0.0)
|
||||||
|
{
|
||||||
|
// If configfile was set and convar has no dontrecord flag
|
||||||
|
if (!(flags & FCVAR_DONTRECORD) && strlen(g_sConfigFile) > 0)
|
||||||
|
{
|
||||||
|
// Reset the results
|
||||||
|
g_iLastFindResult = -1;
|
||||||
|
g_iLastAppendResult = -1;
|
||||||
|
|
||||||
|
|
||||||
|
// Add it if not found
|
||||||
|
char buffer[64];
|
||||||
|
|
||||||
|
g_iLastFindResult = AutoExecConfig_FindValue(name, buffer, sizeof(buffer), true);
|
||||||
|
|
||||||
|
// We only add this convar if it doesn't exist, or the file doesn't exist and it should be auto-generated
|
||||||
|
if (g_iLastFindResult == AUTOEXEC_FIND_NOT_FOUND || (g_iLastFindResult == AUTOEXEC_FIND_FILE_NOT_FOUND && g_bCreateFile))
|
||||||
|
{
|
||||||
|
g_iLastAppendResult = AutoExecConfig_AppendValue(name, defaultValue, description, flags, hasMin, min, hasMax, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create the convar
|
||||||
|
return CreateConVar(name, defaultValue, description, flags, hasMin, min, hasMax, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the autoconfigfile, and adds it to the OnConfigsExecuted forward.
|
||||||
|
* If we didn't created it already we let SourceMod create it.
|
||||||
|
*
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
stock void AutoExecConfig_ExecuteFile()
|
||||||
|
{
|
||||||
|
// Only let sourcemod create the file, if we didn't do that already.
|
||||||
|
AutoExecConfig(!g_bCreateFile, g_sRawFileName, g_sFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a autoconfigfile, prefixes path and adds .cfg extension if missed.
|
||||||
|
*
|
||||||
|
* @param buffer String to format.
|
||||||
|
* @param size Maximum size of buffer.
|
||||||
|
* @return Returns one of the AUTOEXEC_FORMAT values..
|
||||||
|
*/
|
||||||
|
stock static int AutoExecConfig_FormatFileName(char[] buffer, int size, char[] folder="sourcemod")
|
||||||
|
{
|
||||||
|
// No config set
|
||||||
|
if (strlen(g_sConfigFile) < 1)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_NO_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Can't be an cfgfile
|
||||||
|
if (StrContains(g_sConfigFile, ".cfg") == -1 && strlen(g_sConfigFile) < 4)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_FORMAT_BAD_FILENAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Pathprefix
|
||||||
|
char pathprefixbuffer[PLATFORM_MAX_PATH];
|
||||||
|
if (strlen(folder) > 0)
|
||||||
|
{
|
||||||
|
Format(pathprefixbuffer, sizeof(pathprefixbuffer), "cfg/%s/", folder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Format(pathprefixbuffer, sizeof(pathprefixbuffer), "cfg/");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char filebuffer[PLATFORM_MAX_PATH];
|
||||||
|
filebuffer[0] = '\0';
|
||||||
|
|
||||||
|
// Add path if file doesn't begin with it
|
||||||
|
if (StrContains(buffer, pathprefixbuffer) != 0)
|
||||||
|
{
|
||||||
|
StrCat(filebuffer, sizeof(filebuffer), pathprefixbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
StrCat(filebuffer, sizeof(filebuffer), g_sConfigFile);
|
||||||
|
|
||||||
|
|
||||||
|
// Add .cfg extension if file doesn't end with it
|
||||||
|
if (StrContains(filebuffer[strlen(filebuffer) - 4], ".cfg") != 0)
|
||||||
|
{
|
||||||
|
StrCat(filebuffer, sizeof(filebuffer), ".cfg");
|
||||||
|
}
|
||||||
|
|
||||||
|
strcopy(buffer, size, filebuffer);
|
||||||
|
|
||||||
|
return AUTOEXEC_FORMAT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a convar to the global autoconfigfile
|
||||||
|
*
|
||||||
|
* @param name Name of new convar.
|
||||||
|
* @param defaultValue String containing the default value of new convar.
|
||||||
|
* @param description Optional description of the convar.
|
||||||
|
* @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details.
|
||||||
|
* @param hasMin Optional boolean that determines if the convar has a minimum value.
|
||||||
|
* @param min Minimum floating point value that the convar can have if hasMin is true.
|
||||||
|
* @param hasMax Optional boolean that determines if the convar has a maximum value.
|
||||||
|
* @param max Maximum floating point value that the convar can have if hasMax is true.
|
||||||
|
* @return Returns one of the AUTOEXEC_APPEND values
|
||||||
|
*/
|
||||||
|
stock int AutoExecConfig_AppendValue(const char[] name, const char[] defaultValue, const char[] description, int flags, bool hasMin, float min, bool hasMax, float max)
|
||||||
|
{
|
||||||
|
// No config set
|
||||||
|
if (strlen(g_sConfigFile) < 1)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_NO_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char filebuffer[PLATFORM_MAX_PATH];
|
||||||
|
strcopy(filebuffer, sizeof(filebuffer), g_sConfigFile);
|
||||||
|
|
||||||
|
|
||||||
|
//PrintToServer("pathbuffer: %s", filebuffer);
|
||||||
|
|
||||||
|
bool bFileExists = FileExists(filebuffer);
|
||||||
|
|
||||||
|
if (g_bCreateFile || bFileExists)
|
||||||
|
{
|
||||||
|
// If the file already exists we open it in append mode, otherwise we use a write mode which creates the file
|
||||||
|
File fFile = OpenFile(filebuffer, (bFileExists ? "a" : "w"));
|
||||||
|
char writebuffer[2048];
|
||||||
|
|
||||||
|
|
||||||
|
if (fFile == null)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_APPEND_BAD_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We just created the file, so add some header about version and stuff
|
||||||
|
if (g_bCreateFile && !bFileExists)
|
||||||
|
{
|
||||||
|
fFile.WriteLine( "// This file was auto-generated by AutoExecConfig read and append beta");
|
||||||
|
|
||||||
|
GetPluginFilename(g_hPluginHandle, writebuffer, sizeof(writebuffer));
|
||||||
|
Format(writebuffer, sizeof(writebuffer), "// ConVars for plugin \"%s\"", writebuffer);
|
||||||
|
fFile.WriteLine(writebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spacer
|
||||||
|
fFile.WriteLine("\n");
|
||||||
|
|
||||||
|
|
||||||
|
// This is used for multiline comments
|
||||||
|
int newlines = GetCharCountInStr('\n', description);
|
||||||
|
if (newlines == 0)
|
||||||
|
{
|
||||||
|
// We have no newlines, we can write the description to the file as is
|
||||||
|
Format(writebuffer, sizeof(writebuffer), "// %s", description);
|
||||||
|
fFile.WriteLine(writebuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char[][] newlineBuf = new char[newlines +1][2048];
|
||||||
|
ExplodeString(description, "\n", newlineBuf, newlines +1, 2048, false);
|
||||||
|
|
||||||
|
// Each newline gets a commented newline
|
||||||
|
for (int i; i <= newlines; i++)
|
||||||
|
{
|
||||||
|
if (strlen(newlineBuf[i]) > 0)
|
||||||
|
{
|
||||||
|
fFile.WriteLine("// %s", newlineBuf[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Descspacer
|
||||||
|
fFile.WriteLine("// -");
|
||||||
|
|
||||||
|
|
||||||
|
// Default
|
||||||
|
Format(writebuffer, sizeof(writebuffer), "// Default: \"%s\"", defaultValue);
|
||||||
|
fFile.WriteLine(writebuffer);
|
||||||
|
|
||||||
|
|
||||||
|
// Minimum
|
||||||
|
if (hasMin)
|
||||||
|
{
|
||||||
|
Format(writebuffer, sizeof(writebuffer), "// Minimum: \"%f\"", min);
|
||||||
|
fFile.WriteLine(writebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Maximum
|
||||||
|
if (hasMax)
|
||||||
|
{
|
||||||
|
Format(writebuffer, sizeof(writebuffer), "// Maximum: \"%f\"", max);
|
||||||
|
fFile.WriteLine(writebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write end and defaultvalue
|
||||||
|
Format(writebuffer, sizeof(writebuffer), "%s \"%s\"", name, defaultValue);
|
||||||
|
fFile.WriteLine(writebuffer);
|
||||||
|
|
||||||
|
|
||||||
|
fFile.Close();
|
||||||
|
|
||||||
|
|
||||||
|
// Clean up the file
|
||||||
|
//AutoExecConfig_CleanFile(filebuffer, false);
|
||||||
|
|
||||||
|
|
||||||
|
return AUTOEXEC_APPEND_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AUTOEXEC_APPEND_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a convars value from the global autoconfigfile
|
||||||
|
*
|
||||||
|
* @param cvar Cvar to search for.
|
||||||
|
* @param value Buffer to store result into.
|
||||||
|
* @param size Maximum size of buffer.
|
||||||
|
* @param caseSensitive Whether or not the search should be case sensitive.
|
||||||
|
* @return Returns one of the AUTOEXEC_FIND values
|
||||||
|
*/
|
||||||
|
stock int AutoExecConfig_FindValue(const char[] cvar, char[] value, int size, bool caseSensitive=false)
|
||||||
|
{
|
||||||
|
// Security for decl users
|
||||||
|
value[0] = '\0';
|
||||||
|
|
||||||
|
|
||||||
|
// No config set
|
||||||
|
if (strlen(g_sConfigFile) < 1)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_NO_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_bCacheEnabled)
|
||||||
|
{
|
||||||
|
char sTrieValue[64];
|
||||||
|
|
||||||
|
if (g_hConvarTrie.GetString(cvar, sTrieValue, sizeof(sTrieValue)))
|
||||||
|
{
|
||||||
|
strcopy(value, size, sTrieValue);
|
||||||
|
|
||||||
|
return AUTOEXEC_FIND_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AUTOEXEC_FIND_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char filebuffer[PLATFORM_MAX_PATH];
|
||||||
|
strcopy(filebuffer, sizeof(filebuffer), g_sConfigFile);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//PrintToServer("pathbuffer: %s", filebuffer);
|
||||||
|
|
||||||
|
bool bFileExists = FileExists(filebuffer);
|
||||||
|
|
||||||
|
// We want to create the config file and it doesn't exist yet.
|
||||||
|
if (g_bCreateFile && !bFileExists)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_FIND_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (bFileExists)
|
||||||
|
{
|
||||||
|
File fFile = OpenFile(filebuffer, "r");
|
||||||
|
int valuestart;
|
||||||
|
int valueend;
|
||||||
|
int cvarend;
|
||||||
|
|
||||||
|
// Just an reminder to self, leave the values that high
|
||||||
|
char sConvar[64];
|
||||||
|
char sValue[64];
|
||||||
|
char readbuffer[2048];
|
||||||
|
char copybuffer[2048];
|
||||||
|
|
||||||
|
if (fFile == null)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_FIND_BAD_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (!fFile.EndOfFile() && fFile.ReadLine(readbuffer, sizeof(readbuffer)))
|
||||||
|
{
|
||||||
|
// Is a comment or not valid
|
||||||
|
if (IsCharSpace(readbuffer[0]) || readbuffer[0] == '/' || !IsCharAlpha(readbuffer[0]))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Has not enough spaces, must have at least 1
|
||||||
|
if (GetCharCountInStr(' ', readbuffer) < 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ignore cvars which aren't quoted
|
||||||
|
if (GetCharCountInStr('"', readbuffer) != 2)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Get the start of the value
|
||||||
|
if ( (valuestart = StrContains(readbuffer, "\"")) == -1 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the end of the value
|
||||||
|
if ( (valueend = StrContains(readbuffer[valuestart+1], "\"")) == -1 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the start of the cvar,
|
||||||
|
if ( (cvarend = StrContains(readbuffer, " ")) == -1 || cvarend >= valuestart)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Skip if cvarendindex is before valuestartindex
|
||||||
|
if (cvarend >= valuestart)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convar
|
||||||
|
// Tempcopy for security
|
||||||
|
strcopy(copybuffer, sizeof(copybuffer), readbuffer);
|
||||||
|
copybuffer[cvarend] = '\0';
|
||||||
|
|
||||||
|
strcopy(sConvar, sizeof(sConvar), copybuffer);
|
||||||
|
|
||||||
|
|
||||||
|
// Value
|
||||||
|
// Tempcopy for security
|
||||||
|
strcopy(copybuffer, sizeof(copybuffer), readbuffer[valuestart+1]);
|
||||||
|
copybuffer[valueend] = '\0';
|
||||||
|
|
||||||
|
strcopy(sValue, sizeof(sValue), copybuffer);
|
||||||
|
|
||||||
|
|
||||||
|
//PrintToServer("Cvar %s has a value of %s", sConvar, sValue);
|
||||||
|
|
||||||
|
if (StrEqual(sConvar, cvar, caseSensitive))
|
||||||
|
{
|
||||||
|
Format(value, size, "%s", sConvar);
|
||||||
|
|
||||||
|
fFile.Close();
|
||||||
|
return AUTOEXEC_FIND_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fFile.Close();
|
||||||
|
return AUTOEXEC_FIND_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return AUTOEXEC_FIND_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans the global autoconfigfile from too much spaces
|
||||||
|
*
|
||||||
|
* @return One of the AUTOEXEC_CLEAN values.
|
||||||
|
*/
|
||||||
|
stock int AutoExecConfig_CleanFile()
|
||||||
|
{
|
||||||
|
// No config set
|
||||||
|
if (strlen(g_sConfigFile) < 1)
|
||||||
|
{
|
||||||
|
return AUTOEXEC_NO_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char sfile[PLATFORM_MAX_PATH];
|
||||||
|
strcopy(sfile, sizeof(sfile), g_sConfigFile);
|
||||||
|
|
||||||
|
|
||||||
|
// Security
|
||||||
|
if (!FileExists(sfile))
|
||||||
|
{
|
||||||
|
return AUTOEXEC_CLEAN_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char sfile2[PLATFORM_MAX_PATH];
|
||||||
|
Format(sfile2, sizeof(sfile2), "%s_tempcopy", sfile);
|
||||||
|
|
||||||
|
|
||||||
|
char readbuffer[2048];
|
||||||
|
int count;
|
||||||
|
bool firstreached;
|
||||||
|
|
||||||
|
|
||||||
|
// Open files
|
||||||
|
File fFile1 = OpenFile(sfile, "r");
|
||||||
|
File fFile2 = OpenFile(sfile2, "w");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Check filehandles
|
||||||
|
if (fFile1 == null || fFile2 == null)
|
||||||
|
{
|
||||||
|
if (fFile1 != null)
|
||||||
|
{
|
||||||
|
//PrintToServer("Handle1 invalid");
|
||||||
|
fFile1.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fFile2 != null)
|
||||||
|
{
|
||||||
|
//PrintToServer("Handle2 invalid");
|
||||||
|
fFile2.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AUTOEXEC_CLEAN_BAD_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
while (!fFile1.EndOfFile() && fFile1.ReadLine(readbuffer, sizeof(readbuffer)))
|
||||||
|
{
|
||||||
|
// Is space
|
||||||
|
if (IsCharSpace(readbuffer[0]))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
// No space, count from start
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Don't write more than 1 space if seperation after informations have been reached
|
||||||
|
if (count < 2 || !firstreached)
|
||||||
|
{
|
||||||
|
ReplaceString(readbuffer, sizeof(readbuffer), "\n", "");
|
||||||
|
fFile2.WriteLine(readbuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// First bigger seperation after informations has been reached
|
||||||
|
if (count == 2)
|
||||||
|
{
|
||||||
|
firstreached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fFile1.Close();
|
||||||
|
fFile2.Close();
|
||||||
|
|
||||||
|
|
||||||
|
// This might be a risk, for now it works
|
||||||
|
DeleteFile(sfile);
|
||||||
|
RenameFile(sfile, sfile2);
|
||||||
|
|
||||||
|
return AUTOEXEC_CLEAN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns how many times the given char occures in the given string.
|
||||||
|
*
|
||||||
|
* @param str String to search for in.
|
||||||
|
* @return Occurences of the given char found in string.
|
||||||
|
*/
|
||||||
|
stock static int GetCharCountInStr(int character, const char[] str)
|
||||||
|
{
|
||||||
|
int len = strlen(str);
|
||||||
|
int count;
|
||||||
|
|
||||||
|
for (int i; i < len; i++)
|
||||||
|
{
|
||||||
|
if (str[i] == character)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the existing config file and caches any convars and values that were found.
|
||||||
|
*
|
||||||
|
* @param str String to search for in.
|
||||||
|
* @return True when config existed and could be read, false otherwise.
|
||||||
|
*/
|
||||||
|
stock bool AutoExecConfig_CacheConvars()
|
||||||
|
{
|
||||||
|
if (g_hConvarTrie == null)
|
||||||
|
{
|
||||||
|
g_hConvarTrie = new StringMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// No config set
|
||||||
|
if (strlen(g_sConfigFile) < 1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char filebuffer[PLATFORM_MAX_PATH];
|
||||||
|
strcopy(filebuffer, sizeof(filebuffer), g_sConfigFile);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//PrintToServer("pathbuffer: %s", filebuffer);
|
||||||
|
|
||||||
|
bool bFileExists = FileExists(filebuffer);
|
||||||
|
|
||||||
|
// We want to create the config file and it doesn't exist yet.
|
||||||
|
if (!bFileExists)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
File fFile = OpenFile(filebuffer, "r");
|
||||||
|
int valuestart;
|
||||||
|
int valueend;
|
||||||
|
int cvarend;
|
||||||
|
|
||||||
|
// Just an reminder to self, leave the values that high
|
||||||
|
char sConvar[64];
|
||||||
|
char sValue[64];
|
||||||
|
char readbuffer[2048];
|
||||||
|
char copybuffer[2048];
|
||||||
|
|
||||||
|
if (fFile == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (!fFile.EndOfFile() && fFile.ReadLine(readbuffer, sizeof(readbuffer)))
|
||||||
|
{
|
||||||
|
// Is a comment or not valid
|
||||||
|
if (IsCharSpace(readbuffer[0]) || readbuffer[0] == '/' || !IsCharAlpha(readbuffer[0]))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Has not enough spaces, must have at least 1
|
||||||
|
if (GetCharCountInStr(' ', readbuffer) < 1)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ignore cvars which aren't quoted
|
||||||
|
if (GetCharCountInStr('"', readbuffer) != 2)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Get the start of the value
|
||||||
|
if ( (valuestart = StrContains(readbuffer, "\"")) == -1 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the end of the value
|
||||||
|
if ( (valueend = StrContains(readbuffer[valuestart+1], "\"")) == -1 )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get the start of the cvar,
|
||||||
|
if ( (cvarend = StrContains(readbuffer, " ")) == -1 || cvarend >= valuestart)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Skip if cvarendindex is before valuestartindex
|
||||||
|
if (cvarend >= valuestart)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convar
|
||||||
|
// Tempcopy for security
|
||||||
|
strcopy(copybuffer, sizeof(copybuffer), readbuffer);
|
||||||
|
copybuffer[cvarend] = '\0';
|
||||||
|
|
||||||
|
strcopy(sConvar, sizeof(sConvar), copybuffer);
|
||||||
|
|
||||||
|
|
||||||
|
// Value
|
||||||
|
// Tempcopy for security
|
||||||
|
strcopy(copybuffer, sizeof(copybuffer), readbuffer[valuestart+1]);
|
||||||
|
copybuffer[valueend] = '\0';
|
||||||
|
|
||||||
|
strcopy(sValue, sizeof(sValue), copybuffer);
|
||||||
|
|
||||||
|
|
||||||
|
//PrintToServer("Cvar %s has a value of %s", sConvar, sValue);
|
||||||
|
|
||||||
|
char sTrieValue[64];
|
||||||
|
if (!g_hConvarTrie.GetString(sConvar, sTrieValue, sizeof(sTrieValue)))
|
||||||
|
{
|
||||||
|
//PrintToServer("Adding convar %s to trie", sConvar);
|
||||||
|
g_hConvarTrie.SetString(sConvar, sValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fFile.Close();
|
||||||
|
|
||||||
|
g_bCacheEnabled = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -2,8 +2,9 @@
|
||||||
#include <sdktools>
|
#include <sdktools>
|
||||||
#include <store>
|
#include <store>
|
||||||
#include <shavit>
|
#include <shavit>
|
||||||
|
#include <autoexecconfig>
|
||||||
|
|
||||||
#define PLUGIN_VERSION "1.2.2"
|
#define PLUGIN_VERSION "1.3.0"
|
||||||
public Plugin myinfo =
|
public Plugin myinfo =
|
||||||
{
|
{
|
||||||
name = "[shavit] Credits | Zephyrus Store",
|
name = "[shavit] Credits | Zephyrus Store",
|
||||||
|
@ -12,74 +13,98 @@ public Plugin myinfo =
|
||||||
version = PLUGIN_VERSION,
|
version = PLUGIN_VERSION,
|
||||||
url = "https://deadnationgaming.eu/"
|
url = "https://deadnationgaming.eu/"
|
||||||
};
|
};
|
||||||
Handle gh_enabled_normal;
|
|
||||||
Handle gh_enabled_wr;
|
|
||||||
Handle gh_enabled_pb;
|
|
||||||
Handle gh_amount_normal;
|
|
||||||
Handle gh_amount_wr;
|
|
||||||
Handle gh_amount_pb;
|
|
||||||
Handle gh_enabled_t1;
|
|
||||||
char gS_Map[160];
|
|
||||||
int iTier;
|
|
||||||
int istyle;
|
|
||||||
float fpb;
|
|
||||||
int nr_enabled;
|
|
||||||
int wr_enabled;
|
|
||||||
int pb_enabled;
|
|
||||||
int t1_enabled;
|
|
||||||
|
|
||||||
public void OnPluginStart()
|
ConVar g_cvNormalEnabled;
|
||||||
{
|
int g_iNormalEnabled
|
||||||
CreateConVar("shavit_creds_version", PLUGIN_VERSION, "Zephyrus-Store : Shavit Credits Map Finish", FCVAR_SPONLY | FCVAR_DONTRECORD | FCVAR_NOTIFY);
|
ConVar g_cvWREnabled;
|
||||||
gh_enabled_normal = CreateConVar("credits_enable_normal", "1", "Store money give for map finish is enabled?", 0, true, 0.0, true, 1.0);
|
int g_iWREnabled;
|
||||||
gh_enabled_wr = CreateConVar("credits_enable_wr", "1", "Store money given for map World Record is enabled?", 0, true, 0.0, true, 1.0);
|
ConVar g_cvEnabledPb;
|
||||||
gh_enabled_pb = CreateConVar("credits_enable_pb", "1", "Store money given for map Personal Best is enabled?", 0, true, 0.0, true, 1.0);
|
int g_iPBEnabled;
|
||||||
gh_enabled_t1 = CreateConVar("credits_enable_t1", "1", "Enable/Disable give credits for Tier 1 Has no effect on WRs and PBs!", 0, true, 0.0, true, 1.0);
|
ConVar g_cvT1Enabled;
|
||||||
gh_amount_normal = CreateConVar("credits_amount_normal", "10", "Amount of credits are given on map finish.", 0, true, 1.0, false);
|
int g_iT1Enabled;
|
||||||
gh_amount_wr = CreateConVar("credits_amount_wr", "25", "Amount of credits are given on breaking world records.", 0, true, 1.0, false);
|
ConVar g_cvNormalAmount;
|
||||||
gh_amount_pb = CreateConVar("credits_amount_pb", "10", "Amount of credits are given on breaking your personal best.", 0, true, 1.0, false);
|
int g_iNormalAmount;
|
||||||
|
ConVar g_cvWrAmount;
|
||||||
|
int g_iWrAmount;
|
||||||
|
ConVar g_cvPBAmount;
|
||||||
|
int g_iPBAmount;
|
||||||
|
|
||||||
AutoExecConfig(true, "shavit-credits");
|
char g_cMap[160];
|
||||||
|
int g_iTier;
|
||||||
|
int g_iStyle;
|
||||||
|
float g_fPB;
|
||||||
|
|
||||||
nr_enabled = GetConVarInt(gh_enabled_normal);
|
public void OnPluginStart() {
|
||||||
wr_enabled = GetConVarInt(gh_enabled_wr);
|
AutoExecConfig_SetFile("shavit_credits");
|
||||||
pb_enabled = GetConVarInt(gh_enabled_pb);
|
AutoExecConfig_SetCreateFile(true);
|
||||||
t1_enabled = GetConVarInt(gh_enabled_t1);
|
|
||||||
|
|
||||||
|
CreateConVar("shavit_credits_version", PLUGIN_VERSION, "Zephyrus-Store : Shavit Credits Map Finish", FCVAR_SPONLY | FCVAR_DONTRECORD | FCVAR_NOTIFY);
|
||||||
|
g_cvNormalEnabled = AutoExecConfig_CreateConVar("credits_enable_normal", "1", "Store money give for map finish is enabled?", 0, true, 0.0, true, 1.0);
|
||||||
|
g_cvWREnabled = AutoExecConfig_CreateConVar("credits_enable_wr", "1", "Store money given for map World Record is enabled?", 0, true, 0.0, true, 1.0);
|
||||||
|
g_cvEnabledPb = AutoExecConfig_CreateConVar("credits_enable_pb", "1", "Store money given for map Personal Best is enabled?", 0, true, 0.0, true, 1.0);
|
||||||
|
g_cvT1Enabled = AutoExecConfig_CreateConVar("credits_enable_t1", "1", "Enable/Disable give credits for Tier 1 Has no effect on WRs and PBs!", 0, true, 0.0, true, 1.0);
|
||||||
|
g_cvNormalAmount = AutoExecConfig_CreateConVar("credits_amount_normal", "10", "Amount of credits are given on map finish.", 0, true, 1.0, false);
|
||||||
|
g_cvWrAmount = AutoExecConfig_CreateConVar("credits_amount_wr", "25", "Amount of credits are given on breaking world records.", 0, true, 1.0, false);
|
||||||
|
g_cvPBAmount = AutoExecConfig_CreateConVar("credits_amount_pb", "10", "Amount of credits are given on breaking your personal best.", 0, true, 1.0, false);
|
||||||
|
|
||||||
|
HookConVarChange(g_cvNormalEnabled, OnConVarChange);
|
||||||
|
HookConVarChange(g_cvWREnabled, OnConVarChange);
|
||||||
|
HookConVarChange(g_cvEnabledPb, OnConVarChange);
|
||||||
|
HookConVarChange(g_cvT1Enabled, OnConVarChange);
|
||||||
|
HookConVarChange(g_cvNormalAmount, OnConVarChange);
|
||||||
|
HookConVarChange(g_cvWrAmount, OnConVarChange);
|
||||||
|
HookConVarChange(g_cvPBAmount, OnConVarChange);
|
||||||
|
|
||||||
|
|
||||||
|
AutoExecConfig_CleanFile();
|
||||||
|
AutoExecConfig_ExecuteFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnMapStart()
|
public void OnConfigsExecuted() {
|
||||||
{
|
g_iNormalEnabled = GetConVarInt(g_cvNormalEnabled);
|
||||||
GetCurrentMap(gS_Map, 160);
|
g_iWREnabled = GetConVarInt(g_cvWREnabled);
|
||||||
GetMapDisplayName(gS_Map, gS_Map, 160);
|
g_iPBEnabled = GetConVarInt(g_cvEnabledPb);
|
||||||
iTier = Shavit_GetMapTier(gS_Map);
|
g_iT1Enabled = GetConVarInt(g_cvT1Enabled);
|
||||||
|
g_iNormalAmount = GetConVarInt(g_cvNormalAmount);
|
||||||
|
g_iWrAmount = GetConVarInt(g_cvWrAmount);
|
||||||
|
g_iPBAmount = GetConVarInt(g_cvPBAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action Shavit_OnStart(int client, int track)
|
public OnConVarChange(ConVar convar, const char[] oldValue, const char[] newValue) {
|
||||||
{
|
g_iNormalEnabled = GetConVarInt(g_cvNormalEnabled);
|
||||||
istyle = Shavit_GetBhopStyle(client);
|
g_iWREnabled = GetConVarInt(g_cvWREnabled);
|
||||||
fpb = Shavit_GetClientPB(client, istyle, track);
|
g_iPBEnabled = GetConVarInt(g_cvEnabledPb);
|
||||||
|
g_iT1Enabled = GetConVarInt(g_cvT1Enabled);
|
||||||
|
g_iNormalAmount = GetConVarInt(g_cvNormalAmount);
|
||||||
|
g_iWrAmount = GetConVarInt(g_cvWrAmount);
|
||||||
|
g_iPBAmount = GetConVarInt(g_cvPBAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Shavit_OnFinish(int client, int style, float time, int jumps, int track)
|
public void OnMapStart() {
|
||||||
{
|
GetCurrentMap(g_cMap, 160);
|
||||||
|
GetMapDisplayName(g_cMap, g_cMap, 160);
|
||||||
|
g_iTier = Shavit_GetMapTier(g_cMap);
|
||||||
|
}
|
||||||
|
|
||||||
if(nr_enabled == 1)
|
public Action Shavit_OnStart(int client, int track) {
|
||||||
{
|
g_iStyle = Shavit_GetBhopStyle(client);
|
||||||
if(t1_enabled == 1 || iTier != 1)
|
g_fPB = Shavit_GetClientPB(client, g_iStyle, track);
|
||||||
{
|
}
|
||||||
int fcredits = GetConVarInt(gh_amount_normal)*iTier;
|
|
||||||
|
public void Shavit_OnFinish(int client, int style, float time, int jumps, int track) {
|
||||||
|
if (g_iNormalEnabled == 1) {
|
||||||
|
if (g_iT1Enabled == 1 || g_iTier != 1) {
|
||||||
|
int fcredits = GetConVarInt(g_cvNormalAmount) * g_iTier;
|
||||||
|
|
||||||
Store_SetClientCredits(client, Store_GetClientCredits(client) + fcredits);
|
Store_SetClientCredits(client, Store_GetClientCredits(client) + fcredits);
|
||||||
PrintToChat(client, "[\x04Store\x01] You have earned \x04%d\x01 credits for finishing this map.", fcredits);
|
PrintToChat(client, "[\x04Store\x01] You have earned \x04%d\x01 credits for finishing this map.", fcredits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pb_enabled == 1)
|
if (g_iPBEnabled == 1) {
|
||||||
{
|
if (time < g_fPB) {
|
||||||
if(time<fpb){
|
|
||||||
|
|
||||||
int fcredits = GetConVarInt(gh_amount_pb)*iTier;
|
int fcredits = GetConVarInt(g_cvPBAmount) * g_iTier;
|
||||||
|
|
||||||
Store_SetClientCredits(client, Store_GetClientCredits(client) + fcredits);
|
Store_SetClientCredits(client, Store_GetClientCredits(client) + fcredits);
|
||||||
PrintToChat(client, "[\x04Store\x01] You have earned \x04%d\x01 credits for breaking your Personal Best.", fcredits);
|
PrintToChat(client, "[\x04Store\x01] You have earned \x04%d\x01 credits for breaking your Personal Best.", fcredits);
|
||||||
|
@ -87,11 +112,9 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int tr
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public void Shavit_OnWorldRecord(int client, int style, float time, int jumps, int track)
|
public void Shavit_OnWorldRecord(int client, int style, float time, int jumps, int track) {
|
||||||
{
|
if (g_iWREnabled == 1) {
|
||||||
if(wr_enabled == 1)
|
int fcredits = GetConVarInt(g_cvWrAmount) * g_iTier;
|
||||||
{
|
|
||||||
int fcredits = GetConVarInt(gh_amount_wr)*iTier;
|
|
||||||
|
|
||||||
Store_SetClientCredits(client, Store_GetClientCredits(client) + fcredits);
|
Store_SetClientCredits(client, Store_GetClientCredits(client) + fcredits);
|
||||||
PrintToChat(client, "[\x04Store\x01] You have earned \x04%d\x01 credits for break the world records.", fcredits);
|
PrintToChat(client, "[\x04Store\x01] You have earned \x04%d\x01 credits for break the world records.", fcredits);
|
||||||
|
|
Loading…
Reference in a new issue