User
Pass
2FA
 
 

nu pot compila

 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Freakz Forum Index -> Trash Bin -> CS 2006-2019 (Archived) -> Resources
Author Message2218
KillingFloor

[Mentally Stable]



Status: Offline
(since 09-02-2013 10:06)
Joined: 22 Nov 2012
Posts: 14, Topics: 4
Location: Romania

Reputation: 51.5
Votes: 2

Post Posted: 25-11-2012, 20:57:54 | Translate post to: ... (Click for more languages)

Nu pot Compila pluginul asta:

Code:
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>

// set this to 1 to get some debug messages
#define   DEBUG_MODE   0

// turn this off to stop list from being sorted by keywords in alphabetic order
#define   ALLOW_SORT   1

// Array Defines, ATTENTION: ( MAX_RANDOM + 1 ) * TOK_LENGTH must be smaller 2048 !!!
#define MAX_KEYWORDS  80  // Maximum number of keywords ( ATTENTION: 2 are reserved )
#define MAX_RANDOM    15  // Maximum number of sounds per keyword
#define TOK_LENGTH    60  // Maximum length of keyword and sound file strings
#define MAX_BANS      32  // Maximum number of bans stored
#define NUM_PER_LINE  6   // Number of words per line from amx_sound_help
#define BUFFER_LEN   TOK_LENGTH * MAX_RANDOM

//#pragma dynamic 16384
#pragma dynamic 65536

#define ACCESS_ADMIN   ADMIN_LEVEL_H

#define PLUGIN_AUTHOR      "White Panther, Luke Sankey, HunteR"
#define PLUGIN_VERSION      "1.7.1"

new Enable_Sound[] =  "misc/woohoo.wav"   // Sound played when Sank Soounds being enabled
new Disable_Sound[] = "misc/awwcrap.wav"  // Sound played when Sank Soounds being disabled

new config_filename[128]

new SndCount[33] = {0, ...}               // Holds the number telling how many sounds a player has played
new Float:SndLenghtCount[33] = {0.0, ...}
new SndOn[33] = {1, ...}

new SND_WARN = 0                          // The number at which a player will get warned for playing too many sounds
new SND_MAX = 0                           // The number at which a player will get kicked for playing too many sounds
new Float:SND_MAX_DUR = 0.0
new Float:SND_DELAY = 0.0                 // Minimum delay between sounds
new SND_MODE = 15                         // Determinates who can play and who can hear sounds (dead and alive)
new SND_IMMUNITY = ACCESS_ADMIN           // Determine the access levels which shall have immunity to warn/kick/ban (default ACCESS_ADMIN for backwards compatability)
new EXACT_MATCH = 1                       // Determinates if plugin triggers on exact match, or partial speech match
new ADMINS_ONLY = 0                       // Determinates if only admins are allowed to play sounds
new DISPLAY_KEYWORDS = 1                  // Determinates if keywords are shown in chat or not

new Float:NextSoundTime                   // spam protection
new Float:Join_exit_SoundTime             // spam protection 2
new Float:LastSoundTime = 0.0
new bSoundsEnabled = 1                    // amx_sound <on/off> or <1/0>

new CVAR_freezetime, CVAR_obey_duration

new g_max_players
new banned_player_steamids[MAX_BANS][60]
new restrict_playing_sounds[33]
new sound_quota_steamids[33][60]

new motd_sound_list_address[128]

enum
{
   PARSE_SND_MAX,
   PARSE_SND_MAX_DUR,
   PARSE_SND_WARN,
   PARSE_SND_DELAY,
   PARSE_SND_MODE,
   PARSE_SND_IMMUNITY,
   PARSE_EXACT_MATCH,
   PARSE_ADMINS_ONLY,
   PARSE_DISPLAY_KEYWORDS,
   PARSE_KEYWORD
}

enum
{
   ERROR_NONE,
   ERROR_MAX_KEYWORDS,
   ERROR_STRING_LENGTH
}

enum
{
   FLAG_IGNORE_AMOUNT = 1
}

enum
{
   SOUND_TYPE_SPEECH,
   SOUND_TYPE_MP3,
   SOUND_TYPE_WAV,
   SOUND_TYPE_WAV_LOCAL
}

enum SOUND_DATA_BASE
{
   KEYWORD[TOK_LENGTH],
   ADMIN_LEVEL_BASE,
   SOUND_AMOUNT,
   FLAGS,
   PLAY_COUNT_KEY,

   KEY_SOUNDS[BUFFER_LEN],
   Float:DURATION[MAX_RANDOM],
   ADMIN_LEVEL[MAX_RANDOM],
   SOUND_TYPE[MAX_RANDOM],
   PLAY_COUNT[MAX_RANDOM],

   SOUND_DATA_BASE_END
}

new sound_data[MAX_KEYWORDS][SOUND_DATA_BASE]

public plugin_init( )
{
   register_plugin("Sank Sounds Plugin", PLUGIN_VERSION, PLUGIN_AUTHOR)
   register_cvar("sanksounds_version", PLUGIN_VERSION, FCVAR_SERVER)
   set_cvar_string("sanksounds_version", PLUGIN_VERSION)
   
   register_concmd("amx_sound_reset", "amx_sound_reset", ACCESS_ADMIN,ADMIN_LEVEL_H " <user | all> : Resets sound quota for ^"user^", or everyone if ^"all^"")
   register_concmd("amx_sound_add", "amx_sound_add", ACCESS_ADMIN,ADMIN_LEVEL_H " <keyword> <dir/sound> : Adds a Word/Sound combo to the sound list")
   register_clcmd("amx_sound_help", "amx_sound_help")
   register_concmd("amx_sound", "amx_sound", ACCESS_ADMIN,ADMIN_LEVEL_H " :  Turns sounds on/off")
   register_concmd("amx_sound_play", "amx_sound_play", ACCESS_ADMIN,ADMIN_LEVEL_H " <dir/sound> : Plays sound to all users")
   register_concmd("amx_sound_reload", "amx_sound_reload", ACCESS_ADMIN,ADMIN_LEVEL_H " : Reloads config file. Filename is optional. If no filename, default is loaded")
   register_concmd("amx_sound_remove", "amx_sound_remove", ACCESS_ADMIN,ADMIN_LEVEL_H " <keyword> <dir/sound> : Removes a Word/Sound combo from the sound list. Must use quotes")
   register_concmd("amx_sound_write", "amx_sound_write", ACCESS_ADMIN,ADMIN_LEVEL_H " :  Writes current sound configuration to file")
   register_concmd("amx_sound_debug", "amx_sound_debug", ACCESS_ADMIN,ADMIN_LEVEL_H "prints the whole Word/Sound combo list")
   register_concmd("amx_sound_ban", "amx_sound_ban", ACCESS_ADMIN,ADMIN_LEVEL_H " <name or #userid>: Bans player from using sounds for current map")
   register_concmd("amx_sound_unban", "amx_sound_unban", ACCESS_ADMIN,ADMIN_LEVEL_H " <name or #userid>: Unbans player from using sounds for current map")
   register_concmd("amx_sound_top", "amx_sound_top", ACCESS_ADMIN,ADMIN_LEVEL_H " <number> (optional): Shows the top X (default 10) most used keywords during this map")
   
   register_clcmd("say", "HandleSay")
   register_clcmd("say_team", "HandleSay")
   
   register_cvar("mp_sank_sounds_download", "1")
   CVAR_freezetime = register_cvar("mp_sank_sounds_freezetime", "0")
   CVAR_obey_duration = register_cvar("mp_sank_sounds_obey_duration", "1")
   register_cvar("mp_sank_sounds_motd_address", "")
   
   g_max_players = get_maxplayers()
}

public plugin_cfg( )
{
   get_cvar_string("mp_sank_sounds_motd_address", motd_sound_list_address, 127)
   
   new configpath[61]
   get_configsdir(configpath, 60)
   format(config_filename, 127, "%s/SND-LIST.CFG", configpath)   // Name of file to parse
   
   // check if file in capital letter exists
   // otherwise make it all lowercase and try to load it
   if ( file_exists(config_filename) )
   {
      parse_sound_file(config_filename)
   }else
   {
      strtolower(config_filename)
      parse_sound_file(config_filename)
   }
}

public client_putinserver( id )
{
   restrict_playing_sounds[id] = -1
   
   new steamid[60], i
   get_user_authid(id, steamid, 59)
   for ( i = 0; i < MAX_BANS; ++i )
   {
      if ( equal(steamid, banned_player_steamids[i]) )
         restrict_playing_sounds[id] = i
   }
   
   if ( !equal(steamid, sound_quota_steamids[id]) )
   {
      copy(sound_quota_steamids[id], 59, steamid)
      SndCount[id] = 0
      SndLenghtCount[id] = 0.0
   }
   
   SndOn[id] = 1
   
   new Float:gametime = get_gametime()
   if ( gametime <= get_pcvar_num(CVAR_freezetime) )
      return
   
   if ( sound_data[0][SOUND_AMOUNT] == 0 )
      return
   
   if ( Join_exit_SoundTime >= gametime )
      return
   
   new rand = random(sound_data[0][SOUND_AMOUNT])
   new playFile[TOK_LENGTH]
   copy(playFile, TOK_LENGTH, sound_data[0][KEY_SOUNDS][TOK_LENGTH * rand])
   
   if ( sound_data[0][ADMIN_LEVEL][rand] != 0
      && !(get_user_flags(id) & sound_data[0][ADMIN_LEVEL][rand]) )
      return
   
   playsoundall(playFile, sound_data[0][SOUND_TYPE][rand])
   
   Join_exit_SoundTime = gametime + sound_data[0][DURATION][rand]
   if ( NextSoundTime < Join_exit_SoundTime )
      NextSoundTime = Join_exit_SoundTime
}

public client_disconnect( id )
{
   SndOn[id] = 1
   restrict_playing_sounds[id] = -1
   
   new Float:gametime = get_gametime()
   if ( gametime <= get_pcvar_num(CVAR_freezetime) )
      return
   
   if ( sound_data[1][SOUND_AMOUNT] == 0 )
      return
   
   if ( Join_exit_SoundTime >= gametime )
      return
   
   new rand = random(sound_data[1][SOUND_AMOUNT])
   new playFile[TOK_LENGTH]
   copy(playFile, TOK_LENGTH, sound_data[1][KEY_SOUNDS][TOK_LENGTH * rand])
   
   if ( sound_data[1][ADMIN_LEVEL][rand] != 0
      && !(get_user_flags(id) & sound_data[1][ADMIN_LEVEL][rand]) )
      return
   
   playsoundall(playFile, sound_data[1][SOUND_TYPE][rand])
   
   Join_exit_SoundTime = gametime + sound_data[1][DURATION][rand]
   if ( NextSoundTime < Join_exit_SoundTime )
      NextSoundTime = Join_exit_SoundTime
}

public amx_sound_reset( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new arg[33], target
   read_argv(1, arg, 32)
   if ( equal(arg, "all") == 1 )
   {
      client_print(id, print_console, "[REDIRECTME] Quota has been reseted for all players")
      for ( target = 1; target <= g_max_players; ++target )
      {
         SndCount[target] = 0
         SndLenghtCount[target] = 0.0
      }
   }else
   {
      target = cmd_target(id, arg, 1)
      if ( !target )
         return PLUGIN_HANDLED
     
      SndCount[target] = 0
      SndLenghtCount[target] = 0.0
      new name[33]
      get_user_name(target, name, 32)
      client_print(id, print_console, "[REDIRECTME] Quota has been reseted for ^"%s^"", name)
   }
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Adds a Word/Sound combo to the list. If it is a valid line in the config
// file, then it is a valid parameter here. The only difference is you can
// only specify one Sound file at a time with this command.
//
// Usage: amx_sound_add <keyword> <dir/sound>
// Usage: amx_sound_add <setting> <value>
//////////////////////////////////////////////////////////////////////////////
public amx_sound_add( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new Word[TOK_LENGTH + 1], Sound[TOK_LENGTH + 1]
   new configOption = 0
   
   read_argv(1, Word, TOK_LENGTH)
   read_argv(2, Sound, TOK_LENGTH)
   if ( strlen(Word) <= 0
      || strlen(Sound) == 0 )
   {
      client_print(id, print_console, "[REDIRECTME]Invalid format")
      client_print(id, print_console, "[REDIRECTME]USAGE: amx_sound_add keyword <dir/sound>")
     
      return PLUGIN_HANDLED
   }
   
   // First look for special parameters
   if ( equali(Word, "SND_MAX") )
   {
      SND_MAX = str_to_num(Sound)
      configOption = 1
   }else if ( equali(Word, "SND_MAX_DUR") )
   {
      SND_MAX_DUR = floatstr(Sound)
      configOption = 1
   }else if ( equali(Word, "SND_WARN") )
   {
      SND_WARN = str_to_num(Sound)
      configOption = 1
   }else if ( equali(Word, "SND_DELAY") )
   {
      SND_DELAY = floatstr(Sound)
      configOption = 1
   }else if ( equali(Word, "SND_MODE") )
   {
      SND_MODE = str_to_num(Sound)
      configOption = 1
   }else if ( equali(Word, "SND_IMMUNITY") )
   {
      SND_IMMUNITY = str_to_num(Sound)
      configOption = 1
   }else if ( equali(Word, "EXACT_MATCH") )
   {
      EXACT_MATCH = str_to_num(Sound)
      configOption = 1
   }else if ( equali(Word, "ADMINS_ONLY") )
   {
      ADMINS_ONLY = str_to_num(Sound)
      configOption = 1
   }else if ( equali(Word, "DISPLAY_KEYWORDS") )
   {
      DISPLAY_KEYWORDS = str_to_num(Sound)
      configOption = 1
   }
   
   if ( configOption )
   {
      // Do some error checking on the user-input numbers
      ErrorCheck()
     
      return PLUGIN_HANDLED
   }
   
   // Loop once for each keyword
   new i, j
   for( i = 0; i < MAX_KEYWORDS; ++i )
   {
      // If an empty string, then break this loop
      if ( strlen(sound_data[i][KEYWORD]) == 0 )
         break
     
      // If no match found, keep looping
      if ( !equal(Word, sound_data[i][KEYWORD], TOK_LENGTH) )
         continue
     
      // See if the Sound already exists
      for( j = 0; j < MAX_RANDOM; ++j )
      {
         // If an empty string, then break this loop
         if ( strlen(sound_data[i][KEY_SOUNDS][TOK_LENGTH * j]) == 0 )
            break
         
         // See if this is the same as the new Sound
         if ( equali(Sound, sound_data[i][KEY_SOUNDS][TOK_LENGTH * j], TOK_LENGTH) )
         {
            client_print(id, print_console, "[REDIRECTME] ^"%s; %s^" already exists", Word, Sound)
           
            return PLUGIN_HANDLED
         }
      }
     
      // If we reached the end, then there is no room
      if ( j >= MAX_RANDOM - 1 )
         client_print(id, print_console, "Sank Sounds >> No room for new Sound. Increase MAX_RANDOM and recompile")
      else
      {
         // Word exists, but Sound is new to the list, so add entry
         array_add_inner_element(i, j, Sound)
         
         client_print(id, print_console, "[REDIRECTME] ^"%s^" successfully added to ^"%s^"", Sound, Word)
      }
     
      return PLUGIN_HANDLED
   }
   
   // If we reached the end, then there is no room
   if ( i >= MAX_KEYWORDS )
      client_print(id, print_console, "[REDIRECTME] No room for new Word/Sound combo. Increase MAX_KEYWORDS and recompile")
   else
   {
      // Word/Sound combo is new to the list, so make a new entry
      array_add_element(i, Word)
      array_add_inner_element(i, j, Sound)
     
      client_print(id, print_console, "[REDIRECTME]^"%s; %s^" successfully added", Word, Sound)
   }
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// amx_sound_help lists all amx_sound commands and keywords to the user.
//
// Usage: amx_sound_help
//////////////////////////////////////////////////////////////////////////////
public amx_sound_help( id )
{
   print_sound_list(id)
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Turns on/off the playing of the Sound files for this plugin only
//////////////////////////////////////////////////////////////////////////////
public amx_sound( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new onoff[5]
   read_argv(1, onoff, 4)
   if ( equal(onoff, "on")
      || equal(onoff, "1") )
   {
      if ( bSoundsEnabled == 1 )
         console_print(id, "Sank Sounds >> Plugin already enabled")
      else
      {
         bSoundsEnabled = 1
         console_print(id, "Sank Sounds >> Plugin enabled")
         client_print(0, print_chat, "[REDIRECTME]Pluginul a fost dezactivat")
         if ( Enable_Sound[0] )
         {
            new type = Enable_Sound[0] == '^"' ? SOUND_TYPE_SPEECH : ( Enable_Sound[strlen(Enable_Sound) - 1] == '3' ? SOUND_TYPE_MP3 : SOUND_TYPE_WAV )
            playsoundall(Enable_Sound, type)
         }
      }
     
      return PLUGIN_HANDLED
   }else if ( equal(onoff, "off")
      || equal(onoff, "0") )
   {
      if ( bSoundsEnabled == 0 )
         console_print(id, "[REDIRECTME]Pluginul a fost dezactivat")
      else
      {
         bSoundsEnabled = 0
         console_print(id, "Sank Sounds >> Plugin disabled")
         client_print(0, print_chat, "[REDIRECTME] Plugin has been disabled")
         if ( Disable_Sound[0] )
         {
            new type = Disable_Sound[0] == '^"' ? SOUND_TYPE_SPEECH : ( Disable_Sound[strlen(Disable_Sound) - 1] == '3' ? SOUND_TYPE_MP3 : SOUND_TYPE_WAV )
            playsoundall(Disable_Sound, type)
         }
      }
   }
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Plays a sound to all players
//
// Usage: amx_sound_play <dir/sound>
//////////////////////////////////////////////////////////////////////////////
public amx_sound_play( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new arg[128]
   read_argv(1, arg, 127)
   
   if ( strlen(arg) < 1 )
   {
      client_print(id, print_console, "[REDIRECTME] Sound is invalid.")
     
      return PLUGIN_HANDLED
   }
   
   new type = arg[0] == '^"' ? SOUND_TYPE_SPEECH : ( arg[strlen(arg) - 1] == '3' ? SOUND_TYPE_MP3 : SOUND_TYPE_WAV )
   playsoundall(arg, type)
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Reloads the Word/Sound combos from filename
//
// Usage: amx_sound_reload <filename>
//////////////////////////////////////////////////////////////////////////////
public amx_sound_reload( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 0) )
      return PLUGIN_HANDLED
   
   new parsefile[128]
   read_argv(1, parsefile, 127)
   // Initialize sound_data array
   for( new i = 0; i < MAX_KEYWORDS; ++i )
      array_clear_element(i)
   
   parse_sound_file(parsefile, 0)
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Removes a Word/Sound combo from the list. You must specify a keyword, but it
// is not necessary to specify a Sound if you want to remove all Sounds associated
// with that keyword
//
// Usage: amx_sound_remove <keyWord> <dir/sound>"
//////////////////////////////////////////////////////////////////////////////
public amx_sound_remove( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new Word[TOK_LENGTH + 1], Sound[TOK_LENGTH + 1]
   
   read_argv(1, Word, TOK_LENGTH)
   read_argv(2, Sound, TOK_LENGTH)
   if ( strlen(Word) == 0 )
   {
      client_print(id, print_console, "[REDIRECTME] Invalid format")
      client_print(id, print_console, "[REDIRECTME] USAGE: amx_sound_remove keyword <dir/sound>")
     
      return PLUGIN_HANDLED
   }
   
   // speech must have extra ""
   if ( strlen(Sound) != 0
      && containi(Sound, ".wav") == -1
      && containi(Sound, ".mp") == -1 )
      format(Sound, TOK_LENGTH, "^"%s^"", Sound)
   
   // Loop once for each keyWord
   new iCurWord, jCurSound
   for( iCurWord = 0; iCurWord < MAX_KEYWORDS; ++iCurWord )
   {
      // If an empty string, then break this loop, we're at the end
      if ( strlen(sound_data[iCurWord][KEYWORD]) == 0 )
         break
     
      // Look for a Word match
      if ( !equali(Word, sound_data[iCurWord][KEYWORD], TOK_LENGTH) )
         continue
     
      // If no Sound was specified, then remove the whole Word's entry
      if ( strlen(Sound) == 0 )
      {
         // special check for join / exit keywords
         if ( iCurWord < 2 )
         {
            // safe join / exit data
            new temp_char = sound_data[iCurWord][KEYWORD][0]
            new temp_flag = sound_data[iCurWord][FLAGS]
           
            // Delete the last data
            array_clear_element(iCurWord)
           
            // restore data
            sound_data[iCurWord][KEYWORD][0] = temp_char
            sound_data[iCurWord][FLAGS] = temp_flag
           
            // We reached the end
            client_print(id, print_console, "[REDIRECTME] %s successfully cleared", Word)
           
            return PLUGIN_HANDLED
         }
         
         array_remove(iCurWord)
         
         client_print(id, print_console, "[REDIRECTME] %s successfully removed", Word)
         
         return PLUGIN_HANDLED
      }
     
      // Just remove the one Sound, if it exists
      for( jCurSound = 0; jCurSound < MAX_RANDOM; ++jCurSound )
      {
         // If an empty string, then break this loop, we're at the end
         if ( !strlen(sound_data[iCurWord][KEY_SOUNDS][TOK_LENGTH * jCurSound]) )
            break
         
         // Look for a Sound match
         if ( !equali(Sound, sound_data[iCurWord][KEY_SOUNDS][TOK_LENGTH * jCurSound], TOK_LENGTH) )
            continue
         
         if ( sound_data[iCurWord][SOUND_AMOUNT] == 1 )      // If this is the only Sound entry, then remove the entry altogether
         {
            array_remove(iCurWord)
           
            client_print(id, print_console, "[REDIRECTME] >> %s successfully removed", Word)
         }else
         {
            array_remove_inner(iCurWord, jCurSound)
           
            client_print(id, print_console, "[REDIRECTME] %s successfully removed from %s", Sound, Word)
         }
         
         return PLUGIN_HANDLED
      }
      // We reached the end for this Word, and the Sound didn't exist
      client_print(id, print_console, "[REDIRECTME] %s not found", Sound)
     
      return PLUGIN_HANDLED
   }
   // We reached the end, and the Word didn't exist
   client_print(id, print_console, "[REDIRECTME] %s not found", Word)
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Saves the current configuration of Word/Sound combos to filename for possible
// reloading at a later time. You cannot overwrite the default file.
//
// Usage: amx_sound_write <filename>
//////////////////////////////////////////////////////////////////////////////
public amx_sound_write( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new savefile[128]
   
   read_argv(1, savefile, 127)
   if ( strlen(savefile) == 0 )
   {
      client_print(id, print_console, "[REDIRECTME]Trebuie sa specifica?i un nume de fi?ier")
     
      return PLUGIN_HANDLED
   }
   
   // disallow to use same filename as the default config_filename
   if ( equali(savefile, config_filename) )
   {
      client_print(id, print_console, "[REDIRECTME]Illegal write to default sound config file")
      client_print(id, print_console, "[REDIRECTME]Specify a different filename")
     
      return PLUGIN_HANDLED
   }
   
   new TimeStamp[128], name[33], Text[BUFFER_LEN + TOK_LENGTH]
   new Textlen = BUFFER_LEN + TOK_LENGTH - 1
   get_user_name(id, name, 32)
   get_time("%H:%M:%S %A %B %d, %Y", TimeStamp, 127)
   
   new file = fopen(savefile, "w+")
   if ( !file )
   {
      log_amx("Sank Sounds >> Unable to read from ^"%s^" file", savefile)
     
      return PLUGIN_HANDLED
   }
   
   formatex(Text, Textlen, "# TimeStamp:^t^t%s^n", TimeStamp)
   fputs(file, Text)
   formatex(Text, Textlen, "# File created by:^t%s^n", name)
   fputs(file, Text)
   fputs(file, "^n")      // blank line
   fputs(file, "# Important parameters:^n")
   formatex(Text, Textlen, "SND_MAX;^t^t%d^n", SND_MAX)
   fputs(file, Text)
   formatex(Text, Textlen, "SND_MAX_DUR;^t^t%.1f^n", SND_MAX_DUR)
   fputs(file, Text)
   formatex(Text, Textlen, "SND_WARN;^t^t%d^n", SND_WARN)
   fputs(file, Text)
   
   new joinex_snd_buff[BUFFER_LEN]
   cfg_write_keysound(0, joinex_snd_buff, BUFFER_LEN - 1)
   formatex(Text, Textlen, "SND_JOIN;^t^t%s^n", joinex_snd_buff)
   fputs(file, Text)
   joinex_snd_buff[0] = 0
   cfg_write_keysound(1, joinex_snd_buff, BUFFER_LEN - 1)
   formatex(Text, Textlen, "SND_EXIT;^t^t%s^n", joinex_snd_buff)
   fputs(file, Text)
   formatex(Text, Textlen, "SND_DELAY;^t^t%f^n", SND_DELAY)
   fputs(file, Text)
   formatex(Text, Textlen, "SND_MODE;^t^t%d^n", SND_MODE)
   fputs(file, Text)
   new snd_imm_str[32]
   get_flags(SND_IMMUNITY, snd_imm_str, 26)
   formatex(Text, Textlen, "SND_IMMUNITY;^t^t^"%s^"^n", snd_imm_str)
   fputs(file, Text)
   formatex(Text, Textlen, "EXACT_MATCH;^t^t%d^n", EXACT_MATCH)
   fputs(file, Text)
   formatex(Text, Textlen, "ADMINS_ONLY;^t^t%d^n", ADMINS_ONLY)
   fputs(file, Text)
   formatex(Text, Textlen, "DISPLAY_KEYWORDS;^t%d^n", DISPLAY_KEYWORDS)
   fputs(file, Text)
   fputs(file, "^n")      // blank line
   fputs(file, "# Word/Sound combinations:^n")
   
   for ( new i = 2; i < MAX_KEYWORDS; ++i )   // first 2 elements are reserved for Join / Exit sounds
   {
      // See if we reached the end
      if ( strlen(sound_data[i][KEYWORD]) == 0 )
         break
     
      cfg_write_keyword(i, Text, Textlen)
      cfg_write_keysound(i, Text, Textlen)
     
      new text_len = strlen(Text)
      if ( text_len + 2 <= BUFFER_LEN )
      {
         Text[text_len] = '^n'   // add new line
         Text[text_len + 1] = 0
      }
     
      // Now write the formatted string to the file
      fputs(file, Text)
     
      // And loop for the next Sound
   }
   
   fclose(file)
   
   client_print(id, print_console, "[REDIRECTME]Configuratia cu succes scris în %s", savefile)
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Prints out Word/Sound combo matrix for debugging purposes. Kinda cool, even
// if you're not really debugging.
//
// Usage: amx_sound_debug
// Usage: amx_sound_reload <filename>
//////////////////////////////////////////////////////////////////////////////
public amx_sound_debug( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 1)
      && id > 0 )
      return PLUGIN_HANDLED
   
   new i, j, join_snd_buff[BUFFER_LEN], exit_snd_buff[BUFFER_LEN]
   
   if ( !is_dedicated_server()
      && id == 1 )   // for listenserver and with id = 1 we can use server_print
      id = 0
   
   if ( id )
      client_print(id, print_console, "SND_WARN: %d^nSND_MAX: %d^nSND_MAX_DUR: %5.1f^n", SND_WARN, SND_MAX, SND_MAX_DUR)
   else
      server_print("SND_WARN: %d^nSND_MAX: %d^nSND_MAX_DUR: %5.1f^n", SND_WARN, SND_MAX, SND_MAX_DUR)
   
   for( i = 0; i < MAX_RANDOM; ++i )
   {
      new tempstr[TOK_LENGTH]
      if ( strlen(sound_data[0][KEY_SOUNDS][TOK_LENGTH * i]) )
      {
         formatex(tempstr, TOK_LENGTH, "%s;", sound_data[0][KEY_SOUNDS][TOK_LENGTH * i])
         add(join_snd_buff, BUFFER_LEN, tempstr)
      }
      if ( strlen(sound_data[1][KEY_SOUNDS][TOK_LENGTH * i]) )
      {
         formatex(tempstr, TOK_LENGTH, "%s;", sound_data[1][KEY_SOUNDS][TOK_LENGTH * i])
         add(exit_snd_buff, BUFFER_LEN, tempstr)
      }
   }
   
   new snd_imm_str[32]
   get_flags(SND_IMMUNITY, snd_imm_str, 26)
   if ( id )
   {
      client_print(id, print_console, "SND_JOIN: %s", join_snd_buff)
      client_print(id, print_console, "SND_EXIT: %s", exit_snd_buff)
      client_print(id, print_console, "SND_DELAY: %f^nSND_MODE: %d^nSND_IMMUNITY: %s^nEXACT_MATCH: %d", SND_DELAY, SND_MODE, snd_imm_str, EXACT_MATCH)
      client_print(id, print_console, "ADMINS_ONLY: %d^nDISPLAY_KEYWORDS: %d", ADMINS_ONLY, DISPLAY_KEYWORDS)
   }else
   {
      server_print("SND_JOIN: %s^n", join_snd_buff)
      server_print("SND_EXIT: %s^n", exit_snd_buff)
      server_print("SND_DELAY: %f^nSND_MODE: %d^nSND_IMMUNITY: %s^nEXACT_MATCH: %d^n", SND_DELAY, SND_MODE, snd_imm_str, EXACT_MATCH)
      server_print("ADMINS_ONLY: %d^nDISPLAY_KEYWORDS: %d^n", ADMINS_ONLY, DISPLAY_KEYWORDS)
   }
   
   // Print out the matrix of sound data, so we got what we think we did
   for( i = 2; i < MAX_KEYWORDS; ++i )   // first 2 elements are reserved for Join / Exit sounds
   {
      if ( strlen(sound_data[i][KEYWORD]) == 0 )
         break

      new access_level[32]
      get_flags(sound_data[i][ADMIN_LEVEL_BASE], access_level, 31)
      if ( id )
         client_print(id, print_console, "^n[%d] ^"%s^" with %d sound%s and level ^"%s^" (played: %d)", i - 2, sound_data[i][KEYWORD], sound_data[i][SOUND_AMOUNT], sound_data[i][SOUND_AMOUNT] > 1 ? "s" : "", access_level, sound_data[i][PLAY_COUNT_KEY])
      else
         server_print("^n[%d] ^"%s^" with %d sound%s and level ^"%s^" (played: %d)", i - 2, sound_data[i][KEYWORD], sound_data[i][SOUND_AMOUNT], sound_data[i][SOUND_AMOUNT] > 1 ? "s" : "", access_level, sound_data[i][PLAY_COUNT_KEY])
      for( j = 0; j < MAX_RANDOM; ++j )
      {
         if ( strlen(sound_data[i][KEY_SOUNDS][j * TOK_LENGTH]) == 0 )
            continue

         get_flags(sound_data[i][ADMIN_LEVEL][j], access_level, 31)
         if ( id )
            client_print(id, print_console, " ^"%s^" - time: %5.2f - admin level ^"%s^" (played: %d)", sound_data[i][KEY_SOUNDS][j * TOK_LENGTH], sound_data[i][DURATION][j], access_level, sound_data[i][PLAY_COUNT][j])
         else
            server_print(" ^"%s^" - time: %5.2f - admin level ^"%s^" (played: %d)", sound_data[i][KEY_SOUNDS][j * TOK_LENGTH], sound_data[i][DURATION][j], access_level, sound_data[i][PLAY_COUNT][j])
      }
   }
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Bans players from using sounds for current map
//
// Usage: amx_sound_ban <player>
//////////////////////////////////////////////////////////////////////////////
public amx_sound_ban( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new arg[33]
   read_argv(1, arg, 32)
   new player = cmd_target(id, arg, 1)
   if ( !player )
      return PLUGIN_HANDLED
   
   if ( get_user_flags(player) & SND_IMMUNITY )
      return PLUGIN_HANDLED
   
   if ( restrict_playing_sounds[player] == -1 )
   {
      new found, empty = -1
      new steamid[60]
      get_user_authid(id, steamid, 59)
      for ( new i = 0; i < MAX_BANS; ++i )
      {
         if ( empty == -1
            && !banned_player_steamids[i][0] )
            empty = i
         
         if ( !equal(steamid, banned_player_steamids[i]) )
            continue
         
         found = 1
         
         break
      }
      if ( !found )
      {
         if ( empty == -1 )
            empty = 0
         
         copy(banned_player_steamids[empty], 59, steamid)
         
         restrict_playing_sounds[player] = empty
      }
   }
   
   new name[33]
   get_user_name(player, name, 32)
   client_print(id, print_console, "[REDIRECTME]Jucatorului ^"%s^" ia fost interzis de a mai utilizarea sunete", name)
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Unbans players from using sounds for current map
//
// Usage: amx_sound_unban <player>
//////////////////////////////////////////////////////////////////////////////
public amx_sound_unban( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 2) )
      return PLUGIN_HANDLED
   
   new arg[33]
   read_argv(1, arg, 32)
   new player = cmd_target(id, arg)
   if ( !player )
      return PLUGIN_HANDLED
   
   if ( restrict_playing_sounds[player] != -1 )
   {
      new found = -1
      new steamid[60]
      get_user_authid(id, steamid, 59)
      for ( new i = 0; i < MAX_BANS; ++i )
      {
         if ( !equal(steamid, banned_player_steamids[i]) )
            continue
         
         found = i
         
         break
      }
      if ( found != -1 )
         banned_player_steamids[found][0] = 0
     
      restrict_playing_sounds[player] = -1
   }
   
   new name[33]
   get_user_name(player, name, 32)
   client_print(id, print_console, "[REDIRECTME]Jucatorul ^"%s^" a fost debanat de la utilizarea sunete", name)
   
   return PLUGIN_HANDLED
}

public amx_sound_top( id , level , cid )
{
   if ( !cmd_access(id, level, cid, 1) )
      return PLUGIN_HANDLED
   
   new arg[33]
   read_argv(1, arg, 32)
   new topX = 10
   if ( strlen(arg) > 0 )
      topX = str_to_num(arg)
   
   if ( topX < 1
      || topX > 50 )
   {
      client_print(id, print_console, "[REDIRECTME]Setati o valoare de la 1 la 50 sau lasati-l necompletat")
      return PLUGIN_HANDLED
   }
   
   new topIDs[50] = {-1, ...}
   new topCount[50] = {0, ...}
   for ( new keyIndex = 0; keyIndex < MAX_KEYWORDS; ++keyIndex )
   {
      // end of list reached
      if ( sound_data[keyIndex][KEYWORD][0] == 0 )
         break
     
      for ( new i = 0; i < topX; ++i )
      {
         if ( sound_data[keyIndex][PLAY_COUNT_KEY] <= topCount[i] )
            continue
         
         // copy all other down
         for ( new j = topX - 1; j > i; --j )
         {
            topIDs[j] = topIDs[j - 1]
            topCount[j] = topCount[j - 1]
         }
         topIDs[i] = keyIndex
         topCount[i] = sound_data[keyIndex][PLAY_COUNT_KEY]
         break
      }
   }
   new text[512]
   new counter = 0
   client_print(id, print_console, "Sank Sounds >> Top %d:", topX)
   while ( counter < topX )
   {
      if ( topIDs[counter] != -1 )
         format(text, 511, "%s(%d) %s^n", text, topCount[counter], sound_data[topIDs[counter]][KEYWORD])
      else
         counter = topX - 1
      if ( (counter % 10 == 0
            && counter != 0 )
         || counter == topX - 1 )
      {
         client_print(id, print_console, text)
         text[0] = 0
      }
      ++counter
   }
   
   return PLUGIN_HANDLED
}

//////////////////////////////////////////////////////////////////////////////
// Everything a person says goes through here, and we determine if we want to
// play a sound or not.
//
// Usage: say <anything>
//////////////////////////////////////////////////////////////////////////////
public HandleSay( id )
{
   // If sounds are not enabled, then skip this whole thing
   if ( !bSoundsEnabled )
      return PLUGIN_CONTINUE
   
   // player is banned from playing sounds
   if ( restrict_playing_sounds[id] != -1 )
      return PLUGIN_CONTINUE
   
   new Speech[128]
   read_args(Speech, 127)
   remove_quotes(Speech)
   
   // credit to SR71Goku for fixing this oversight:
   new speachLen = strlen(Speech)
   if ( !speachLen )
      return PLUGIN_CONTINUE
   
   if ( equal(Speech, "/sound", 6) )
   {
      if ( Speech[6] == 's' )
      {
         if ( Speech[7] == 'o'
            && Speech[8] == 'n' )
         {
            SndOn[id] = 1
            client_print(id, print_chat, "[REDIRECTME]Veti auzi toate sunetele din nou")
         }else if ( Speech[7] == 'o'
            && Speech[8] == 'f'
            && Speech[9] == 'f'
            && Speech[10] == 0 )
         {
            SndOn[id] = 0
            client_print(id, print_chat, "[REDIRECTME]Eu voi opri sunetul pentru tine")
         }else if ( Speech[7] == 0 )
            print_sound_list(id, 1)
         else
            return PLUGIN_CONTINUE
         
         return PLUGIN_HANDLED
      }else if ( Speech[6] == 'l'
         && Speech[7] == 'i'
         && Speech[8] == 's'
         && Speech[9] == 't'
         && Speech[10] == 0 )
      {
         print_sound_list(id, 1)
         
         return PLUGIN_HANDLED
      }
     
      return PLUGIN_CONTINUE
   }
   
   new ListIndex = -1
   new pinToLocation = (Speech[speachLen - 1] == '!')
   // Check to see if what the player said is a trigger for a sound
   for ( new i = 2; i < MAX_KEYWORDS; ++i )   // first 2 elements are reserved for Join / Exit sounds
   {
      // end of list reached
      if ( sound_data[i][KEYWORD][0] == 0 )
         break
     
      if ( equali(Speech, sound_data[i][KEYWORD])
         || (EXACT_MATCH == 1
            && pinToLocation == 1
            && speachLen == strlen(sound_data[i][KEYWORD]) + 1
            && equali(Speech, sound_data[i][KEYWORD], speachLen - 1) )
         || ( EXACT_MATCH == 0
            && containi(Speech, sound_data[i][KEYWORD]) != -1 ) )
      {
         // check for access
         if ( sound_data[i][ADMIN_LEVEL_BASE] == 0
            || get_user_flags(id) & sound_data[i][ADMIN_LEVEL_BASE] )
            ListIndex = i
         
         break
      }
   }
   
   // check If player used NO sound trigger
   if ( ListIndex == -1 )
      return PLUGIN_CONTINUE
   
   new obey_duration_mode = get_pcvar_num(CVAR_obey_duration)
   new admin_flags = get_user_flags(id)
   new Float:gametime = get_gametime()
   if ( gametime > NextSoundTime + SND_DELAY         // 1.  check for sound overlapping + delay time
      || ( admin_flags & ADMIN_RCON            // 2.  check if super admin
         && !(obey_duration_mode & 4) )         // 2b. check if super admin have to obey duration
      || ( admin_flags & SND_IMMUNITY            // 3.  check if admin
         && !(obey_duration_mode & 2) )         // 3b. check if admin have to obey duration
      || ( !(obey_duration_mode & 1)            // 4.  check if overlapping is allowed
         && gametime > LastSoundTime + SND_DELAY ) )   // 4b. or for delay time
   {
      // check if player is allowed to play sounds depending on config
      new alive = is_user_alive(id)
      if ( SND_MODE & ( alive + 1 )
         && !QuotaExceeded(id) )      // If the user has not exceeded their quota, then play a Sound
      {
         new rand = random(sound_data[ListIndex][SOUND_AMOUNT])
         new timeout
         new playFile[TOK_LENGTH]
         
         // This for loop runs around until it finds a real file to play
         // Defaults to the first Sound file, if no file is found at random.
         for( timeout = MAX_RANDOM;         // Initial condition
            timeout >= 0 && !strlen(playFile);   // While these are true
            --timeout )            // Update each iteration
         {
            rand = random(sound_data[ListIndex][SOUND_AMOUNT])
            // If for some reason we never find a file
            //  then default to the first Sound entry
            if ( !timeout )
               rand = 0
           
            // check if sound has access defined, if so only allow admins to use it
            if ( sound_data[ListIndex][ADMIN_LEVEL][rand] == 0
               || ( get_user_flags(id) & sound_data[ListIndex][ADMIN_LEVEL][rand] ) )
               copy(playFile, TOK_LENGTH, sound_data[ListIndex][KEY_SOUNDS][rand * TOK_LENGTH])
         }
         
         if ( playFile[0] )
         {
            NextSoundTime = gametime + sound_data[ListIndex][DURATION][rand]
           
            // Increment their playsound count
            ++SndCount[id]
            SndLenghtCount[id] += sound_data[ListIndex][DURATION][rand]
           
            // increment counter
            ++sound_data[ListIndex][PLAY_COUNT_KEY]
            ++sound_data[ListIndex][PLAY_COUNT][rand]
           
            new type = sound_data[ListIndex][SOUND_TYPE][rand]
            if ( pinToLocation == 1
               && type == SOUND_TYPE_WAV )
               type = SOUND_TYPE_WAV_LOCAL
            playsoundall(playFile, type, SND_MODE & 16, alive)
           
            LastSoundTime = gametime
         }
      }
   }else if ( gametime <= NextSoundTime + SND_DELAY
      && obey_duration_mode != 0 )
      client_print(id, print_chat, "[REDIRECTME]Sunetul inca se aude (asteapta %3.1f secunde )", NextSoundTime + SND_DELAY - gametime)
   else
      client_print(id, print_chat, "[REDIRECTME]Nu utiliza?i sunete prea des( asteapta %3.1f secunde )", LastSoundTime + SND_DELAY - gametime)
   
   if ( DISPLAY_KEYWORDS == 0 )
      return PLUGIN_HANDLED
   
   return PLUGIN_CONTINUE
}

//////////////////////////////////////////////////////////////////////////////
// Parses the sound file specified by loadfile. If loadfile is empty, then
// it parses the default config_filename.
//////////////////////////////////////////////////////////////////////////////
parse_sound_file( loadfile[] , precache_sounds = 1 )
{
   if ( !strlen(loadfile) )
      copy(loadfile, 127, config_filename)
   
   if ( !file_exists(loadfile) )
   {
      // file does not exist
      log_amx("Sank Sounds >> Cannot find ^"%s^" file", loadfile)
     
      return
   }
   
   new current_package_str[4]
   new current_package, package_num
   if ( vaultdata_exists("sank_sounds_current_package") )
   {
      get_vaultdata("sank_sounds_current_package", current_package_str, 3)
      current_package = str_to_num(current_package_str)
   }
   
   new allowed_to_precache = 1, allow_check_existence = 1, allow_to_use_sounds = 1
   new allow_global_precache = get_cvar_num("mp_sank_sounds_download")
   new mapname[32]
   get_mapname(mapname, 31)
   
   new i
   new ListIndex = -1
   new tmpIndex = -1
   new maxLineBuf_len = ( BUFFER_LEN + TOK_LENGTH ) - 1
   new strLineBuf[BUFFER_LEN + TOK_LENGTH]
   
   new error_code = ERROR_NONE
   new parse_option = PARSE_KEYWORD
   new temp_str[128]
   new check_for_semi
   new position
   
   new file = fopen(loadfile, "r")
   if ( !file )
   {
      log_amx("Sank Sounds >> Unable to read from ^"%s^" file", loadfile)

      return
   }
   
   while ( fgets(file, strLineBuf, maxLineBuf_len) )
   {
      if ( (strLineBuf[0] == '^n')                  // empty line
         || ( strLineBuf[0] == 10 && strLineBuf[1] == '^n' )      // empty line
         || ( strLineBuf[0] == '/' && strLineBuf[1] == '/' )      // comment
         || (strLineBuf[0] == '#') )               // another comment
         continue
     
      trim(strLineBuf)   // remove newline and spaces
     
      if ( equali(strLineBuf, "package ", 8) )
      {
         ++package_num
         if ( current_package )
         {
            if ( current_package == str_to_num(strLineBuf[8]) )
               allowed_to_precache = 1
            else
               allowed_to_precache = 0
         }else
         {
            current_package = 1
            allowed_to_precache = 1
         }
         
         allow_to_use_sounds = 1
         allow_check_existence = 1
         
         continue
      }else if ( equali(strLineBuf, "mapname ", 8) )
      {
         if ( equali(strLineBuf[8], mapname) )
            allowed_to_precache = 1
         else
            allowed_to_precache = 0
         
         allow_to_use_sounds = 1
         allow_check_existence = 1
         
         continue
      }else if ( equali(strLineBuf, "mapnameonly ", 12) )
      {
         if ( equali(strLineBuf[12], mapname) )
         {
            allowed_to_precache = 1
            allow_to_use_sounds = 1
         }else
         {
            allowed_to_precache = 0
            allow_to_use_sounds = 0
         }
         
         allow_check_existence = 1
         
         continue
      }else if ( equali(strLineBuf, "modspecific", 11) )
      {
         allow_to_use_sounds = 1
         allow_check_existence = 0
         
         continue
      }
     
      if ( !allow_to_use_sounds )   // check for sounds that can be used only on specified map
         continue
     
      if ( ListIndex >= MAX_KEYWORDS )
      {
         log_amx("Sank Sounds >> Sound list truncated. Increase MAX_KEYWORDS. Stopped parsing file ^"%s^"^n", loadfile)
         
         break
      }
     
      error_code = ERROR_NONE
      position = 0
      for( i = 0; i < MAX_RANDOM; ++i )
      {
         // check if reached end of buffer ( input has been parsed )
         if ( position >= strlen(strLineBuf) )
         {
            strLineBuf[0] = 0
            break
         }
         
         temp_str[0] = 0      // reset
         check_for_semi = contain(strLineBuf[position], ";")
         if ( check_for_semi != -1 )
         {
            copyc(temp_str, 127, strLineBuf[position], ';')
            position += check_for_semi + 1
         }else
         {
            copy(temp_str, 127, strLineBuf[position])
            position += strlen(temp_str)
         }
         
         // Now remove any spaces or tabs from around the strings -- clean them up
         trim(temp_str)
         
         // check if file length is bigger than array
         if ( strlen(temp_str) > TOK_LENGTH )
         {
            error_code = ERROR_STRING_LENGTH
           
            break
         }
         
         if ( i == 0 )
         {   // first entry is not a sound file
            if ( equali(temp_str, "SND_MAX") )
               parse_option = PARSE_SND_MAX
            else if ( equali(temp_str, "SND_MAX_DUR") )
               parse_option = PARSE_SND_MAX_DUR
            else if ( equali(temp_str, "SND_WARN") )
               parse_option = PARSE_SND_WARN
            else if ( equali(temp_str, "SND_DELAY") )
               parse_option = PARSE_SND_DELAY
            else if ( equali(temp_str, "SND_MODE") )
               parse_option = PARSE_SND_MODE
            else if ( equali(temp_str, "SND_IMMUNITY") )
               parse_option = PARSE_SND_IMMUNITY
            else if ( equali(temp_str, "EXACT_MATCH") )
               parse_option = PARSE_EXACT_MATCH
            else if ( equali(temp_str, "ADMINS_ONLY") )
               parse_option = PARSE_ADMINS_ONLY
            else if ( equali(temp_str, "DISPLAY_KEYWORDS") )
               parse_option = PARSE_DISPLAY_KEYWORDS
            else
            {
               parse_option = PARSE_KEYWORD
               if ( ListIndex != -1
                  && sound_data[ListIndex][SOUND_AMOUNT] == 0
                  && !(sound_data[ListIndex][FLAGS] & FLAG_IGNORE_AMOUNT) )   // check if allowed to ignore amount of sounds ( eg: SND_JOIN / SND_EXIT )
                  log_amx("Sank Sounds >> Found keyword without any valid sound. Skipping this keyword: ^"%s^"", sound_data[ListIndex][KEYWORD])
               else
                  ++ListIndex
               
               if ( ListIndex >= MAX_KEYWORDS )
               {
                  error_code = ERROR_MAX_KEYWORDS
                 
                  break
               }
               
               new result = array_add_element(ListIndex, temp_str)
               if ( result > -1 )
               {
                  tmpIndex = result
                  --ListIndex
               }else
               {
                  tmpIndex = -1
                  if ( result == -1 )
                     ListIndex = 2
               }
            }
         }else
         {
            switch ( parse_option )
            {
               case PARSE_SND_MAX:
               {
                  SND_MAX = str_to_num(temp_str)
               }
               case PARSE_SND_MAX_DUR:
               {
                  SND_MAX_DUR = floatstr(temp_str)
               }
               case PARSE_SND_WARN:
               {
                  SND_WARN = str_to_num(temp_str)
               }
               case PARSE_SND_DELAY:
               {
                  SND_DELAY = floatstr(temp_str)
               }
               case PARSE_SND_MODE:
               {
                  SND_MODE = str_to_num(temp_str)
               }
               case PARSE_SND_IMMUNITY:
               {
                  if ( temp_str[0] == '^"' )
                  {
                     new temp_str2[32]
                     copyc(temp_str2, 31, temp_str[1], '^"')
                     if ( strlen(temp_str2) == 0 )
                        SND_IMMUNITY = (1<<30)
                     else
                        SND_IMMUNITY = read_flags(temp_str2)
                  }else
                     SND_IMMUNITY = read_flags(temp_str)
               }
               case PARSE_EXACT_MATCH:
               {
                  EXACT_MATCH = str_to_num(temp_str)
               }
               case PARSE_ADMINS_ONLY:
               {
                  ADMINS_ONLY = str_to_num(temp_str)
               }
               case PARSE_DISPLAY_KEYWORDS:
               {
                  DISPLAY_KEYWORDS = str_to_num(temp_str)
               }
               case PARSE_KEYWORD:
               {
                  new error_value = -1
                  if ( tmpIndex != -1 )
                     error_value = array_add_inner_element(tmpIndex, i - 1, temp_str, allow_check_existence, allow_global_precache, precache_sounds, allowed_to_precache)
                  else
                     error_value = array_add_inner_element(ListIndex, i - 1, temp_str, allow_check_existence, allow_global_precache, precache_sounds, allowed_to_precache)
                  if ( error_value == -1 )
                  {
                     // sound could not be added, so clear that array entry
                     if ( tmpIndex != -1 )
                        array_clear_inner_element(tmpIndex, i - 1)
                     else
                        array_clear_inner_element(ListIndex, i - 1)
                     
                     continue
                  }
               }
            }
         }
      }
     
      // Error occured so skip Word/Sound Combo
      if ( error_code == ERROR_MAX_KEYWORDS )
      {
         log_amx("Sank Sounds >> Sound list truncated. Increase MAX_KEYWORDS. Stopped parsing file ^"%s^"^n", loadfile)
         
         break
      }
     
      if ( error_code == ERROR_STRING_LENGTH )
      {
         log_amx("Sank Sounds >> Skipping this word/sound combo. Word or Sound is too long: ^"%s^". Length is %i but max is %i (change name/remove spaces in config or increase TOK_LENGTH)", temp_str, strlen(temp_str), TOK_LENGTH)
         
         continue
      }
      if ( error_code != ERROR_NONE )
      {
         log_amx("Sank Sounds >> Fatal Error")
         
         continue
      }
     
      // If we finished MAX_RANDOM times, and strLineBuf[position] still has contents
      // then we should have a bigger MAX_RANDOM
      else if ( position < strlen(strLineBuf) )
      {
         log_amx("Sank Sounds >> Sound list partially truncated. Increase MAX_RANDOM. Continuing to parse file ^"%s^"^n", loadfile)
      }
   }
   
   fclose(file)
   
   if ( ListIndex != -1 )
   {
      if ( sound_data[ListIndex][SOUND_AMOUNT] == 0
         && !(sound_data[ListIndex][FLAGS] & FLAG_IGNORE_AMOUNT) )   // check if allowed to ignore amount of sounds ( eg: SND_JOIN / SND_EXIT )
      {
         log_amx("Sank Sounds >> Found keyword without any valid sound. Skipping this keyword: ^"%s^"", sound_data[ListIndex][KEYWORD])
         sound_data[ListIndex][KEYWORD][0] = 0
         --ListIndex
      }
   }
   
   // Now we have all of the data from the text file in our data structures.
   // Next we do some error checking, some setup, and we're done parsing!
   ErrorCheck()
   
   ++current_package
   if ( current_package > package_num )
      current_package = 1
   
   num_to_str(current_package, current_package_str, 3)
   set_vaultdata("sank_sounds_current_package", current_package_str)
   
   //++ListIndex
#if ALLOW_SORT == 1
   if ( ListIndex > 1 )
      sort_HeapSort(ListIndex - 1)   // -2 cause first two are reserved for join/exit sounds
#endif
}

//////////////////////////////////////////////////////////////////////////////
// Returns 0 if the user is allowed to say things
// Returns 1 and mutes the user if the quota has been exceeded.
//////////////////////////////////////////////////////////////////////////////
QuotaExceeded( id )
{
   // check if is admin
   new admin_check = ( get_user_flags(id) & SND_IMMUNITY )
   if ( ADMINS_ONLY && !admin_check )
      return 1
   
   // If the sound limitation is disabled, then return happily.
   if ( admin_check )
      return 0
   
   if ( SND_MAX != 0 )
   {
      if ( SndCount[id] >= SND_MAX )
      {
         if ( SndCount[id] - 3 < SND_MAX )
         {
            client_print(id, print_chat, "[REDIRECTME]Ai fost avertizat, esti mut")

            // player is already muted, we increament here to save a variable to protect player from "you are muted" spam ( only 3 warnings )
            ++SndCount[id]
         }
         
         return 1
      }else if ( SndCount[id] >= SND_WARN )
      {
         if ( SndCount[id] + 1 == SND_MAX )
            client_print(id, print_chat, "[REDIRECTME]Daca mai incerci o sa iei mute")
         else
            client_print(id, print_chat, "[REDIRECTME]Daca mai incerci inca o data iei mute")
      }
   }
   
   if ( SND_MAX_DUR != 0.0
      && SndLenghtCount[id] > SND_MAX_DUR )
      return 1
   
   return 0
}

//////////////////////////////////////////////////////////////////////////////
// Checks the input variables for invalid values
//////////////////////////////////////////////////////////////////////////////
ErrorCheck( )
{
   // Can't have negative delay between sounds
   if ( SND_DELAY < 0.0 )
   {
      log_amx("Sank Sounds >> SND_DELAY cannot be negative. Setting to value: 0")
      SND_DELAY = 0.0
   }
   
   // If SND_MAX is zero, then sounds quota is disabled. Can't have negative quota
   if ( SND_MAX < 0 )
   {
      SND_MAX = 0   // in case it was negative
      log_amx("Sank Sounds >> SND_MAX cannot be negative. Setting to value: 0")
   }
   
   // If SND_MAX_DUR is zero, then sounds quota is disabled. Can't have negative quota
   if ( SND_MAX_DUR < 0.0 )
   {
      SND_MAX_DUR = 0.0   // in case it was negative
      log_amx("Sank Sounds >> SND_MAX_DUR cannot be negative. Setting to value: 0.0")
   }
   
   // If SND_WARN is zero, then we can't have warning every time a keyword is said,
   // so we default to 3 less than max
   else if ( ( SND_WARN <= 0 && SND_MAX != 0 )
      || SND_MAX < SND_WARN )
   {
      if ( SND_MAX < SND_WARN  )
         // And finally, if they want to warn after a person has been
         // muted, that's silly, so we'll fix it.
         log_amx("Sank Sounds >> SND_WARN cannot be higher than SND_MAX")
      else if ( SND_WARN <= 0 )
         log_amx("Sank Sounds >> SND_WARN cannot be set to zero")
     
      if ( SND_MAX > 3 )
         SND_WARN = SND_MAX - 3
      else
         SND_WARN = SND_MAX - 1
     
      log_amx("Sank Sounds >> SND_WARN set to default value: %i", SND_WARN)
   }
}

playsoundall( sound[] , type , split_dead_alive = 0 , sender_alive_status = 0 )
{
   new alive
   for( new i = 1; i <= g_max_players; ++i )
   {
      if ( !is_user_connected(i) )
         continue
     
      if ( is_user_bot(i) )
         continue
     
      if ( !SndOn[i] )
         continue
     
      alive = is_user_alive(i)
      if ( !(SND_MODE & ( alive * 4 + 4 )) )
         continue
     
      if ( split_dead_alive
         && alive != sender_alive_status      // make sure if splited both are in same group
         && !(SND_MODE & ( alive * 32 + 32 )) )   // OR check if different groups may hear each other
         continue
     
      if ( type == SOUND_TYPE_MP3 )
         client_cmd(i, "mp3 play ^"%s^"", sound)
      else if ( type == SOUND_TYPE_WAV_LOCAL )
         client_cmd(i, "play ^"%s^"", sound)
      else if ( type == SOUND_TYPE_SPEECH )
         client_cmd(i, "spk %s", sound)
      else
         client_cmd(i, "spk ^"%s^"", sound)
   }
}

print_sound_list( id , motd_msg = 0 )
{
   new text[256], motd_buffer[2048], ilen, skip_for_loop
   new info_text[64] = "say < keyword >: plays A sound. keYwords are listed Below:"
   if ( strlen(motd_sound_list_address) > 3 )   // make sure at least you have something like: a.b ( http://a.b )
   {
      copy(motd_buffer, 127, motd_sound_list_address)
      skip_for_loop = 1
      motd_msg = 1
   }else if ( motd_msg )
      ilen = format(motd_buffer, 2047, "<body bgcolor=#000000><font color=#FFB000><pre>%s^n", info_text)
   else
      client_print(id, print_console, info_text)
   
   // Loop once for each keyword
   new i, j = -1
   for ( i = 2; i < MAX_KEYWORDS && skip_for_loop == 0; ++i )   // first 2 elements are reserved for Join / Exit sounds
   {
      // If an invalid string, then break this loop
      if ( strlen(sound_data[i][KEYWORD]) == 0
         || strlen(sound_data[i][KEYWORD]) > TOK_LENGTH )
         break
     
      // check if player can see admin sounds
      ++j
      new found_stricted = 0
      if ( sound_data[i][ADMIN_LEVEL_BASE] == 0
         || get_user_flags(id) & sound_data[i][ADMIN_LEVEL_BASE] )
      {
         if ( motd_msg )
            ilen += format(motd_buffer[ilen], 2047 - ilen, "%s", sound_data[i][KEYWORD])
         else
            add(text, 255, sound_data[i][KEYWORD])
      }else
      {
         --j
         found_stricted = 1
      }
     
      if ( !found_stricted )
      {
         if ( j % NUM_PER_LINE == NUM_PER_LINE - 1 )
         {
            // We got NUM_PER_LINE on this line,
            // so print it and start on the next line
            if ( motd_msg )
               ilen += format(motd_buffer[ilen], 2047 - ilen, "^n")
            else
            {
               client_print(id, print_console, "%s", text)
               text[0] = 0
            }
         }else
         {
            if ( motd_msg )
               ilen += format(motd_buffer[ilen], 2047 - ilen, " | ")
            else
               add(text, 255, " | ")
         }
      }
   }
   if ( motd_msg
      && strlen(motd_buffer) )
      show_motd(id, motd_buffer)
   else if ( strlen(text) )
      client_print(id, print_console, text)
}

#if ALLOW_SORT == 1
// 4 functions for array sort ( by Bailopan ) ( customized to fit plugin )
sort_HeapSort( ListIndex )
{
   new i
   new aSize = ( ListIndex / 2 ) - 1
   for ( i = aSize; i >= 0; --i )
      sort_SiftDown(i, ListIndex - 1)
   
   for ( i = ListIndex - 1; i >= 1; --i )
   {
      array_switch_elements(0, i)
      sort_SiftDown(0, i - 1)
   }
}

sort_compare( elem1 , elem2 )
{
   // skip first 2 elements ( join / exit )
   elem1 += 2
   elem2 += 2
   
   new i = 0
   for ( i = 0; i < TOK_LENGTH; ++i )
   {
      if ( sound_data[elem1][KEYWORD][i] != sound_data[elem2][KEYWORD][i] )
      {
         if ( sound_data[elem1][KEYWORD][i] > sound_data[elem2][KEYWORD][i] )
            return 1
         
         return -1
      }
   }
   
   return 0
}

sort_SiftDown( root , bottom )
{
   new done, child
   while ( ( root * 2 <= bottom ) && !done )
   {
      if ( root * 2 == bottom )
         child = root * 2
      else if ( sort_compare(root * 2, root * 2 + 1) > 0 )
         child = root * 2
      else
         child = root * 2 + 1
     
      if ( sort_compare(root, child) < 0 )
      {
         array_switch_elements(root, child)
         root = child
      }else
         done = 1
   }
}

array_switch_elements( element_one , element_two )
{
   // skip first 2 elements ( join / exit )
   element_one += 2
   element_two += 2
   
   new i
   new temp_sounds[BUFFER_LEN]
   new temp_keyword[TOK_LENGTH]
   new temp_int, Float:temp_float, temp_access, temp_access_base, temp_type, temp_flags, temp_play_count
   
   copy(temp_keyword, TOK_LENGTH, sound_data[element_one][KEYWORD])
   for ( i = 0; i < BUFFER_LEN; ++i )
      temp_sounds[i] = sound_data[element_one][KEY_SOUNDS][i]
   temp_int = sound_data[element_one][SOUND_AMOUNT]
   temp_access_base = sound_data[element_one][ADMIN_LEVEL_BASE]
   temp_flags = sound_data[element_one][FLAGS]
   temp_play_count = sound_data[element_one][PLAY_COUNT_KEY]
   
   copy(sound_data[element_one][KEYWORD], TOK_LENGTH, sound_data[element_two][KEYWORD])
   for ( i = 0; i < BUFFER_LEN; ++i )
      sound_data[element_one][KEY_SOUNDS][i] = sound_data[element_two][KEY_SOUNDS][i]
   sound_data[element_one][SOUND_AMOUNT] = sound_data[element_two][SOUND_AMOUNT]
   sound_data[element_one][ADMIN_LEVEL_BASE] = sound_data[element_two][ADMIN_LEVEL_BASE]
   sound_data[element_one][FLAGS] = sound_data[element_two][FLAGS]
   sound_data[element_one][PLAY_COUNT_KEY] = sound_data[element_two][PLAY_COUNT_KEY]
   
   copy(sound_data[element_two][KEYWORD], TOK_LENGTH, temp_keyword)
   for ( i = 0; i < BUFFER_LEN; ++i )
      sound_data[element_two][KEY_SOUNDS][i] = temp_sounds[i]
   sound_data[element_two][SOUND_AMOUNT] = temp_int
   sound_data[element_two][ADMIN_LEVEL_BASE] = temp_access_base
   sound_data[element_two][FLAGS] = temp_flags
   sound_data[element_two][PLAY_COUNT_KEY] = temp_play_count
   
   for ( i = 0; i < MAX_RANDOM; ++i )
   {
      temp_float = sound_data[element_one][DURATION][i]
      sound_data[element_one][DURATION][i] = _:sound_data[element_two][DURATION][i]
      sound_data[element_two][DURATION][i] = _:temp_float

      temp_access = sound_data[element_one][ADMIN_LEVEL][i]
      sound_data[element_one][ADMIN_LEVEL][i] = sound_data[element_two][ADMIN_LEVEL][i]
      sound_data[element_two][ADMIN_LEVEL][i] = temp_access

      temp_type = sound_data[element_one][SOUND_TYPE][i]
      sound_data[element_one][SOUND_TYPE][i] = sound_data[element_two][SOUND_TYPE][i]
      sound_data[element_two][SOUND_TYPE][i] = temp_type

      temp_play_count = sound_data[element_one][PLAY_COUNT][i]
      sound_data[element_one][PLAY_COUNT][i] = sound_data[element_two][PLAY_COUNT][i]
      sound_data[element_two][PLAY_COUNT][i] = temp_play_count
   }
}
#endif

array_add_element( num , keyword[] )
{
   new join_check = equali(keyword, "SND_JOIN")
   new exit_check = equali(keyword, "SND_EXIT")
   // if index is 0 or 1 but not the correct keyword then make sure to save in correct array position
   if ( join_check == 0
      && exit_check == 0 )
   {
      if ( num == 0
         || num == 1 )
      {
         join_check = -1
         exit_check = -1
         num = 2
      }
   }else
   {
      if ( num > 1 )
      {
         if ( join_check != 0 )
         {
            num = 0
            exit_check = -1
         }else if ( exit_check != 0 )
         {
            num = 1
            join_check = -1
         }
      }
   }
   
   if ( join_check > 0
      || exit_check > 0 )
      sound_data[num][FLAGS] |= FLAG_IGNORE_AMOUNT
   sound_data[num][ADMIN_LEVEL_BASE] = cfg_parse_access(keyword)
   copy(sound_data[num][KEYWORD], TOK_LENGTH, keyword)
   sound_data[num][PLAY_COUNT_KEY] = 0
   
   return (join_check == -1 && exit_check == -1)
      ? -1
      : (join_check == -1 || exit_check == -1)
         ? num : -2
}

array_add_inner_element( num , elem , soundfile[] , allow_check_existence = 1 , allow_global_precache = 0 , precache_sounds = 0 , allowed_to_precache = 0 )
{
   sound_data[num][ADMIN_LEVEL][elem] = cfg_parse_access(soundfile)
   sound_data[num][SOUND_TYPE][elem] = soundfile[0] == '^"' ? SOUND_TYPE_SPEECH : ( soundfile[strlen(soundfile) - 1] == '3' ? SOUND_TYPE_MP3 : SOUND_TYPE_WAV )
   sound_data[num][PLAY_COUNT][elem] = 0
   
   // check if not speech sounds
   if ( soundfile[0] != '^"' )
   {
      new sound_file_name[TOK_LENGTH + 1 + 10]
      new is_mp3 = ( containi(soundfile, ".mp3") != -1 )
      new isWav_inSound_folder = 0
      if ( !is_mp3 )
      {   // ".mp3" in not in the string
         if ( equali(soundfile, "sound/", 6) )
         {
            formatex(sound_file_name, TOK_LENGTH + 10, "%s", soundfile)
            isWav_inSound_folder = 1
         }else
            formatex(sound_file_name, TOK_LENGTH + 10, "sound/../%s", soundfile)
      }
      else
      {
         copy(sound_file_name, TOK_LENGTH + 10, soundfile)
      }
     
      if ( allow_check_existence )
      {
         if ( !file_exists(sound_file_name) )
         {
            log_amx("Sank Sounds >> Trying to load a file that dont exist. Skipping this file: ^"%s^"", sound_file_name)

            return -1
         }
         
         sound_data[num][DURATION][elem] = _:cfg_get_duration(sound_file_name, is_mp3 ? SOUND_TYPE_MP3 : SOUND_TYPE_WAV )
         
         if ( sound_data[num][DURATION][elem] <= 0.0 )
         {
            log_amx("Sank Sounds >> Sound duration is not valid. File is damaged. Skipping this file: ^"%s^"", sound_file_name)
           
            return -1
         }
      }
     
      if ( allow_global_precache
         && precache_sounds == 1
         && allowed_to_precache )
      {
         if ( is_mp3
            || !isWav_inSound_folder )
            engfunc(EngFunc_PrecacheGeneric, soundfile)
         else
            engfunc(EngFunc_PrecacheSound, soundfile[6])
      }
   }
   
   copy(sound_data[num][KEY_SOUNDS][TOK_LENGTH * elem], TOK_LENGTH, soundfile)
   ++sound_data[num][SOUND_AMOUNT]
   
   return 1
}

array_clear_element( index )
{
   for ( new i = 0; i < TOK_LENGTH; ++i )
      sound_data[index][KEYWORD][i] = 0
   sound_data[index][SOUND_AMOUNT] = 0
   sound_data[index][ADMIN_LEVEL_BASE] = 0
   sound_data[index][FLAGS] = 0
   sound_data[index][PLAY_COUNT_KEY] = 0
   
   for ( new i = 0; i < MAX_RANDOM; ++i )
      array_clear_inner_element(index, i)
}

array_clear_inner_element( index , elem )
{
   for ( new i = 0; i < TOK_LENGTH; ++i )
      sound_data[index][KEY_SOUNDS][TOK_LENGTH * elem + i] = 0
   sound_data[index][DURATION][elem] = _:0.0
   sound_data[index][ADMIN_LEVEL][elem] = 0
   sound_data[index][SOUND_TYPE][elem] = 0
   sound_data[index][PLAY_COUNT][elem] = 0
}

array_copy_element( dest , source )
{
   copy(sound_data[dest][KEYWORD], TOK_LENGTH, sound_data[source][KEYWORD])
   sound_data[dest][SOUND_AMOUNT] = sound_data[source][SOUND_AMOUNT]
   sound_data[dest][ADMIN_LEVEL_BASE] = sound_data[source][ADMIN_LEVEL_BASE]
   sound_data[dest][FLAGS] = sound_data[source][FLAGS]
   sound_data[dest][PLAY_COUNT_KEY] = sound_data[source][PLAY_COUNT_KEY]
   
   for ( new i = 0; i < MAX_RANDOM; ++i )
      array_copy_inner_elements(dest, i, source, i)
}

array_copy_inner_elements( array1 , elem1 , array2 , elem2 )
{
   copy(sound_data[array1][KEY_SOUNDS][TOK_LENGTH * elem1], TOK_LENGTH, sound_data[array2][KEY_SOUNDS][TOK_LENGTH * elem2])
   sound_data[array1][DURATION][elem1] = _:sound_data[array2][DURATION][elem2]
   sound_data[array1][ADMIN_LEVEL][elem1] = sound_data[array2][ADMIN_LEVEL][elem2]
   sound_data[array1][SOUND_TYPE][elem1] = sound_data[array2][SOUND_TYPE][elem2]
   sound_data[array1][PLAY_COUNT][elem1] = sound_data[array2][PLAY_COUNT][elem2]
}

array_remove( index )
{
   // Keep looping array, copying the next into the current
   for ( ; index < MAX_KEYWORDS; ++index )
   {
      // We are at last List element or there is no succesor
      // so clear it cause we want to remove one element anyway
      if ( index == MAX_KEYWORDS - 1
         || sound_data[index + 1][KEYWORD][0] == 0 )
      {
         // Delete data
         array_clear_element(index)
         
         // We reached the end
         return
      }
     
      // Copy the next data over the current
      array_copy_element(index, index + 1)
   }
}

array_remove_inner( index , elem )
{
   // we are removing an element, so decrease counter
   --sound_data[index][SOUND_AMOUNT]
   
   for( ; elem < MAX_RANDOM; ++elem )
   {
      // If we're about to copy data that doesn't exist,
      // then just erase the last entry instead of copying
      if ( elem == MAX_RANDOM - 1
         || sound_data[index][KEY_SOUNDS][TOK_LENGTH * (elem + 1)] == 0 )
      {
         // Delete Sound
         array_clear_inner_element(index, elem)
         
         // We reached the end
         return
      }
     
      // else
      // Copy the next data over the current
      array_copy_inner_elements(index, elem, index, elem + 1)
   }
}

cfg_write_keyword( index , Text[] , Textlen )
{
   Text[0] = 0
   
   if ( sound_data[index][ADMIN_LEVEL_BASE] )
   {
      new access_str[32]
      get_flags(sound_data[index][ADMIN_LEVEL_BASE], access_str, 31)
      formatex(Text, Textlen, "@%s@%s;^t^t", access_str, sound_data[index][KEYWORD])
   }else
      formatex(Text, Textlen, "%s;^t^t", sound_data[index][KEYWORD])
}

cfg_write_keysound( index , Text[] , Textlen )
{
   new access_str[32]
   for ( new j = 0; j < MAX_RANDOM && strlen(sound_data[index][KEY_SOUNDS][TOK_LENGTH * j]); ++j )
   {
      if ( sound_data[index][ADMIN_LEVEL][j] )
      {
         get_flags(sound_data[index][ADMIN_LEVEL][j], access_str, 31)
         format(Text, Textlen, "%s@%s@%s;", Text, access_str, sound_data[index][KEY_SOUNDS][TOK_LENGTH * j])
      }else
         format(Text, Textlen, "%s%s;", Text, sound_data[index][KEY_SOUNDS][TOK_LENGTH * j])
   }
}

cfg_parse_access( str[] )
{
   new access_level
   if ( str[0] == '@' )
   {
      new second_at = contain(str[1], "@")
      if ( second_at != -1 )
      {
         new temp_access[32]
         copy(temp_access, second_at, str[1])
         strtolower(temp_access)
         access_level = read_flags(temp_access)
         copy(str, 127, str[second_at + 1 + 1])
      }else
      {
         access_level = SND_IMMUNITY
         copy(str, 127, str[1])
      }
   }
   
   return access_level
}

Float:cfg_get_duration( sound_file[] , type )
{
   switch ( type )
   {
      case SOUND_TYPE_WAV:
      {
         return cfg_get_wav_duration(sound_file)
      }
      case SOUND_TYPE_MP3:
      {
         return cfg_get_mp3_duration(sound_file)
      }
   }
   
   return 0.0
}

Float:cfg_get_wav_duration( wav_file[] )
{
   new file = fopen(wav_file, "rb")
   new dummy_input
   new i
   for ( i = 0; i < 24; ++i )
      dummy_input = fgetc(file)
   
   // 24th byte
   new hertz = fgetc(file)
   // 25th byte
   hertz += fgetc(file) * 256
   // 26th byte
   hertz += fgetc(file) * 256 * 256
   
   for ( i = 27; i < 34; ++i )
      dummy_input = fgetc(file)
   
   // 34th byte
   new bitrate = fgetc(file)
   
   // bytes for data length start right after ascii "data", so search for it
   // normally it is at 35 but also saw at 44, so just in case add bigger search area
   new data_found
   
   do
   {
      dummy_input = fgetc(file)
      if ( dummy_input == 'd' )
         data_found = 1
      else if ( dummy_input == 'a'
         && data_found == 1 )
         data_found = 2
      else if ( dummy_input == 't'
         && data_found == 2 )
         data_found = 3
      else if ( dummy_input == 'a'
         && data_found == 3 )
         data_found = 4
      else
         data_found = 0
   }while ( dummy_input != -1 && data_found < 4 )
   
   if ( dummy_input == -1
      || hertz <= 0
      || bitrate <= 0
      || data_found != 4 )
   {
      fclose(file)
      return 0.0
   }
   
   // 1st byte after data
   new data_length = fgetc(file)
   // 2nd byte after data
   data_length += fgetc(file) * 256
   // 3rd byte after data
   data_length += fgetc(file) * 256 * 256
   // 4th byte after data
   data_length += fgetc(file) * 256 * 256 * 256
   
   fclose(file)
   
   return float(data_length) / ( float(hertz * bitrate) / 8.0 )
}

enum
{
   MP3_MPEG_VERSION_BIT1 = 8,
   MP3_MPEG_VERSION_BIT2 = 16,
   MP3_LAYER_BIT1 = 2,
   MP3_LAYER_BIT2 = 4,
   MP3_PROTECT_BIT = 1,
   
   MP3_BITRATE_BIT1 = 16,
   MP3_BITRATE_BIT2 = 32,
   MP3_BITRATE_BIT3 = 64,
   MP3_BITRATE_BIT4 = 128,
   MP3_BITRATE_INVALID = 15,
   MP3_SAMPLERATE_BIT1 = 4,
   MP3_SAMPLERATE_BIT2 = 8,
   MP3_SAMPLERATE_INVALID = 3,
   MP3_PADDING_BIT = 2,
   MP3_PRIVATE_BIT = 1,
}

// bitrate info
new const bitrate_table[] = {
   //MPEG 2 & 2.5
   0, 32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256, -1,   // Layer I
   0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, -1,   // Layer II
   0,  8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160, -1,   // Layer III
   //MPEG 1
   0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1,   // Layer I
   0, 32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384, -1,   // Layer II
   0, 32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, -1,   // Layer III
}

#if DEBUG_MODE == 1
// frequency info
new const samplingrate_table[] = {
   11025, 12000,  8000, 0,   // MPEG 2.5   // have not seen MPEG 2.5, so UNTESTED
      -1,    -1,    -1, 0,   // reserved
   22050, 24000, 16000, 0,   // MPEG 2
   44100, 48000, 32000, 0   // MPEG 1
}
#endif

Float:cfg_get_mp3_duration( mp3_file[] )
{
   new file = fopen(mp3_file, "rb")
   new byte, found_header, file_pos
   new byte2
   
   new mpeg_version
   new layer
   new mp3_bitrate
   new mp3_samplerate
   new result = -1
   do
   {
      byte = fgetc(file)
      if ( byte == -1 )
         break
     
      ++file_pos
      if ( byte != 255 )
         continue
     
      byte = fgetc(file)
      byte2 = fgetc(file)
      result = verify_header(byte, byte2, mpeg_version, layer, mp3_bitrate, mp3_samplerate)
      if ( result == -1 )
      {
         fseek(file, file_pos, SEEK_SET)
         ++file_pos
         continue
      }else
         break
   }while ( !found_header && byte != -1 )
   
   fclose(file)
   
   if ( byte == -1 )
      return 0.0
   
   new mpeg_version_for_bitrate = 0
   if ( mpeg_version == 3 )
      mpeg_version_for_bitrate = 1
   new mp3_bitrate_kbps = bitrate_table[mpeg_version_for_bitrate * ( 3 * 16 ) + ( layer - 1 ) * 16 + mp3_bitrate]
   
#if DEBUG_MODE == 1
   log_amx("Sank Sounds >> DEBUG for file ^"%s^"", mp3_file)
   log_amx("Sank Sounds >> Data bytes = %i / %i", byte, byte2)
   log_amx("Sank Sounds >> Header position = %i", file_pos)
   new mpeg_version_str[10]
   if ( mpeg_version == 0 )
      copy(mpeg_version_str, 9, "MPEG 2.5")
   else if ( mpeg_version == 2 )
      copy(mpeg_version_str, 9, "MPEG 2")
   else if ( mpeg_version == 3 )
      copy(mpeg_version_str, 9, "MPEG 1")
   log_amx("Sank Sounds >> MPEG version = %i / Format: %s", mpeg_version, mpeg_version_str)
   log_amx("Sank Sounds >> Layer = %i", layer)
   log_amx("Sank Sounds >> Bitrate = %iKbps (%i)", mp3_bitrate_kbps, mp3_bitrate)
   
   new mp3_samplerate_hz = samplingrate_table[mpeg_version * 4 + mp3_samplerate]
   
   log_amx("Sank Sounds >> Samplerate = %iHz (%i)", mp3_samplerate_hz, mp3_samplerate)
#endif
   new size_of_file = file_size(mp3_file, 0)
   
   if ( mp3_bitrate_kbps == 0 )
      return 0.0
   
   //song length...
   return float(size_of_file) / ( float(mp3_bitrate_kbps) * 1000.0 ) * 8.0
}

verify_header( header , header2 , &mpeg_version , &layer , &mp3_bitrate , &mp3_samplerate)
{
   // check if first 3 bits set
   if ( header & 0xe0 != 0xe0 )
      return -1
   
   layer = 4
      - ( header & MP3_LAYER_BIT1 ) / MP3_LAYER_BIT1
      + ( header & MP3_LAYER_BIT2 ) / MP3_LAYER_BIT1
   
   if ( layer != 3 )
      return -1
   
   mp3_bitrate = ( header2 & MP3_BITRATE_BIT1 ) / MP3_BITRATE_BIT1
      + ( header2 & MP3_BITRATE_BIT2 ) / MP3_BITRATE_BIT1
      + ( header2 & MP3_BITRATE_BIT3 ) / MP3_BITRATE_BIT1
      + ( header2 & MP3_BITRATE_BIT4 ) / MP3_BITRATE_BIT1
   
   if ( mp3_bitrate & MP3_BITRATE_INVALID == MP3_BITRATE_INVALID )
      return -1
   
   mp3_samplerate = ( header2 & MP3_SAMPLERATE_BIT1 ) / MP3_SAMPLERATE_BIT1
      + ( header2 & MP3_SAMPLERATE_BIT2 ) / MP3_SAMPLERATE_BIT1
   
   if ( mp3_samplerate & MP3_SAMPLERATE_INVALID == MP3_SAMPLERATE_INVALID )
      return -1
   
   mpeg_version = ( header & MP3_MPEG_VERSION_BIT1 ) / MP3_MPEG_VERSION_BIT1
      + ( header & MP3_MPEG_VERSION_BIT2 ) / MP3_MPEG_VERSION_BIT1
   
   return 1
}


0 0
  
Back to top
View user's profile Send private message
killik

[Whaaaaat?!]



Status: Offline
(since 26-05-2019 09:22)
Joined: 14 Jun 2010
Posts: 7576, Topics: 198
Location: Timisoara

Reputation: 301.5
Votes: 99

       
Post Posted: 26-11-2012, 00:39:50 | Translate post to: ... (Click for more languages)

Normal ca nu il poti compila din moment ce e plin de erori si incomplet


0 0
  
Back to top
View user's profile Send private message Yahoo! Messenger ID
KillingFloor

[Mentally Stable]



Status: Offline
(since 09-02-2013 10:06)
Joined: 22 Nov 2012
Posts: 14, Topics: 4
Location: Romania

Reputation: 51.5
Votes: 2

Post Posted: 26-11-2012, 19:05:18 | Translate post to: ... (Click for more languages)

poi si nu poti sa mi-l faci? please - nu stiu ce e de facut -
0 0
  
Back to top
View user's profile Send private message
KillingFloor

[Mentally Stable]



Status: Offline
(since 09-02-2013 10:06)
Joined: 22 Nov 2012
Posts: 14, Topics: 4
Location: Romania

Reputation: 51.5
Votes: 2

Post Posted: 27-11-2012, 14:20:02 | Translate post to: ... (Click for more languages)

ma ajuta si pe mn cineva pls?
0 0
  
Back to top
View user's profile Send private message
Wish*

[Account disabled]



Status: Offline
(since 17-12-2012 18:09)
Joined: 01 Sep 2012
Posts: 763, Topics: 63
Location: New York

Reputation: 45
Votes: 16

Post Posted: 30-11-2012, 13:58:30 | Translate post to: ... (Click for more languages)

Este logic , ca nu il poti compila .
Este plin de erori , si este si incomplet .
+1 killik

0 0
  
Back to top
View user's profile Send private message
KillingFloor

[Mentally Stable]



Status: Offline
(since 09-02-2013 10:06)
Joined: 22 Nov 2012
Posts: 14, Topics: 4
Location: Romania

Reputation: 51.5
Votes: 2

Post Posted: 30-11-2012, 14:47:43 | Translate post to: ... (Click for more languages)

am inteles ca este incomplet si plind de erori dar ai putea sa mi-l repari? adica sa ii pui tot ce ii lipseste si sa ii rezolvi erorile?
0 0
  
Back to top
View user's profile Send private message
SaKaL

[SeFu Lu RyBoXxX]



Status: Offline
(since 02-06-2013 12:00)
Joined: 21 Oct 2011
Posts: 1358, Topics: 63
Location: Slatina

Reputation: 3.2
Votes: 52

Post Posted: 30-11-2012, 14:59:26 | Translate post to: ... (Click for more languages)

O sa vorbesc eu cu cineva daca te poate ajuta



0 0
  
Back to top
View user's profile Send private message
KillingFloor

[Mentally Stable]



Status: Offline
(since 09-02-2013 10:06)
Joined: 22 Nov 2012
Posts: 14, Topics: 4
Location: Romania

Reputation: 51.5
Votes: 2

Post Posted: 30-11-2012, 17:25:34 | Translate post to: ... (Click for more languages)

ok multumesc mult...astept
0 0
  
Back to top
View user's profile Send private message
null009

[Mentally Stable]



Status: Offline
(since 08-11-2019 07:39)
Joined: 18 Jun 2012
Posts: 32, Topics: 5
Location: Romania

Reputation: 17.4
Votes: 4

Post Posted: 30-11-2012, 21:01:15 | Translate post to: ... (Click for more languages)

Este logic ca nuti merge .. Scz ca tiam zis dar are foarte multe erori ..
0 0
  
Back to top
View user's profile Send private message
valentinFREAKZ

[Proo!!]



Status: Offline
(since 09-12-2012 06:41)
Joined: 04 Mar 2012
Posts: 2302, Topics: 34
Location: Romania

Reputation: -105.8
Votes: 21

Post Posted: 01-12-2012, 11:47:31 | Translate post to: ... (Click for more languages)

null009 wrote:
Este logic ca nuti merge .. Scz ca tiam zis dar are foarte multe erori ..

Ce va mai place SPAM-UL au postat 2 acelasi lucru "ca este plin de erori.." si vi si tu si spui acelasi lucru omu a inteles ca are erori da daca tot vrei sa postezi treb sa postezi ceva folositor nu "Este logic ca nuti merge .. Scz ca tiam zis dar are foarte multe erori .."

0 0
  
Back to top
View user's profile Send private message
KillingFloor

[Mentally Stable]



Status: Offline
(since 09-02-2013 10:06)
Joined: 22 Nov 2012
Posts: 14, Topics: 4
Location: Romania

Reputation: 51.5
Votes: 2

Post Posted: 03-12-2012, 17:46:42 | Translate post to: ... (Click for more languages)

cineva :-s ?
0 0
  
Back to top
View user's profile Send private message
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Freakz Forum Index -> Trash Bin -> CS 2006-2019 (Archived) -> Resources  


The time now is 08-07-2024, 03:37:56
Copyright info

Based on phpBB ro/com
B

 
 
 







I forgot my password


This message appears only once, so
like us now until it's too late ! :D
x