diff --git a/addons/amxmodx/configs/csgor_configs.ini b/addons/amxmodx/configs/csgor_configs.ini index f25fcdf..d43899d 100644 --- a/addons/amxmodx/configs/csgor_configs.ini +++ b/addons/amxmodx/configs/csgor_configs.ini @@ -313,7 +313,6 @@ "Deagle" "26" "P90" "30" - [Main Menu] ; Example of menus: ; "Menu Name" "Menu open Command" @@ -325,9 +324,10 @@ "CSGOR_MM_OPEN_CRAFT" "opencase" "CSGOR_MM_MARKET" "market" "CSGOR_MM_GIVEAWAY" "giveaway" +"CSGOR_MM_MVP" "mvp_menu" +"CSGOR_MM_GAMES" "games" "CSGOR_MM_DUSTBIN" "dustbin" "CSGOR_MM_GIFT_TRADE" "gift" -"CSGOR_MM_GAMES" "games" [SKIP FROM CHAT] ; In this section you can enter strings or characters which you want to be skipped from showing in chat! diff --git a/addons/amxmodx/configs/csgor_mvp.ini b/addons/amxmodx/configs/csgor_mvp.ini new file mode 100644 index 0000000..677a4db --- /dev/null +++ b/addons/amxmodx/configs/csgor_mvp.ini @@ -0,0 +1,60 @@ +[TRACKS SECTION] +# Tracks must be in .mp3 format +# "Track Name" "Track Path" "Only for VIP" "Track Cost" +# Ex: "TRACK #1" "sound/mvp_otr/track1.mp3" "0" "1000" +"Janji - Heroes Tonight" "sound/csgor_mvp/heroes_tonight.wav" "0" "100" +"Cartoon, Jeja - On & On" "sound/csgor_mvp/on_and_on.wav" "0" "150" +"DEAF KEV - Invincible" "sound/csgor_mvp/invincible.wav" "1" "200" + +[SETTINGS SECTION] +# Chat Prefix of MVP Message +CHAT_PREFIX = [{g}MVP{n}] + +# Hud Prefix of MVP Message +HUD_PREFIX = [MVP] + +# Menu Prefix +MENU_PREFIX = [MVP] + +# How to save player's preferences: 0 = nVault | 1 = MySQL | 2 = SQLite +# If you want to use SQLite Database, you need to activate the "sqlite" module in modules.ini by removing ";" +SAVE_TYPE = 0 + +# Database informations +# For SQLite you need to remove password from SQL_PASS field. +SQL_HOST = localhost +SQL_USER = root +SQL_PASS = password +SQL_DATABASE = database +SQL_TABLE = mvp_otr + +# Vault informations +NVAULT_DATABASE = mvp_otr + +# Save player's data method: +# 0 = Save player's data on Name +# 1 = Save player's data on SteamID +AUTH_METHOD = 0 + +# Save player's data instant?: 0 = No | 1 = Yes +INSTANT_SAVE = 1 + +# Message type when MVP event is triggered +# 0 = Message is sent through chat +# 1 = Message is sent through DHUD channel ( recommended ) +# 2 = Message is sent through HUD channel +MESSAGE_TYPE = 1 + +# HUD Color | R G B +HUD_COLOR = 0 255 0 + +# HUD Position | xOy Axis +HUD_POSITION = -1.0 0.26 + +# Commands to open the MVP Tracks Menu +# Commands must be splitted by "," +MENU_COMMANDS = say /mvp, say_team /mvp, mvp_menu + +# Access for VIP Tracks +# Default: "t" / ADMIN_LEVEL_H +VIP_ACCESS = t diff --git a/addons/amxmodx/data/lang/csgor_language.txt b/addons/amxmodx/data/lang/csgor_language.txt index 7b4b71f..d8a62cf 100644 --- a/addons/amxmodx/data/lang/csgor_language.txt +++ b/addons/amxmodx/data/lang/csgor_language.txt @@ -319,6 +319,31 @@ CSGOR_ACCOUNT_REMOVED = Contul %s a fost sters CSGOR_ACCOUNT_RESET_ITEM = Contului %s i-a fost resetat %s CSOGR_ACCOUNT_NOT_FOUND = Contul %s nu a fost gasit! +MVP_MENU_TITLE = Meniu MVP +MVP_SHOW_MVP_COUNT = Ai fost de \r%d ori\y MVP\w! +MVP_SELECTED_TRACK = \yMelodia ta\d: \r%s +MVP_NOT_SELECTED = \yNu ai selectat nicio melodie! +MVP_CHOOSE_TRACK = Alege o melodie +MVP_TRACK_LIST = Vezi lista melodiilor +MVP_SOUNDS_ON_OFF = Sunete MVP: \y%s +MVP_TRACK_X_SELECTED = Ai selectat melodia: ^4%s +MVP_TRACK_X_DESELECTED = Ai deselectat melodia: ^4%s +MVP_TRACK_LIST_TITLE = Lista Melodiilor +MVP_KILLER_SHOW_CHAT = Jucatorul acestei runde: ^3%s^1 pentru ^4uciderea a %i jucatori. +MVP_KILLER_SHOW_HUD = Jucatorul acestei runde: %s pentru uciderea a %i jucatori. +MVP_DEFUSER_SHOW_CHAT = Jucatorul acestei runde: ^3%s^1 pentru ^4dezamorsarea bombei. +MVP_DEFUSER_SHOW_HUD = Jucatorul acestei runde: %s pentru dezamorsarea bombei. +MVP_PLANTER_SHOW_CHAT = Jucatorul acestei runde: ^3%s^1 pentru ^4plantarea bombei. +MVP_PLANTER_SHOW_HUD = Jucatorul acestei runde: %s pentru plantarea bombei. +NO_MVP_SHOW_CHAT = Jucatorul acestei runde: ^3Niciun Jucator^1 nu a fost destul de ^4bun aceasta runda. +NO_MVP_SHOW_HUD = Jucatorul acestei runde: Niciun Jucator nu a fost destul de bun aceasta runda. +MVP_NO_TRACKS_LOADED =Nicio melodie incarcata. +MVP_VIP_ONLY = \r[Doar VIP] +MVP_TRACK_VIP_ONLY = Aceasta melodie este doar pentru membri ^4V.I.P^1. +MVP_PLAYING_TRACK = Asculti melodia: +MVP_BUY_SUCCESS = ^1Ai cumparat melodia ^4%s^1 cu ^4%d^1 puncte. +MVP_BUY_FAILED = ^1Nu ai destule puncte pentru a cumpara ^4%s. Detii %d/%d puncte. + [en] CSGOR_NO_DROP_SKINS = There are no drop type skins! CSGOR_NO_CRAFT_SKINS = There are no craft type skins! @@ -639,4 +664,29 @@ CSGOR_INVALID_ARGUMENT = Invalid argument number %d: %s CSGOR_ACCOUNT_RESET = Account %s has been reset CSGOR_ACCOUNT_REMOVED = Account %s has been removed CSGOR_ACCOUNT_RESET_ITEM = Account's %s got %s reset -CSOGR_ACCOUNT_NOT_FOUND = Account %s has not been found! \ No newline at end of file +CSOGR_ACCOUNT_NOT_FOUND = Account %s has not been found! + +MVP_MENU_TITLE = MVP Menu +MVP_SHOW_MVP_COUNT = You were \r%d times\y MVP\w! +MVP_SELECTED_TRACK = \yYour track\d: \r%s +MVP_NOT_SELECTED = \yYou don't have any selected track! +MVP_CHOOSE_TRACK = Choose a track +MVP_TRACK_LIST = Preview Tracks list +MVP_SOUNDS_ON_OFF = MVP Sounds: \y%s +MVP_TRACK_X_SELECTED = You have selected the track: ^4%s +MVP_TRACK_X_DESELECTED = You have deselected the track: ^4%s +MVP_TRACK_LIST_TITLE = Tracks List +MVP_KILLER_SHOW_CHAT = Player of the round: ^3%s^1 for ^4killing %i players. +MVP_KILLER_SHOW_HUD = Player of the round: %s for killing %i players. +MVP_DEFUSER_SHOW_CHAT = Player of the round: ^3%s^1 for ^4defusing the bomb. +MVP_DEFUSER_SHOW_HUD = Player of the round: %s for defusing the bomb. +MVP_PLANTER_SHOW_CHAT = Player of the round: ^3%s^1 for ^4planting the bomb. +MVP_PLANTER_SHOW_HUD = Player of the round: %s for planting the bomb. +NO_MVP_SHOW_CHAT = Player of the round: ^3No Player^1 was ^4good enough this round. +NO_MVP_SHOW_HUD = Player of the round: No Player was good enough this round. +MVP_NO_TRACKS_LOADED = No tracks loaded. +MVP_VIP_ONLY = \r[VIP Only] +MVP_TRACK_VIP_ONLY = This track is only for ^4V.I.P^1 members. +MVP_PLAYING_TRACK = Playing Track: +MVP_BUY_SUCCESS = ^1You have succesfully bought ^4%s^1 with ^4%d^1 points. +MVP_BUY_FAILED = ^1You don't have enough points to buy ^4%s. You have %d/%d \ No newline at end of file diff --git a/addons/amxmodx/scripting/csgo_remake.sma b/addons/amxmodx/scripting/csgo_remake.sma index 4861e8f..9e56b1e 100644 --- a/addons/amxmodx/scripting/csgo_remake.sma +++ b/addons/amxmodx/scripting/csgo_remake.sma @@ -21,8 +21,8 @@ /* DO NOT MODIFY THIS LIME. */ #pragma dynamic MAX_SKINS * 17 -#define PLUGIN "CS:GO Remake" -#define VERSION "2.3.2" +#define PLUGIN "[CS:GO Remake] Core" +#define VERSION "2.3.3" #define AUTHOR "Shadows Adi" #define CSGO_TAG "[CS:GO Remake]" @@ -1249,7 +1249,7 @@ RegisterForwards() g_iForwards[ user_register ] = CreateMultiForward("csgor_user_register", ET_IGNORE, FP_CELL) g_iForwards[ user_pass_fail ] = CreateMultiForward("csgor_user_password_failed", ET_IGNORE, FP_CELL, FP_CELL) g_iForwards[ user_assist ] = CreateMultiForward("csgor_user_assist", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL, FP_CELL) - g_iForwards[ user_mvp ] = CreateMultiForward("csgor_user_mvp", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL) + g_iForwards[ user_mvp ] = CreateMultiForward("csgor_user_mvp", ET_CONTINUE, FP_CELL, FP_CELL, FP_CELL) g_iForwards[ user_case_opening ] = CreateMultiForward("csgor_user_case_open", ET_IGNORE, FP_CELL) g_iForwards[ user_craft ] = CreateMultiForward("csgor_user_craft", ET_IGNORE, FP_CELL) g_iForwards[ user_level_up ] = CreateMultiForward("csgor_user_levelup", ET_IGNORE, FP_CELL, FP_STRING, FP_CELL) @@ -1841,24 +1841,24 @@ public task_Check_Conditions(data[]) { if (g_bBombExplode) { - _ShowMVP(g_iBombPlanter, 1) + _ShowMVP(g_iBombPlanter, MVP_PLANTER) } else { new top1 = _GetTopKiller(1) - _ShowMVP(top1, 0) + _ShowMVP(top1, MVP_KILLER) } } case 2: { if (g_bBombDefused) { - _ShowMVP(g_iBombDefuser, 2) + _ShowMVP(g_iBombDefuser, MVP_DEFUSER) } else { new top1 = _GetTopKiller(2) - _ShowMVP(top1, 0) + _ShowMVP(top1, MVP_KILLER) } } } @@ -2721,8 +2721,12 @@ public QueryPlayerLoadedSkins(iFailState, Handle:iQuery, Error[], Errcode, szDat } } - client_print_color(id, print_chat, "^4%s^1 %L", CSGO_TAG, LANG_SERVER, "CSGOR_DATA_LOADED") - g_bLoaded[id] = true + if(g_bLogged[id]) + { + client_print_color(id, print_chat, "^4%s^1 %L", CSGO_TAG, LANG_SERVER, "CSGOR_DATA_LOADED") + g_bLoaded[id] = true + _ShowMainMenu(id) + } } public _SaveData(id) @@ -2983,26 +2987,25 @@ public reg_menu_handler(id, menu, item) _LoadSkins(id) - new spLen = strlen(g_szUser_SavedPass[id]) + new spLen = strlen(g_szUserPassword[id]) if (strlen(g_szUserPassword[id]) <= 0) { - client_print_color(id, print_chat, "^4%s^1 %L", CSGO_TAG, LANG_SERVER, "CSGOR_REG_INSERT_PASS", 6) + client_print_color(id, print_chat, "^4%s^1%L", CSGO_TAG, LANG_SERVER, "CSGOR_REG_INSERT_PASS", 6) client_cmd(id, "messagemode UserPassword") } if (!equal(g_szUserPassword[id], g_szUser_SavedPass[id], spLen)) { g_iUserPassFail[id]++ - client_print_color(id, print_chat, "^4%s ^1 %L", CSGO_TAG, LANG_SERVER, "CSGOR_PASS_FAIL") + client_print_color(id, print_chat, "^4%s ^1%L", CSGO_TAG, LANG_SERVER, "CSGOR_PASS_FAIL") _ShowRegMenu(id) ExecuteForward(g_iForwards[ user_pass_fail ], g_iForwardResult, id, g_iUserPassFail[id]) } else { g_bLogged[id] = true - _ShowMainMenu(id) - client_print_color(id, print_chat, "^4%s^1 %L", CSGO_TAG, LANG_SERVER, "CSGOR_LOGIN_SUCCESS") + client_print_color(id, print_chat, "^4%s ^1%L", CSGO_TAG, LANG_SERVER, "CSGOR_LOGIN_SUCCESS") ExecuteForward(g_iForwards[ user_log_in ], g_iForwardResult, id) } @@ -10963,12 +10966,18 @@ _ShowMVP(id, event) g_iUserMVP[id]++ + new iRet + ExecuteForward(g_iForwards[ user_mvp ], iRet, id, event, g_iRoundKills[id]) + + if(iRet > PLUGIN_CONTINUE) + { + return PLUGIN_HANDLED + } + + _GiveBonus(id, 1) + switch (g_iCvars[iMVPMsgType]) { - case 0: - { - goto _End - } case 1: { switch (event) @@ -11026,11 +11035,7 @@ _ShowMVP(id, event) } } } - - _End: - ExecuteForward(g_iForwards[ user_mvp ], g_iForwardResult, id, event, g_iRoundKills[id]) - _GiveBonus(id, 1) - + return PLUGIN_HANDLED } @@ -11097,7 +11102,7 @@ _GiveBonus(id, type) if (!g_bLogged[id]) { client_print_color(id, print_chat, "^4%s^1 %L", CSGO_TAG, LANG_SERVER, "CSGOR_REGISTER") - return PLUGIN_HANDLED + return -1 } new rpoints @@ -11120,7 +11125,7 @@ _GiveBonus(id, type) _Save(id) } - return PLUGIN_CONTINUE + return rpoints } _SetKillsIcon(id, reset) diff --git a/addons/amxmodx/scripting/csgor_mvp.sma b/addons/amxmodx/scripting/csgor_mvp.sma new file mode 100644 index 0000000..c5c1576 --- /dev/null +++ b/addons/amxmodx/scripting/csgor_mvp.sma @@ -0,0 +1,1699 @@ +/* Uncomment this line if you want to use only ReAPI Support*/ +// Activated by Default +#define USE_REAPI + +/*Comment the below line if you are not testing the plugin. When testing, debug information will be printed to all players */ +//#define TESTING + +#define CC_COLORS_TYPE CC_COLORS_NAMED_SHORT + +#define BYTE(%0) (%0&0xFF) +#define BITS(%0,%1) ((%0&(1<<%1))?1:0) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if AMXX_VERSION_NUM < 183 +#include +#endif + +#include +#pragma defclasslib sqlite sqlite + +#if defined USE_REAPI +#include +#else +#include + +const m_LastHitGroup = 75 +#endif + +#if !defined MAX_NAME_LENGTH +#define MAX_NAME_LENGTH 32 +#endif + +#if !defined MAX_PLAYERS +#define MAX_PLAYERS 32 +#endif + +#define PLUGIN "[CS:GO Remake] Most Valuable Player" +#define VERSION "3.0" +#define AUTHOR "Shadows Adi" + +#define IsPlayer(%1) (1 <= %1 <= g_iMaxPlayers) + +#define NATIVE_ERROR -1 + +#define MAX_TRACK_LENGHT 64 + +#define MAX_CONNECT_TRY 2 + +// Support for other mods +#define set_player_points(%0,%1) csgor_set_user_points(%0,%1) +#define get_player_points(%0) csgor_get_user_points(%0) +#define is_player_logged(%0) csgor_is_user_logged(%0) + +new const CHAT_PREFIX[] = "CHAT_PREFIX" +new const HUD_PREFIX[] = "HUD_PREFIX" +new const MENU_PREFIX[] = "MENU_PREFIX" +new const SQL_HOSTNAME[] = "SQL_HOST" +new const SQL_USERNAME[] = "SQL_USER" +new const SQL_PASSWORD[] = "SQL_PASS" +new const SQL_DATABASE[] = "SQL_DATABASE" +new const SQL_DBTABLE[] = "SQL_TABLE" +new const AUTH_METHOD[] = "AUTH_METHOD" +new const INSTANT_SAVE[] = "INSTANT_SAVE" +new const MESSAGE_TYPE[] = "MESSAGE_TYPE" +new const HUD_COLOR[] = "HUD_COLOR" +new const HUD_POSITION[] = "HUD_POSITION" +new const MENU_COMMANDS[] = "MENU_COMMANDS" +new const VIP_ACCESS[] = "VIP_ACCESS" +new const LOG_FILE[] = "mvp_errors.log" + +new MenuColors[][] = {"\r", "\y", "\d", "\w", "\R"} + +enum _:DamageData +{ + iDamage = 0, + iHSDmg = 1 +} + +enum +{ + MVP_CHAT_MSG = 0, + MVP_DHUD_MSG = 1, + MVP_HUD_MSG = 2 +} + +enum +{ + TRACKS_SECTION = 1, + SETTINGS_SECTION = 2 +} + +enum _:Tracks +{ + szNAME[MAX_TRACK_LENGHT], + szPATH[MAX_TRACK_LENGHT], + iVipOnly, + iCost, + Float:flDuration +} + +enum _:Prefix +{ + PREFIX_CHAT[16], + PREFIX_HUD[16], + PREFIX_MENU[16] +} + +enum _:HudSettings +{ + Float:HudPosX, + Float:HudPosY, + HudColorR, + HudColorG, + HudColorB +} + +enum _:DBSettings +{ + MYSQL_HOST[32], + MYSQL_USER[32], + MYSQL_PASS[48], + MYSQL_TABLE[32], + MYSQL_DB[32] +} + +enum _:PlayerType +{ + iPlanter = 0, + iDefuser, + iTopKiller +} + +new WinScenario:g_iScenario = NO_SCENARIO + +new Array:g_aTracks + +new bool:g_bAuthData +new bool:g_bExistTracks +new bool:g_bDisableTracks[MAX_PLAYERS + 1] +new bool:g_bIsBombPlanted +new bool:g_bIsBombDefused + +new g_szName[MAX_PLAYERS + 1][MAX_NAME_LENGTH] +new g_szAuthID[MAX_PLAYERS + 1][20] +new g_iDamage[MAX_PLAYERS + 1][DamageData] +new g_iPlayerMVP[MAX_PLAYERS + 1] +new g_iKills[MAX_PLAYERS + 1] +new g_iUserSelectedTrack[MAX_PLAYERS + 1] +new g_eMVPlayer[PlayerType] +new g_szPlayingTrack[MAX_TRACK_LENGHT] + +new g_eDBConfig[DBSettings] +new g_iHudColor[HudSettings] +new g_szPrefix[Prefix] +new g_iTracksNum + +new g_iSaveInstant +new g_iMessageType +new g_iVipFlag + +new g_fHudPos[HudSettings] + +new g_fwScenario +new g_iForwardResult + +new Handle:g_hSqlTuple +new Handle:g_iSqlConnection +new g_szSqlError[512] + +new g_IsConnected +new g_iMaxPlayers + +new bool:g_bNotOnlyVip + +new Trie:g_tPlayerTracks + +new bool:g_bLoaded[MAX_PLAYERS + 1] + +public plugin_init() +{ + register_plugin(PLUGIN, VERSION, AUTHOR) + + register_cvar("mvp_otr", VERSION, FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_UNLOGGED|FCVAR_SPONLY) + + register_dictionary("csgor_language.txt") + + #if defined USE_REAPI + RegisterHookChain(RG_CSGameRules_RestartRound, "RG_RestartRound_Post", 1) + RegisterHookChain(RG_CBasePlayer_TakeDamage, "RG_Player_Damage_Post", 1) + RegisterHookChain(RG_CBasePlayer_Killed, "RG_Player_Killed_Post", 1) + RegisterHookChain(RG_RoundEnd, "RG_Round_End") + RegisterHookChain(RG_CBasePlayer_SetClientUserInfoName, "RG_SetClientUserInfoName_Post", 1) + #else + register_event("TextMsg", "Event_Game_Restart", "a", "2&#Game_C", "2&#Game_w") + RegisterHam(Ham_TakeDamage, "player", "Ham_Player_Damage_Post", 1) + RegisterHam(Ham_Killed, "player", "Ham_Player_Killed_Post", 1) + register_logevent("Logev_Roundend", 2, "1=Round_End") + register_event("SendAudio", "Event_Terroristwin", "a", "2&%!MRAD_terwin") + register_event("SendAudio", "Event_CTwin", "a", "2=%!MRAD_ctwin") + register_forward(FM_ClientUserInfoChanged, "Fw_ClientUserInfoChanged_Post", 1) + #endif + + register_logevent("Logev_Roundstart", 2, "1=Round_Start") + + #if defined TESTING + register_clcmd("say /test", "Clcmd_Say_Test") + #endif + + g_fwScenario = CreateMultiForward("mvp_scenario", ET_IGNORE, FP_CELL) + + g_iMaxPlayers = get_maxplayers() + + g_tPlayerTracks = TrieCreate() +} + +public plugin_natives() +{ + register_library("most_valuable_player") + + register_native("get_user_mvp_kills", "native_get_user_mvp_kills") + register_native("get_user_mvp_topkiller", "native_get_user_mvp_topkiller") + register_native("get_user_mvp_damage", "native_get_user_mvp_damage") + register_native("get_user_mvp_hs_damage", "native_get_user_mvp_hs_damage") + register_native("get_user_mvps", "native_get_user_mvp") + register_native("get_user_mvp_track", "native_get_user_mvp_track") + register_native("get_mvp_track_info", "native_get_mvp_track_info") + register_native("get_mvp_index", "native_get_mvp_index") + + g_aTracks = ArrayCreate(Tracks) +} + +public plugin_end() +{ + ArrayDestroy(g_aTracks) + TrieDestroy(g_tPlayerTracks) + SQL_FreeHandle(g_hSqlTuple) + SQL_FreeHandle(g_iSqlConnection) +} + +public plugin_precache() +{ + new szConfigsDir[256], szFileName[256] + get_configsdir(szConfigsDir, charsmax(szConfigsDir)) + formatex(szFileName, charsmax(szFileName), "%s/csgor_mvp.ini", szConfigsDir) + + #if defined TESTING + server_print("%s", szFileName) + #endif + + new iFile = fopen(szFileName, "rt") + + if(iFile) + { + new szData[128], iSection, szString[64], szValue[64], eTrack[Tracks], szTemp[2][6] + new szErrorMsg[128], szHudColorR[4], szHudColorG[4], szHudColorB[4], szHudPosX[5], szHudPosY[5] + + while(fgets(iFile, szData, charsmax(szData))) + { + trim(szData) + + if(szData[0] == '#' || szData[0] == EOS || szData[0] == ';') + continue + + if(szData[0] == '[') + { + iSection += 1 + continue + } + + switch(iSection) + { + case TRACKS_SECTION: + { + parse(szData, eTrack[szNAME], charsmax(eTrack[szNAME]), eTrack[szPATH], charsmax(eTrack[szPATH]), szTemp[0], charsmax(szTemp[]), szTemp[1], charsmax(szTemp[])) + + eTrack[iVipOnly] = str_to_num(szTemp[0]) + eTrack[iCost] = str_to_num(szTemp[1]) + eTrack[flDuration] = GetTrackDuration(eTrack[szPATH]) + + #if defined TESTING + server_print("Name: %s", eTrack[szNAME]) + server_print("Path: %s", eTrack[szPATH]) + server_print("Vip: %d", eTrack[iVipOnly]) + #endif + + if(!file_exists(eTrack[szPATH])) + { + formatex(szErrorMsg, charsmax(szErrorMsg), "Error. Can't precache sound %s, file doesn't exist!", eTrack[szPATH]) + log_to_file(LOG_FILE, szErrorMsg) + continue + } + precache_generic(eTrack[szPATH]) + + if(!eTrack[iVipOnly]) + { + g_bNotOnlyVip = true + } + + g_iTracksNum += 1 + + ArrayPushArray(g_aTracks, eTrack) + + #if defined TESTING + server_print("Tracks Num: %d", g_iTracksNum) + #endif + } + case SETTINGS_SECTION: + { + strtok(szData, szString, charsmax(szString), szValue, charsmax(szValue), '=') + trim(szString) + trim(szValue) + + if(equal(szString, CHAT_PREFIX)) + { + copy(g_szPrefix[PREFIX_CHAT], charsmax(g_szPrefix[PREFIX_CHAT]), szValue) + } + else if(equal(szString, HUD_PREFIX)) + { + copy(g_szPrefix[PREFIX_HUD], charsmax(g_szPrefix[PREFIX_HUD]), szValue) + } + else if(equal(szString, MENU_PREFIX)) + { + copy(g_szPrefix[PREFIX_MENU], charsmax(g_szPrefix[PREFIX_MENU]), szValue) + } + else if(equal(szString, SQL_HOSTNAME)) + { + if(szValue[0] == EOS) + { + LogReadingError(SQL_HOSTNAME) + } + else + { + copy(g_eDBConfig[MYSQL_HOST], charsmax(g_eDBConfig[MYSQL_HOST]), szValue) + } + } + else if(equal(szString, SQL_USERNAME)) + { + if(szValue[0] == EOS) + { + LogReadingError(SQL_USERNAME) + } + else + { + copy(g_eDBConfig[MYSQL_USER], charsmax(g_eDBConfig[MYSQL_USER]), szValue) + } + } + else if(equal(szString, SQL_PASSWORD)) + { + if(szValue[0] == EOS) + { + LogReadingError(SQL_PASSWORD) + } + else + { + copy(g_eDBConfig[MYSQL_PASS], charsmax(g_eDBConfig[MYSQL_PASS]), szValue) + } + } + else if(equal(szString, SQL_DATABASE)) + { + if(szValue[0] == EOS) + { + LogReadingError(SQL_DATABASE) + } + else + { + copy(g_eDBConfig[MYSQL_DB], charsmax(g_eDBConfig[MYSQL_DB]), szValue) + } + } + else if(equal(szString, SQL_DBTABLE)) + { + if(szValue[0] == EOS) + { + LogReadingError(SQL_DBTABLE) + } + else + { + copy(g_eDBConfig[MYSQL_TABLE], charsmax(g_eDBConfig[MYSQL_TABLE]), szValue) + } + } + else if(equal(szString, AUTH_METHOD)) + { + if(szValue[0] == EOS) + { + LogReadingError(AUTH_METHOD) + } + g_bAuthData = bool:clamp(str_to_num(szValue), 0, 1) + } + else if(equal(szString, INSTANT_SAVE)) + { + g_iSaveInstant = clamp(str_to_num(szValue), 0, 1) + } + else if(equal(szString, MESSAGE_TYPE)) + { + if(MVP_CHAT_MSG <= str_to_num(szValue) <= MVP_HUD_MSG) + { + g_iMessageType = str_to_num(szValue) + } + else + { + g_iMessageType = MVP_DHUD_MSG + } + } + else if(equal(szString, HUD_COLOR)) + { + parse(szValue, szHudColorR, charsmax(szHudColorR), szHudColorG, charsmax(szHudColorG), szHudColorB, charsmax(szHudColorB)) + g_iHudColor[HudColorR] = str_to_num(szHudColorR) + g_iHudColor[HudColorG] = str_to_num(szHudColorG) + g_iHudColor[HudColorB] = str_to_num(szHudColorB) + } + else if(equal(szString, HUD_POSITION)) + { + parse(szValue, szHudPosX, charsmax(szHudPosX), szHudPosY, charsmax(szHudPosY)) + g_fHudPos[HudPosX] = _:str_to_float(szHudPosX) + g_fHudPos[HudPosY] = _:str_to_float(szHudPosY) + } + else if(equal(szString, MENU_COMMANDS)) + { + while(szValue[0] != EOS && strtok(szValue, szString, charsmax(szString), szValue, charsmax(szValue), ',')) + { + register_clcmd(szString, "Clcmd_MVPMenu") + } + } + else if(equal(szString, VIP_ACCESS)) + { + g_iVipFlag = FindCharPos(szValue) + } + } + } + } + fclose(iFile) + } + + CC_SetPrefix(g_szPrefix[PREFIX_CHAT]) + + if(g_iTracksNum > 0) + { + g_bExistTracks = true + } + + DetectSaveType() +} + +public client_authorized(id) +{ + get_user_name(id, g_szName[id], charsmax(g_szName)) + get_user_authid(id, g_szAuthID[id], charsmax(g_szAuthID)) +} + +public client_putinserver(id) +{ + g_IsConnected |= ( 1 << ( id & 31 ) ) + + g_iUserSelectedTrack[id] = -1 + + g_bDisableTracks[id] = false + + g_iPlayerMVP[id] = 0 + + g_bLoaded[id] = false + + LoadPlayerData(id) +} + +public client_disconnected(id) +{ + if(g_eMVPlayer[iTopKiller] == id && (g_iScenario == KILLER_MVP_TERO || g_iScenario == KILLER_MVP_CT)) + { + g_eMVPlayer[iTopKiller] = -1 + } + + if(g_bIsBombDefused && g_eMVPlayer[iDefuser] == id) + { + g_eMVPlayer[iDefuser] = -1 + } + + if(g_bIsBombPlanted && g_eMVPlayer[iPlanter] == id) + { + g_eMVPlayer[iPlanter] = -1 + } + + SavePlayerData(id, true) + + g_iKills[id] = 0 + + arrayset(g_iDamage[id], 0, sizeof(g_iDamage[])) + + g_IsConnected &= ~( 1 << ( id & 31 ) ) +} + +#if defined USE_REAPI +public RG_RestartRound_Post() +{ + new iPlayers[32], iNum + get_players(iPlayers, iNum, "ch") + + for(new i; i < iNum; i++) + { + arrayset(g_iDamage[iPlayers[i]], 0, sizeof(g_iDamage[])) + } + arrayset(g_iKills, 0, charsmax(g_iKills)) + g_eMVPlayer[iTopKiller] = 0 + g_eMVPlayer[iPlanter] = 0 + g_eMVPlayer[iDefuser] = 0 + g_iScenario = NO_SCENARIO + g_bIsBombDefused = false + g_bIsBombPlanted = false +} + +public RG_Player_Damage_Post(iVictim, iInflictor, iAttacker, Float:fDamage) +{ + if(!IsPlayer(iVictim) || !IsPlayer(iAttacker) || iVictim == iAttacker) + return HC_CONTINUE + + new iHitzone = get_member(iAttacker , m_LastHitGroup) + + g_iDamage[iAttacker][iDamage] += floatround(fDamage) + if(iHitzone == HIT_HEAD) + { + g_iDamage[iAttacker][iHSDmg] += floatround(fDamage) + } + + return HC_CONTINUE +} + +public RG_Player_Killed_Post(pVictim, pAttacker, iGibs) +{ + if(!IsPlayer(pVictim) || !IsPlayer(pAttacker) || pVictim == pAttacker) + return HC_CONTINUE + + g_iKills[pAttacker]++ + + return HC_CONTINUE +} + +public RG_Round_End(WinStatus:status, ScenarioEventEndRound:event, Float:fDelay) +{ + switch(status) + { + case WINSTATUS_TERRORISTS: + { + if(g_bIsBombPlanted) + { + g_iScenario = TERO_MVP + } + else + { + g_iScenario = KILLER_MVP_TERO + } + } + case WINSTATUS_CTS: + { + if(g_bIsBombDefused) + { + g_iScenario = CT_MVP + } + else + { + g_iScenario = KILLER_MVP_CT + } + } + } + set_task(1.0, "Task_Check_Scenario") + + #if defined TESTING + client_print(0, print_chat, "rg_round_end() called") + #endif + + return HC_CONTINUE +} + +public RG_SetClientUserInfoName_Post(id, infobuffer[], szNewName[]) +{ + if(containi(infobuffer, "name") != -1) + { + if(g_iSaveInstant) + { + SavePlayerData(id) + } + + copy(g_szName[id], charsmax(g_szName[]), szNewName) + + LoadPlayerData(id) + } +} +#else +public Event_Game_Restart() +{ + new iPlayers[32], iNum + get_players(iPlayers, iNum, "ch") + + for(new i; i < iNum; i++) + { + arrayset(g_iDamage[iPlayers[i]], 0, sizeof(g_iDamage[])) + } + + arrayset(g_iKills, 0, charsmax(g_iKills)) + g_eMVPlayer[iTopKiller] = 0 + g_eMVPlayer[iPlanter] = 0 + g_eMVPlayer[iDefuser] = 0 + + g_bIsBombDefused = false + g_bIsBombPlanted = false +} + +public Ham_Player_Damage_Post(iVictim, iInflictor, iAttacker, Float:fDamage) +{ + if(!IsPlayer(iVictim) || !IsPlayer(iAttacker) || iVictim == iAttacker) + return HAM_IGNORED + + new iHitzone = get_pdata_int( iAttacker , m_LastHitGroup ) + + g_iDamage[iAttacker][iDamage] += floatround(fDamage) + if(iHitzone == HIT_HEAD) + { + g_iDamage[iAttacker][iHSDmg] += floatround(fDamage) + } + + return HAM_IGNORED +} + +public Ham_Player_Killed_Post(iVictim, iAttacker) +{ + if(!IsPlayer(iVictim) || !IsPlayer(iAttacker) || iVictim == iAttacker) + return HAM_IGNORED + + g_iKills[iAttacker]++ + + return HAM_IGNORED +} + +public Logev_Roundend() +{ + set_task(1.0, "Task_Check_Scenario") + + return PLUGIN_CONTINUE +} + +public Event_Terroristwin() +{ + if(g_bIsBombPlanted) + { + g_iScenario = TERO_MVP + } + else + { + g_iScenario = KILLER_MVP_TERO + } + + #if defined TESTING + client_print(0, print_chat, "Event_Terroristwin called") + #endif +} + +public Event_CTwin() +{ + if(g_bIsBombDefused) + { + g_iScenario = CT_MVP + } + else + { + g_iScenario = KILLER_MVP_CT + } + + #if defined TESTING + client_print(0, print_chat, "Event_CTwin called") + #endif +} + +public Fw_ClientUserInfoChanged_Post(id) +{ + new szNewName[MAX_NAME_LENGTH] + get_user_name(id, szNewName, charsmax(szNewName)) + + if(!equal(g_szName[id], szNewName)) + { + if(g_iSaveInstant) + { + SavePlayerData(id) + } + + copy(g_szName[id], charsmax(g_szName[]), szNewName) + + LoadPlayerData(id) + } +} +#endif + +public Logev_Roundstart() +{ + new iPlayers[32], iNum, iPlayer + get_players(iPlayers, iNum, "ch") + + for(new i; i < iNum; i++) + { + iPlayer = iPlayers[i] + + arrayset(g_iDamage[iPlayer], 0, sizeof(g_iDamage[])) + arrayset(g_iKills[iPlayer], 0, sizeof(g_iKills[])) + } + + g_eMVPlayer[iTopKiller] = 0 + g_eMVPlayer[iPlanter] = 0 + g_eMVPlayer[iDefuser] = 0 + g_iScenario = NO_SCENARIO + g_bIsBombDefused = false + g_bIsBombPlanted = false +} + +public csgor_user_mvp(id, event, kills) +{ + return PLUGIN_HANDLED +} + +public Task_Check_Scenario() +{ + switch(g_iScenario) + { + case NO_SCENARIO: + { + if(!g_eMVPlayer[iPlanter] || !g_eMVPlayer[iDefuser] || !g_eMVPlayer[iTopKiller]) + { + ShowMVP(NO_SCENARIO) + } + } + case TERO_MVP: + { + if(g_bIsBombPlanted && IsPlayer(g_eMVPlayer[iPlanter])) + { + g_iPlayerMVP[g_eMVPlayer[iPlanter]] += 1 + + PlayTrack(g_eMVPlayer[iPlanter]) + + ShowMVP(TERO_MVP) + + #if defined TESTING + client_print(0, print_chat, "Scenario: TERO_MVP %d", g_iScenario) + #endif + } + } + case CT_MVP: + { + if(g_bIsBombDefused && IsPlayer(g_eMVPlayer[iDefuser])) + { + g_iPlayerMVP[g_eMVPlayer[iDefuser]] += 1 + + PlayTrack(g_eMVPlayer[iDefuser]) + + ShowMVP(CT_MVP) + + #if defined TESTING + client_print(0, print_chat, "Scenario: CT_MVP %d", g_iScenario ) + #endif + } + } + case KILLER_MVP_TERO: + { + CalculateTopKiller(KILLER_MVP_TERO) + + #if defined TESTING + client_print(0, print_chat, "Scenario: KILLER_MVP_TERO %d", g_iScenario) + #endif + + } + case KILLER_MVP_CT: + { + CalculateTopKiller(KILLER_MVP_CT) + + #if defined TESTING + client_print(0, print_chat, "Scenario: KILLER_MVP_CT %d", g_iScenario) + #endif + } + } + + if(g_fwScenario != INVALID_HANDLE) + { + ExecuteForward(g_fwScenario, g_iForwardResult, WinScenario:g_iScenario) + } +} + +public bomb_explode(id) +{ + g_eMVPlayer[iPlanter] = id + g_bIsBombPlanted = true + g_iScenario = TERO_MVP + + #if defined TESTING + client_print(0, print_chat, "bomb_explode forward called") + #endif +} + +public bomb_defused(id) +{ + g_eMVPlayer[iDefuser] = id + g_bIsBombDefused = true + g_iScenario = CT_MVP + + #if defined TESTING + client_print(0, print_chat, "bomb_defused forward called") + #endif +} + +#if defined TESTING +public Clcmd_Say_Test(id) +{ + client_print(id, print_chat, "Scenario: %d", g_iScenario) + + console_print(id, "DB Host: %s", g_eDBConfig[MYSQL_HOST]) + console_print(id, "DB User: %s", g_eDBConfig[MYSQL_USER]) + console_print(id, "DB Pass: %s", g_eDBConfig[MYSQL_PASS]) + console_print(id, "DB Table: %s", g_eDBConfig[MYSQL_TABLE]) + console_print(id, "DB Database: %s", g_eDBConfig[MYSQL_DB]) + console_print(id, "Nvault DB: %s", g_eDBConfig[NVAULT_DB]) + console_print(id, "Message type: %i", g_iMessageType) + console_print(id, "Instant Save: %i", g_iSaveInstant) + console_print(id, "Selected Track: %i", g_iUserSelectedTrack[id]) + console_print(id, "Pushed Track Array: %i", ArraySize(g_aTracks)) + console_print(id, "Total Tracks: %i", g_iTracksNum) +} +#endif + +public Clcmd_MVPMenu(id) +{ + new szTemp[128] + + if(!is_player_logged(id)) + { + CC_SendMessage(id, "%L", id, "CSGOR_NOT_LOGGED") + return + } + + new bool:bHasTrack = 0 <= g_iUserSelectedTrack[id] + new eTrack[Tracks] + + if(bHasTrack) + { + ArrayGetArray(g_aTracks, g_iUserSelectedTrack[id], eTrack) + } + + formatex(szTemp, charsmax(szTemp), "\r%s \w%L^n^n\w%L^n^n%L", g_szPrefix[PREFIX_MENU], LANG_PLAYER, "MVP_MENU_TITLE", LANG_PLAYER, "MVP_SHOW_MVP_COUNT", g_iPlayerMVP[id], id, bHasTrack ? "MVP_SELECTED_TRACK" : "MVP_NOT_SELECTED", eTrack[szNAME]) + new menu = menu_create(szTemp, "Mvp_Menu_Handle") + + formatex(szTemp, charsmax(szTemp), "\w%L", LANG_PLAYER, "MVP_CHOOSE_TRACK") + menu_additem(menu, szTemp) + + formatex(szTemp, charsmax(szTemp), "\w%L", LANG_PLAYER, "MVP_TRACK_LIST") + menu_additem(menu, szTemp) + + formatex(szTemp, charsmax(szTemp), "\w%L", LANG_PLAYER, "MVP_SOUNDS_ON_OFF", g_bDisableTracks[id] ? "OFF" : "ON") + menu_additem(menu, szTemp) + + menu_display(id, menu) +} + +public Mvp_Menu_Handle(id, menu, item) +{ + if(item == MENU_EXIT || !is_user_connected(id)) + { + return MenuExit(menu) + } + + switch(item) + { + case 0: + { + Clcmd_ChooseTrack(id) + } + case 1: + { + Clcmd_TrackList(id) + } + case 2: + { + if(!g_bDisableTracks[id]) + { + g_bDisableTracks[id] = true + } + else + { + g_bDisableTracks[id] = false + } + Clcmd_MVPMenu(id) + } + } + return MenuExit(menu) +} + +public Clcmd_ChooseTrack(id) +{ + new szTemp[128], eTrack[Tracks], szSecTemp[32] + + formatex(szTemp, charsmax(szTemp), "\r%s \w%L", g_szPrefix[PREFIX_MENU], LANG_PLAYER, "MVP_CHOOSE_TRACK") + new menu = menu_create(szTemp, "Choose_Track_Handle") + + if(g_bExistTracks) + { + new iSize = ArraySize(g_aTracks) * 3 + new szData = new[iSize] + + new sTracks = new[g_iTracksNum + 1] + + TrieGetString(g_tPlayerTracks, g_szName[id], _$szData[0], iSize - 1) + + formatex(szSecTemp, charsmax(szSecTemp), "%L", LANG_PLAYER, "MVP_VIP_ONLY") + + new szInfo[3] + for(new i; i < g_iTracksNum; i++) + { + strtok(_$szData[0], _$sTracks[i], 2, _$szData[0], iSize, ',') + + ArrayGetArray(g_aTracks, i, eTrack) + + if(_$sTracks[i] == '0') + { + formatex(szTemp, charsmax(szTemp), "\w%s %s \r[\d%d\y$\r]", eTrack[szNAME], eTrack[iVipOnly] ? szSecTemp : "", eTrack[iCost]) + } + else + { + formatex(szTemp, charsmax(szTemp), "\w%s %s \r%s", eTrack[szNAME], eTrack[iVipOnly] ? szSecTemp : "", (i == g_iUserSelectedTrack[id]) ? "#" : "") + } + + formatex(szInfo, charsmax(szInfo), "%s", _$sTracks[i]) + + menu_additem(menu, szTemp, szInfo) + } + } + else + { + formatex(szTemp, charsmax(szTemp), "\w%L", LANG_PLAYER, "MVP_NO_TRACKS_LOADED") + menu_additem(menu, szTemp) + } + + menu_display(id, menu) +} + +public Choose_Track_Handle(id, menu, item) +{ + if(item == MENU_EXIT || !is_user_connected(id) || !g_bExistTracks || !is_player_logged(id)) + { + return MenuExit(menu) + } + + new szTemp[3] + menu_item_getinfo(menu, item, .info = szTemp, .infolen = charsmax(szTemp)) + + new eTracks[Tracks] + + ArrayGetArray(g_aTracks, item, eTracks) + + if(eTracks[iVipOnly] && !IsUserVip(id)) + { + CC_SendMessage(id, "^1%L", LANG_PLAYER, "MVP_TRACK_VIP_ONLY") + return MenuExit(menu) + } + + if(szTemp[0] == '0') + { + new iPoints = get_player_points(id) + if(iPoints < eTracks[iCost]) + { + CC_SendMessage(id, "^1%L", id, "MVP_BUY_FAILED", eTracks[szNAME], iPoints, eTracks[iCost]) + return MenuExit(menu) + } + else + { + new iSize = ArraySize(g_aTracks) * 3 + new szData = new[iSize] + new szTemp = new[iSize] + new sTemp[3] + + TrieGetString(g_tPlayerTracks, g_szName[id], _$szData[0], iSize - 1) + + for(new i; i < g_iTracksNum; i++) + { + strtok(_$szData[0], sTemp, charsmax(sTemp), _$szData[0], iSize - 1, ',') + if(i == 0) + formatex(_$szTemp[0], iSize - 1, "%c", (i == item) ? '1' : sTemp[0]) + else + format(_$szTemp[0], iSize - 1, "%s,%c", _$szTemp[0], (i == item) ? '1' : sTemp[0]) + } + + set_player_points(id, iPoints - eTracks[iCost]) + + TrieSetString(g_tPlayerTracks, g_szName[id], _$szTemp[0]) + CC_SendMessage(id, "^1%L", id, "MVP_BUY_SUCCESS", eTracks[szNAME], eTracks[iCost]) + Clcmd_ChooseTrack(id) + + return MenuExit(menu) + } + } + + new bool:bSameTrack + + if(item == g_iUserSelectedTrack[id]) + { + bSameTrack = true + } + + if(!bSameTrack) + { + g_iUserSelectedTrack[id] = item + CC_SendMessage(id, "^1%L", LANG_PLAYER, "MVP_TRACK_X_SELECTED", ReplaceMColors(eTracks[szNAME], charsmax(eTracks[szNAME]))) + } + else + { + g_iUserSelectedTrack[id] = -1 + CC_SendMessage(id, "^1%L", LANG_PLAYER, "MVP_TRACK_X_DESELECTED", ReplaceMColors(eTracks[szNAME], charsmax(eTracks[szNAME]))) + } + + if(g_iSaveInstant) + { + SavePlayerData(id) + } + + return MenuExit(menu) +} + +public Clcmd_TrackList(id) +{ + new szTemp[128], eTrack[Tracks], szSecTemp[32] + + formatex(szTemp, charsmax(szTemp), "%s %L", g_szPrefix[PREFIX_MENU], LANG_PLAYER, "MVP_TRACK_LIST_TITLE") + new menu = menu_create(szTemp, "Clcmd_Tracklist_Handle") + + if(g_bExistTracks) + { + formatex(szSecTemp, charsmax(szSecTemp), "%L", LANG_PLAYER, "MVP_VIP_ONLY") + + new iDuration + + for(new i; i < g_iTracksNum; i++) + { + ArrayGetArray(g_aTracks, i, eTrack) + iDuration = floatround(eTrack[flDuration]) + + formatex(szTemp, charsmax(szTemp), "\w%s %s | \r%02d%s\w:\r%02d\ys", eTrack[szNAME], eTrack[iVipOnly] ? szSecTemp : "", + iDuration / 60, iDuration / 60 > 0 ? "\ym" : "", iDuration % 60) + menu_additem(menu, szTemp) + } + } + else + { + formatex(szTemp, charsmax(szTemp), "\w%L", LANG_PLAYER, "MVP_NO_TRACKS_LOADED") + menu_additem(menu, szTemp) + } + menu_display(id, menu) +} + +public Clcmd_Tracklist_Handle(id, menu, item) +{ + if(item == MENU_EXIT || !is_user_connected(id)) + { + return MenuExit(menu) + } + + new eTracks[Tracks] + + ArrayGetArray(g_aTracks, item, eTracks) + + PlaySound(id, eTracks[szPATH]) + + CC_SendMessage(id, "^1%L ^4%s^1.", LANG_PLAYER, "MVP_PLAYING_TRACK", eTracks[szNAME]) + + if(g_bExistTracks) + { + Clcmd_MVPMenu(id) + } + + return MenuExit(menu) +} + +DetectSaveType() +{ + static iTry + if(iTry == MAX_CONNECT_TRY || !CheckValidDatabase()) + { + SQL_SetAffinity("sqlite") + + if(iTry) + { + log_to_file(LOG_FILE, "MVP: Failed to connect to MySql Database, switched to SqLite!") + } + + if(!CheckValidDatabase()) + { + log_to_file(LOG_FILE, "MVP: One or more data field for database is empty. Switched to SqLite!") + } + } + + g_hSqlTuple = SQL_MakeDbTuple(g_eDBConfig[MYSQL_HOST], g_eDBConfig[MYSQL_USER], g_eDBConfig[MYSQL_PASS], g_eDBConfig[MYSQL_DB]) + + new iError + g_iSqlConnection = SQL_Connect(g_hSqlTuple, iError, g_szSqlError, charsmax(g_szSqlError)) + + if(g_iSqlConnection == Empty_Handle) + { + log_to_file(LOG_FILE, "MVP: Failed to connect to database. %s", iTry ? "Connecting to SqLite..." : "Retrying!") + iTry += 1 + DetectSaveType() + return + } + + new Handle:iQueries = SQL_PrepareQuery(g_iSqlConnection, "CREATE TABLE IF NOT EXISTS `%s`\ + (`AuthID` VARCHAR(32) NOT NULL,\ + `Player MVP` INT NOT NULL,\ + `Track` INT NOT NULL,\ + `Disabled` INT NOT NULL,\ + `Bought Tracks` TEXT NOT NULL, \ + PRIMARY KEY(AuthID));", g_eDBConfig[MYSQL_TABLE]) + + if(!SQL_Execute(iQueries)) + { + SQL_QueryError(iQueries, g_szSqlError, charsmax(g_szSqlError)) + log_amx(g_szSqlError) + } + + SQL_FreeHandle(iQueries) +} + +LoadPlayerData(id) +{ + if(is_user_bot(id) && is_user_hltv(id)) + return + + new Handle:iQuery = SQL_PrepareQuery(g_iSqlConnection, "SELECT * FROM `%s` WHERE `AuthID` = ^"%s^";", g_eDBConfig[MYSQL_TABLE], g_bAuthData ? g_szAuthID[id] : g_szName[id]) + + if(!SQL_Execute(iQuery)) + { + SQL_QueryError(iQuery, g_szSqlError, charsmax(g_szSqlError)) + log_to_file(LOG_FILE, g_szSqlError) + SQL_FreeHandle(iQuery) + return + } + + new szQuery[256] + new bool:bFoundData = SQL_NumResults( iQuery ) > 0 ? true : false + + new iSize = ArraySize(g_aTracks) * 2 + new szData = new[iSize] + + if(!bFoundData) + { + copy(_$szData[0], iSize - 1, "0") + for(new i; i < ArraySize(g_aTracks) - 1; i++) + { + format(_$szData[0], iSize - 1, "%s,%d", _$szData[0], 0) + } + + TrieSetString(g_tPlayerTracks, g_szName[id], _$szData[0]) + formatex(szQuery, charsmax(szQuery), "INSERT INTO `%s` (`AuthID`, `Player MVP`, `Track`, `Disabled`, `Bought Tracks`) VALUES (^"%s^", '0', '0', '0', ^"%s^");", g_eDBConfig[MYSQL_TABLE], g_bAuthData ? g_szAuthID[id] : g_szName[id], _$szData[0]) + } + else + { + formatex(szQuery, charsmax(szQuery), "SELECT * FROM %s WHERE `AuthID` = ^"%s^";", g_eDBConfig[MYSQL_TABLE], g_bAuthData ? g_szAuthID[id] : g_szName[id]) + } + + iQuery = SQL_PrepareQuery(g_iSqlConnection, szQuery) + + if(!SQL_Execute(iQuery)) + { + SQL_QueryError(iQuery, g_szSqlError, charsmax(g_szSqlError)) + log_to_file(LOG_FILE, g_szSqlError) + SQL_FreeHandle(iQuery) + return + } + + if(bFoundData) + { + if(SQL_NumResults(iQuery) > 0) + { + g_iPlayerMVP[id] = SQL_ReadResult(iQuery, SQL_FieldNameToNum(iQuery, "Player MVP")) + g_iUserSelectedTrack[id] = SQL_ReadResult(iQuery, SQL_FieldNameToNum(iQuery, "Track")) + g_bDisableTracks[id] = SQL_ReadResult(iQuery, SQL_FieldNameToNum(iQuery, "Disabled")) == 1 ? true : false + SQL_ReadResult(iQuery, SQL_FieldNameToNum(iQuery, "Bought Tracks"), _$szData[0], iSize - 1) + + // Check if the user has saved any new tracks + new iLen = strlen(_$szData[0]) + if(iLen < (ArraySize(g_aTracks) * 2 - 1)) + { + // If the user has not every track indexed in database, insert new zeros + for(new i = (iLen -1) / 2; i < ArraySize(g_aTracks) - 1; i++) + { + add(_$szData[0], iSize - 1, ",0") + } + } + + TrieSetString(g_tPlayerTracks, g_szName[id], _$szData[0]) + } + } + + SQL_FreeHandle(iQuery) + + g_bLoaded[id] = true +} + +SavePlayerData(id, bool:bDisconnect = false) +{ + if(is_user_bot(id) || is_user_hltv(id) || !g_bLoaded[id]) + return + + new iSize = ArraySize(g_aTracks) * 3 + 12 + new szData = new[iSize] + + new szQuery[256] + + TrieGetString(g_tPlayerTracks, g_szName[id], _$szData[0], iSize - 1) + + formatex(szQuery, charsmax(szQuery), "UPDATE `%s` SET `Player MVP`='%i', `Track`='%i', `Disabled`='%i', `Bought Tracks`=^"%s^" WHERE `AuthID`=^"%s^";", g_eDBConfig[MYSQL_TABLE], g_iPlayerMVP[id], g_iUserSelectedTrack[id], g_bDisableTracks[id] ? 1 : 0, _$szData[0], g_bAuthData ? g_szAuthID[id] : g_szName[id]) + + if(bDisconnect) + TrieDeleteKey(g_tPlayerTracks, g_szName[id]) + + new Handle:iQuery = SQL_PrepareQuery(g_iSqlConnection, szQuery) + + if(!SQL_Execute(iQuery)) + { + SQL_QueryError(iQuery, g_szSqlError, charsmax(g_szSqlError)) + log_to_file(LOG_FILE, g_szSqlError) + } + + SQL_FreeHandle(iQuery) +} + +CalculateTopKiller(WinScenario:status) +{ + if((g_bIsBombDefused || g_bIsBombPlanted) && (g_eMVPlayer[iDefuser] || g_eMVPlayer[iPlanter])) + return PLUGIN_HANDLED + + new iPlayers[32], iNum, iPlayer + + get_players(iPlayers, iNum, "ceh", status == KILLER_MVP_TERO ? "TERRORIST" : "CT") + + new iFrags, iTemp, iTempID, bool:bIsValid + for(new i; i < iNum; i++) + { + iPlayer = iPlayers[i] + + iFrags = g_iKills[iPlayer] + + if(iFrags > iTemp) + { + iTemp = iFrags + iTempID = iPlayer + } + } + + if(0 < iTempID) + { + g_eMVPlayer[iTopKiller] = iTempID + bIsValid = true + } + else + { + bIsValid = false + } + + switch(bIsValid) + { + case true: + { + g_iPlayerMVP[g_eMVPlayer[iTopKiller]] += 1 + + PlayTrack(g_eMVPlayer[iTopKiller]) + + ShowMVP(KILLER_MVP) + } + case false: + { + ShowMVP(NO_SCENARIO) + } + } + + return PLUGIN_HANDLED +} + +ShowMVP(WinScenario:iScenario) +{ + switch(iScenario) + { + case NO_SCENARIO: + { + switch(g_iMessageType) + { + case MVP_CHAT_MSG: + { + CC_SendMessage(0, "^1%L", LANG_SERVER, "NO_MVP_SHOW_CHAT") + } + case MVP_DHUD_MSG: + { + set_dhudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_dhudmessage(0, "%s %L", g_szPrefix[PREFIX_HUD], LANG_SERVER, "NO_MVP_SHOW_HUD") + } + case MVP_HUD_MSG: + { + set_hudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_hudmessage(0, "%s %L", g_szPrefix[PREFIX_HUD], LANG_SERVER, "NO_MVP_SHOW_HUD") + } + } + } + case TERO_MVP: + { + switch(g_iMessageType) + { + case MVP_CHAT_MSG: + { + CC_SendMessage(0, "^1%L", LANG_SERVER, "MVP_PLANTER_SHOW_CHAT", g_szName[g_eMVPlayer[iPlanter]]) + CC_SendMessage(0, "%L ^4%s", LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + case MVP_DHUD_MSG: + { + set_dhudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_dhudmessage(0, "%s %L^n%L %s", g_szPrefix[PREFIX_HUD], LANG_SERVER, "MVP_PLANTER_SHOW_HUD", g_szName[g_eMVPlayer[iPlanter]], LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + case MVP_HUD_MSG: + { + set_hudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_hudmessage(0, "%s %L^n%L %s", g_szPrefix[PREFIX_HUD], LANG_SERVER, "MVP_PLANTER_SHOW_HUD", g_szName[g_eMVPlayer[iPlanter]], LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + } + } + case CT_MVP: + { + switch(g_iMessageType) + { + case MVP_CHAT_MSG: + { + CC_SendMessage(0, "^1%L", LANG_SERVER, "MVP_DEFUSER_SHOW_CHAT", g_szName[g_eMVPlayer[iDefuser]]) + CC_SendMessage(0, "%L ^4%s", LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + case MVP_DHUD_MSG: + { + set_dhudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_dhudmessage(0, "%s %L^n%L %s", g_szPrefix[PREFIX_HUD], LANG_SERVER, "MVP_DEFUSER_SHOW_HUD", g_szName[g_eMVPlayer[iDefuser]], LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + case MVP_HUD_MSG: + { + set_hudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_hudmessage(0, "%s %L^n%L %s", g_szPrefix[PREFIX_HUD], LANG_SERVER, "MVP_DEFUSER_SHOW_HUD", g_szName[g_eMVPlayer[iDefuser]], LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + } + } + case KILLER_MVP: + { + switch(g_iMessageType) + { + case MVP_CHAT_MSG: + { + CC_SendMessage(0, "^1%L", LANG_SERVER, "MVP_KILLER_SHOW_CHAT", g_szName[g_eMVPlayer[iTopKiller]], g_iKills[g_eMVPlayer[iTopKiller]]) + CC_SendMessage(0, "%L ^4%s", LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + case MVP_DHUD_MSG: + { + set_dhudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_dhudmessage(0, "%s %L^n%L %s", g_szPrefix[PREFIX_HUD], LANG_SERVER, "MVP_KILLER_SHOW_HUD", g_szName[g_eMVPlayer[iTopKiller]], g_iKills[g_eMVPlayer[iTopKiller]], LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED") , g_szPlayingTrack) + } + case MVP_HUD_MSG: + { + set_hudmessage(g_iHudColor[HudColorR], g_iHudColor[HudColorG], g_iHudColor[HudColorB], g_fHudPos[HudPosX], g_fHudPos[HudPosY], 1) + show_hudmessage(0, "%s %L^n%L %s", g_szPrefix[PREFIX_HUD], LANG_SERVER, "MVP_KILLER_SHOW_HUD", g_szName[g_eMVPlayer[iTopKiller]], g_iKills[g_eMVPlayer[iTopKiller]], LANG_SERVER, (g_bExistTracks ? "MVP_PLAYING_TRACK" : "MVP_NO_TRACKS_LOADED"), g_szPlayingTrack) + } + } + } + } +} + +PlayTrack(iIndex) +{ + if(g_iSaveInstant) + { + SavePlayerData(iIndex) + } + + if(!g_bExistTracks) + { + return + } + + new iPlayers[MAX_PLAYERS], iPlayer, iNum + get_players(iPlayers, iNum, "ch") + + new eTrack[Tracks], iRandom, Array:aTempArray, bool:bTakeTemp, iTempID + if(g_bNotOnlyVip) + { + aTempArray = ArrayCreate(Tracks) + for(new i; i < ArraySize(g_aTracks); i++) + { + ArrayGetArray(g_aTracks, i, eTrack) + + if(!eTrack[iVipOnly]) + { + ArrayPushCell(aTempArray, i) + } + } + } + + if(g_iUserSelectedTrack[iIndex] != -1 && g_iUserSelectedTrack[iIndex] <= ArraySize(g_aTracks)) + { + ArrayGetArray(g_aTracks, g_iUserSelectedTrack[iIndex], eTrack) + if(eTrack[iVipOnly] && !IsUserVip(iIndex)) + { + { + if(g_bNotOnlyVip) + { + bTakeTemp = true + } + g_iUserSelectedTrack[iIndex] = -1 + } + } + } + else + { + if(!IsUserVip(iIndex) && g_bNotOnlyVip) + { + bTakeTemp = true + } + + new iSize = ArraySize(bTakeTemp ? aTempArray : g_aTracks) + + iRandom = iSize > 1 ? random_num(0, iSize - 1) : (iSize - 1) + + if(bTakeTemp) + { + iTempID = ArrayGetCell(aTempArray, iRandom) + } + + ArrayGetArray(g_aTracks, bTakeTemp ? iTempID : iRandom , eTrack) + } + + if(g_bNotOnlyVip) + { + ArrayDestroy(aTempArray) + } + + copy(g_szPlayingTrack, charsmax(g_szPlayingTrack), eTrack[szNAME]) + ReplaceMColors(g_szPlayingTrack, charsmax(g_szPlayingTrack)) + + for(new i; i < iNum; i++) + { + iPlayer = iPlayers[i] + + if(!g_bDisableTracks[iPlayer]) + { + PlaySound(iPlayer, eTrack[szPATH]) + } + } +} + +PlaySound(id, const sound[]) +{ + if(g_IsConnected & ( 1 << ( id & 31 ) ) ) + { + client_cmd(id, "stopsound") + if (equal(sound[strlen(sound)-4], ".mp3")) + client_cmd(id, "mp3 play ^"sound/%s^"", sound); + else + client_cmd(id, "spk ^"%s^"", sound); + } +} + +Float:GetTrackDuration(szTrack[]) +{ + return sfile_get_duration(szTrack) +} + +MenuExit(menu) +{ + menu_destroy(menu) + + return PLUGIN_HANDLED +} + +ReplaceMColors(szString[], iLen) +{ + new szTemp[64] + for(new i; i < sizeof(MenuColors); i++) + { + replace_all(szString, iLen, MenuColors[i], "") + } + + formatex(szTemp, iLen, szString) + + return szTemp +} + +IsUserVip(id) +{ + if(g_iVipFlag < 0) + { + abort(AMX_ERR_PARAMS, "[MVP] VIP_ACCESS parameter must be an ASCII alphabet character!") + } + + if(get_user_flags(id) & (1 << (g_iVipFlag - 1))) + return true + + return false +} + +FindCharPos(Char[]) +{ + if(isalpha(Char[0])) + { + return (Char[0] & 31) + } + return -1; +} + +LogReadingError(const szError[]) +{ + log_to_file(LOG_FILE, "[MVP] You have a missing parameter on line ^"%s^"", szError) +} + +bool:CheckValidDatabase() +{ + if(g_eDBConfig[MYSQL_HOST][0] != EOS && g_eDBConfig[MYSQL_USER][0] != EOS && g_eDBConfig[MYSQL_PASS][0] != EOS && g_eDBConfig[MYSQL_DB][0] != EOS) + { + return true + } + return false +} + +public native_get_user_mvp_kills(iPluginID, iParamNum) +{ + if(iParamNum != 1) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid param num ! Valid: (PlayerID)") + return NATIVE_ERROR + } + + new id = get_param(1) + + if(!IsPlayer(id)) + { + log_error(AMX_ERR_NATIVE, "[MVP] Player is not connected (%d)", id) + return NATIVE_ERROR + } + + return g_iKills[g_eMVPlayer[iTopKiller]] +} + +public native_get_user_mvp_topkiller(iPluginID, iParamNum) +{ + if(iParamNum != 1) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid param num ! Valid: (PlayerID)") + return NATIVE_ERROR + } + + new id = get_param(1) + + if(!IsPlayer(id)) + { + log_error(AMX_ERR_NATIVE, "[MVP] Player is not connected (%d)", id) + return NATIVE_ERROR + } + + return g_eMVPlayer[iTopKiller] +} + +public native_get_user_mvp_damage(iPluginID, iParamNum) +{ + if(iParamNum != 1) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid param num ! Valid: (PlayerID)") + return NATIVE_ERROR + } + + new id = get_param(1) + + if(!IsPlayer(id)) + { + log_error(AMX_ERR_NATIVE, "[MVP] Player is not connected (%d)", id) + return NATIVE_ERROR + } + + return g_iDamage[g_eMVPlayer[iTopKiller]][iDamage] +} + +public native_get_user_mvp_hs_damage(iPluginID, iParamNum) +{ + if(iParamNum != 1) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid param num ! Valid: (PlayerID)") + return NATIVE_ERROR + } + + new id = get_param(1) + + if(!IsPlayer(id)) + { + log_error(AMX_ERR_NATIVE, "[MVP] Player is not connected (%d)", id) + return NATIVE_ERROR + } + + return g_iDamage[g_eMVPlayer[iTopKiller]][iHSDmg] +} + +public native_get_user_mvp(iPluginID, iParamNum) +{ + if(iParamNum != 1) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid param num ! Valid: (PlayerID)") + return NATIVE_ERROR + } + + new id = get_param(1) + + if(!IsPlayer(id)) + { + log_error(AMX_ERR_NATIVE, "[MVP] Player is not connected (%d)", id) + return NATIVE_ERROR + } + + return g_iPlayerMVP[id] +} + +public native_get_user_mvp_track(iPluginID, iParamNum) +{ + if(iParamNum != 1) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid param num ! Valid: (PlayerID)") + return NATIVE_ERROR + } + + new id = get_param(1) + + if(!IsPlayer(id)) + { + log_error(AMX_ERR_NATIVE, "[MVP] Player is not connected (%d)", id) + return NATIVE_ERROR + } + + return g_iUserSelectedTrack[id] +} + +public native_get_mvp_track_info(iPluginID, iParamNum) +{ + enum { arg_trackid = 1, arg_name, arg_namelen, arg_path, arg_pathlen, arg_viponly, + arg_cost, arg_duration } + + if(iParamNum != arg_duration) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid param num ! Valid: (%d)", arg_duration) + return NATIVE_ERROR + } + + new iTrackID = get_param(arg_trackid) + new iSize = ArraySize(g_aTracks) + + if(0 > iTrackID || iSize < iTrackID ) + { + log_error(AMX_ERR_NATIVE, "[MVP] Invalid TrackID ! Got %d, Expected ( Min: %d | Max: %d )", iTrackID, 0, iSize - 1) + return NATIVE_ERROR + } + + new iData[Tracks] + ArrayGetArray(g_aTracks, iTrackID, iData) + + set_string(arg_name, ReplaceMColors(iData[szNAME], charsmax(iData[szNAME])), get_param(arg_namelen)) + set_string(arg_path, iData[szPATH], get_param(arg_pathlen)) + set_param_byref(arg_viponly, iData[iVipOnly]) + set_param_byref(arg_cost, iData[iCost]) + set_float_byref(arg_duration, iData[flDuration]) + + return 1 +} + +public native_get_mvp_index(iPluginID, iParamNum) +{ + switch(g_iScenario) + { + case NO_SCENARIO: + { + return -1 + } + case TERO_MVP: + { + return g_eMVPlayer[iPlanter] + } + case CT_MVP: + { + return g_eMVPlayer[iDefuser] + } + case KILLER_MVP_TERO , KILLER_MVP_CT: + { + return g_eMVPlayer[iTopKiller] + } + } + + return -1 +} \ No newline at end of file diff --git a/addons/amxmodx/scripting/csgor_save_skin_names.sma b/addons/amxmodx/scripting/csgor_save_skin_names.sma index 21a5c3c..e192a7d 100644 --- a/addons/amxmodx/scripting/csgor_save_skin_names.sma +++ b/addons/amxmodx/scripting/csgor_save_skin_names.sma @@ -41,15 +41,6 @@ public csgor_on_configs_executed(iSuccess) { if(iSuccess) { - new pcvar = get_cvar_pointer("csgor_savetype") - - if(get_pcvar_num(pcvar) != 1) - { - - pause("d") - return - } - csgor_get_database_data(g_eSqlConnection[szSqlHost], charsmax(g_eSqlConnection[szSqlHost]), g_eSqlConnection[szSqlUsername], \ charsmax(g_eSqlConnection[szSqlUsername]), g_eSqlConnection[szSqlPassword], charsmax(g_eSqlConnection[szSqlPassword]), \ g_eSqlConnection[szSqlDatabase], charsmax(g_eSqlConnection[szSqlDatabase])) diff --git a/addons/amxmodx/scripting/include/cromchat.inc b/addons/amxmodx/scripting/include/cromchat.inc new file mode 100644 index 0000000..0a08a70 --- /dev/null +++ b/addons/amxmodx/scripting/include/cromchat.inc @@ -0,0 +1,982 @@ +#if defined _cromchat_included + #endinput +#endif + +#define _cromchat_included + +#include +#include + +#if !defined replace_string + #define replace_string replace_all +#endif + +#if !defined CC_DONT_OVERWRITE_183_PRINT + #define client_print_color CC_SendMatched + #define print_team_default CC_COLOR_TEAM + #define print_team_grey CC_COLOR_GREY + #define print_team_blue CC_COLOR_BLUE + #define print_team_red CC_COLOR_RED +#endif + +#if !defined CC_DONT_OVERWRITE_COLORCHAT + #define ColorChat CC_SendMatched + #define NORMAL CC_COLOR_TEAM + #define TEAM_COLOR CC_COLOR_TEAM + #define GREEN CC_COLOR_TEAM + #define GREY CC_COLOR_GREY + #define BLUE CC_COLOR_BLUE + #define RED CC_COLOR_RED +#endif + +#if !defined CC_DONT_OVERWRITE_ACTIVITY + #define show_activity CC_ShowActivity + #define show_activity_id CC_ShowActivityId + #define show_activity_key CC_ShowActivityKey +#endif + +#if !defined CC_DONT_OVERWRITE_WPMG + #define PrintChatColor CC_SendMatched + #define PRINT_COLOR_GREY CC_COLOR_GREY + #define PRINT_COLOR_RED CC_COLOR_RED + #define PRINT_COLOR_BLUE CC_COLOR_BLUE + #define PRINT_COLOR_PLAYERTEAM CC_COLOR_TEAM +#endif + +#if !defined CC_DONT_OVERWRITE_CHATPRINT + #define ChatPrint CC_SendMessage +#endif + +#if !defined CC_PERCENT_REPLACE + #define CC_PERCENT_REPLACE "%" +#endif + +#define CromChat CC_SendMessage + +const Float:CC_VERSION = 3.3 +const CC_MAX_ACT_PREFIX_SIZE = 10 +const CC_MAX_PLAYERS = 32 +const CC_MAX_PREFIX_SIZE = 64 +const CC_MAX_MESSAGE_SIZE = 177 +new const CC_LIBRARY_NAME[] = "cromchat" +static const CC_FILTERING_FLAGS[] = "ch" + +#if !defined CC_COLORS_TYPE + #define CC_COLORS_TYPE CC_COLORS_CROMCHAT +#endif + +#if !defined CC_ACTIVITY_FLAG + #define CC_ACTIVITY_FLAG -1 +#endif + +#if !defined CC_ACTIVITY_PREFIX_PLAYER + #define CC_ACTIVITY_PREFIX_PLAYER "PLAYER" +#endif + +#if !defined CC_ACTIVITY_PREFIX_ADMIN + #define CC_ACTIVITY_PREFIX_ADMIN "ADMIN" +#endif + +enum +{ + CC_COLOR_TEAM = CC_MAX_PLAYERS + 25, + CC_COLOR_GREY, + CC_COLOR_BLUE, + CC_COLOR_RED +} + +const CC_COLOR_WHITE = CC_COLOR_GREY + +enum +{ + CC_COLORS_CROMCHAT, + CC_COLORS_SHORT, + CC_COLORS_NAMED, + CC_COLORS_NAMED_SHORT, + CC_COLORS_STANDARD, + CC_COLORS_CUSTOM +} + +#define CC_SYM_MENU_YELLOW "\y" +#define CC_SYM_MENU_WHITE "\w" +#define CC_SYM_MENU_GREY "\d" +#define CC_SYM_MENU_RIGHT "\R" + +#define CC_SYM_CHAT_DEF_NORMAL "^x01" +#define CC_SYM_CHAT_DEF_TEAM "^x03" +#define CC_SYM_CHAT_DEF_GREEN "^x04" + +static bool:CC_FIRST_TIME_ACTIVITY = true, bool:CC_IS_CSCZ, bool:CC_COLOR_FORCE +static CC_ACTIVITY_POINTER, CC_COLOR_PLAYER_INDEX + +new CC_PREFIX[CC_MAX_PREFIX_SIZE] + +#if CC_COLORS_TYPE == CC_COLORS_CUSTOM + #if !defined CC_SYM_CHAT_NORMAL + #define CC_SYM_CHAT_NORMAL "&x01" + #endif + + #if !defined CC_SYM_CHAT_TEAM + #define CC_SYM_CHAT_TEAM "&x03" + #endif + + #if !defined CC_SYM_CHAT_GREEN + #define CC_SYM_CHAT_GREEN "&x04" + #endif + + #if !defined CC_SYM_CHAT_WHITE + #define CC_SYM_CHAT_WHITE "&x05" + #endif + + #if !defined CC_SYM_CHAT_BLUE + #define CC_SYM_CHAT_BLUE "&x06" + #endif + + #if !defined CC_SYM_CHAT_RED + #define CC_SYM_CHAT_RED "&x07" + #endif + + #if !defined CC_SYM_CHAT_NOPREF + #define CC_SYM_CHAT_NOPREF "&x00" + #endif +#else + #if CC_COLORS_TYPE == CC_COLORS_CROMCHAT + #define CC_SYM_CHAT_NORMAL "&x01" + #define CC_SYM_CHAT_TEAM "&x03" + #define CC_SYM_CHAT_GREEN "&x04" + #define CC_SYM_CHAT_WHITE "&x05" + #define CC_SYM_CHAT_BLUE "&x06" + #define CC_SYM_CHAT_RED "&x07" + #define CC_SYM_CHAT_NOPREF "&x00" + #endif + + #if CC_COLORS_TYPE == CC_COLORS_SHORT + #define CC_SYM_CHAT_NORMAL "!n" + #define CC_SYM_CHAT_TEAM "!t" + #define CC_SYM_CHAT_GREEN "!g" + #define CC_SYM_CHAT_WHITE "!w" + #define CC_SYM_CHAT_BLUE "!b" + #define CC_SYM_CHAT_RED "!r" + #define CC_SYM_CHAT_NOPREF "!p" + #endif + + #if CC_COLORS_TYPE == CC_COLORS_NAMED + #define CC_SYM_CHAT_NORMAL "{normal}" + #define CC_SYM_CHAT_TEAM "{team}" + #define CC_SYM_CHAT_GREEN "{green}" + #define CC_SYM_CHAT_WHITE "{white}" + #define CC_SYM_CHAT_BLUE "{blue}" + #define CC_SYM_CHAT_RED "{red}" + #define CC_SYM_CHAT_NOPREF "{nopref}" + #endif + + #if CC_COLORS_TYPE == CC_COLORS_NAMED_SHORT + #define CC_SYM_CHAT_NORMAL "{n}" + #define CC_SYM_CHAT_TEAM "{t}" + #define CC_SYM_CHAT_GREEN "{g}" + #define CC_SYM_CHAT_WHITE "{w}" + #define CC_SYM_CHAT_BLUE "{b}" + #define CC_SYM_CHAT_RED "{r}" + #define CC_SYM_CHAT_NOPREF "{p}" + #endif + + #if CC_COLORS_TYPE == CC_COLORS_STANDARD + #define CC_SYM_CHAT_NORMAL "^1" + #define CC_SYM_CHAT_TEAM "^3" + #define CC_SYM_CHAT_GREEN "^4" + #define CC_SYM_CHAT_WHITE "^5" + #define CC_SYM_CHAT_BLUE "^6" + #define CC_SYM_CHAT_RED "^7" + #define CC_SYM_CHAT_NOPREF "^0" + #endif +#endif + +static const CC_NO_PREFIX[] = CC_SYM_CHAT_NOPREF +static const CC_MENU_COLORS[][] = { CC_SYM_MENU_YELLOW, CC_SYM_MENU_WHITE, CC_SYM_MENU_GREY, CC_SYM_MENU_RIGHT } +static const CC_REPLACE_COLORS[][] = { CC_SYM_CHAT_GREEN, CC_SYM_CHAT_DEF_GREEN, CC_SYM_CHAT_TEAM, CC_SYM_CHAT_DEF_TEAM, CC_SYM_CHAT_NORMAL, CC_SYM_CHAT_DEF_NORMAL } +static const CC_PLUS_COLORS_STR[][] = { CC_SYM_CHAT_RED, CC_SYM_CHAT_BLUE, CC_SYM_CHAT_WHITE } +static const CC_PLUS_COLORS_INT[] = { CC_COLOR_RED, CC_COLOR_BLUE, CC_COLOR_WHITE } +static const CC_COLORS_LIST[][] = { CC_SYM_CHAT_RED, CC_SYM_CHAT_BLUE, CC_SYM_CHAT_WHITE, CC_SYM_CHAT_GREEN, CC_SYM_CHAT_TEAM, CC_SYM_CHAT_NORMAL, CC_SYM_CHAT_NOPREF } + +/** + * Sends a colored chat message. + * + * @param id Client index (use 0 to send to all players) + * @param input The message to send + * @param ... Variable number of formatting parameters + * + * @return Length of the printed message + */ +stock CC_SendMessage(id, const input[], any:...) +{ + _CC_ModInit() + static iPlayers[CC_MAX_PLAYERS], iPnum + + if(id) + { + if(!is_user_connected(id)) + { + return 0 + } + } + else + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + if(!iPnum) + { + return 0 + } + } + + static szMessage[CC_MAX_MESSAGE_SIZE], bool:bNoPrefix, i + vformat(szMessage[1], charsmax(szMessage), input, 3) + szMessage[0] = 0x01 + + bNoPrefix = bool:(equal(szMessage[1], CC_NO_PREFIX, charsmax(CC_NO_PREFIX)) || equal(szMessage[2], CC_NO_PREFIX, charsmax(CC_NO_PREFIX))) + + if(bNoPrefix) + { + replace(szMessage, charsmax(szMessage), CC_NO_PREFIX, "") + } + else if(CC_PREFIX[0]) + { + if(CC_IS_CSCZ) + { + format(szMessage, charsmax(szMessage), "%s%s %s%s", CC_SYM_CHAT_DEF_NORMAL, CC_PREFIX, CC_SYM_CHAT_DEF_NORMAL, szMessage) + } + else + { + format(szMessage, charsmax(szMessage), "%s%s %s", CC_SYM_CHAT_DEF_NORMAL, CC_PREFIX, szMessage) + } + } + + for(i = 0; i < sizeof(CC_REPLACE_COLORS) - 1; i += 2) + { + if(CC_IS_CSCZ) + { + replace_string(szMessage, charsmax(szMessage), CC_REPLACE_COLORS[i], CC_REPLACE_COLORS[i + 1]) + } + else + { + replace_string(szMessage, charsmax(szMessage), CC_REPLACE_COLORS[i], "") + } + } + + for(i = 0; i < sizeof(CC_PLUS_COLORS_STR); i++) + { + if(contain(szMessage, CC_PLUS_COLORS_STR[i]) != -1) + { + if(!CC_COLOR_FORCE) + { + CC_COLOR_PLAYER_INDEX = CC_PLUS_COLORS_INT[i] + } + + for(i = 0; i < 3; i++) + { + if(CC_IS_CSCZ) + { + replace_string(szMessage, charsmax(szMessage), CC_COLORS_LIST[i], CC_SYM_CHAT_DEF_TEAM) + } + else + { + replace_string(szMessage, charsmax(szMessage), CC_COLORS_LIST[i], "") + } + } + + break + } + } + + if(id) + { + _CC_WriteMessage(id, szMessage) + } + else + { + for(i = 0; i < iPnum; i++) + { + _CC_WriteMessage(iPlayers[i], szMessage) + } + } + + CC_COLOR_FORCE = false + CC_COLOR_PLAYER_INDEX = 0 + + return strlen(szMessage) +} + +/** + * Sends a colored chat message matching a specific player's color. + * + * @note You can use the "player" argument to set a specific color instead of matching + * it automtaically. To do this, you can use one of the following color arguments: + * CC_COLOR_TEAM, CC_COLOR_GREY (or CC_COLOR_WHITE), CC_COLOR_BLUE, CC_COLOR_RED. + * + * @param id Client index (use 0 to send to all players) + * @param player Matching player's index + * @param input The message to send + * @param ... Variable number of formatting parameters + * + * @return Length of the printed message + */ +stock CC_SendMatched(id, player, const input[], any:...) +{ + static szMessage[CC_MAX_MESSAGE_SIZE] + vformat(szMessage[1], charsmax(szMessage), input, 4) + szMessage[0] = 0x01 + CC_COLOR_PLAYER_INDEX = player + return CC_SendMessage(id, szMessage) +} + +/** + * Sends a colored chat message to a group of players matching the flags from the get_players() function. + * + * @note The filtering flags are the same that are used by the get_players() function + * + * @param flags Filtering flags + * @param params String to match against if the flags require it + * @param input The message to send + * @param ... Variable number of formatting parameters + * + * @return Length of the printed message or 0 if no players were matched + */ +stock CC_GroupMessage(const flags[] = "", const params[] = "", const input[], any:...) +{ + static szMessage[CC_MAX_MESSAGE_SIZE], iPlayers[CC_MAX_PLAYERS], iPnum + vformat(szMessage, charsmax(szMessage), input, 4) + get_players(iPlayers, iPnum, flags, params) + + if(!iPnum) + { + return 0 + } + + static bool:bForce, iColor, i + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + CC_SetColor(iColor, bForce) + CC_SendMessage(iPlayers[i], szMessage) + } + + return strlen(szMessage) +} + +/** + * Sends a colored chat message to all players who have the specified admin flags. + * + * @param flags Admin flags + * @param allflags If set to true it will match players who have ALL of the specified admin flags, otherwise it will match players with ANY of the flags + * @param input The message to send + * @param ... Variable number of formatting parameters + * + * @return Length of the printed message or 0 if no players were matched + */ +stock CC_SendAdminMessage(const flags[] = "", bool:allflags = true, const input[], any:...) +{ + static szMessage[CC_MAX_MESSAGE_SIZE], iPlayers[CC_MAX_PLAYERS], iPnum + vformat(szMessage, charsmax(szMessage), input, 4) + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + if(!iPnum) + { + return 0 + } + + static bool:bForce, iColor, iCount, iFlags, iPlayer, i + iFlags = read_flags(flags) + iCount = 0 + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + + switch(allflags) + { + case true: + { + if(get_user_flags(iPlayer) & iFlags != iFlags) + { + continue + } + } + case false: + { + if(!(get_user_flags(iPlayer) & iFlags)) + { + continue + } + } + } + + iCount++ + + CC_SetColor(iColor, bForce) + CC_SendMessage(iPlayer, szMessage) + } + + if(!iCount) + { + return 0 + } + + return strlen(szMessage) +} + +/** + * Sends a colored chat message and logs it at the same time. + * + * @note If the file name is not set, the default log file will be used instead. + * + * @param id Client index (use 0 to send to all players) + * @param file The log file that will be used + * @param input The message to send + * @param ... Variable number of formatting parameters + * + * @return Length of the printed message + */ +stock CC_LogMessage(id, const file[] = "", const input[], any:...) +{ + static szMessage[CC_MAX_MESSAGE_SIZE] + vformat(szMessage, charsmax(szMessage), input, 4) + + if(!CC_SendMessage(id, szMessage)) + { + return 0 + } + + CC_RemoveColors(szMessage, charsmax(szMessage)) + file[0] ? log_to_file(file, szMessage) : log_amx(szMessage) + return strlen(szMessage) +} + +/** + * Sends a colored chat message to all players that obeys the amx_show_activity cvar. + * + * @note This function is made to mimic the show_activity() function, but sends a + * colored chat message instead using the CC_SendMessage() function. This means + * that the default AMXX function can directly be replaced with this one in order + * for it to display a colored chat message rather than a default one. + * @note By default, cromchat.inc will replace all show_activity() functions in the file + * with the CC_ShowActivity() function. You can disable this feature by adding + * #define CC_DONT_OVERWRITE_ACTIVITY before #include in your plugin. + * + * @param id Client index performing the action + * @param name Name of client performing the action + * @param input Formatting rules + * @param ... Variable number of formatting parameters + * + * @noreturn + */ +stock CC_ShowActivity(id, const name[], const input[], any:...) +{ + if(CC_FIRST_TIME_ACTIVITY) + { + _CC_ActivityInit() + } + + static szMessage[CC_MAX_MESSAGE_SIZE], szPrefix[CC_MAX_ACT_PREFIX_SIZE], iPlayers[CC_MAX_PLAYERS], bool:bForce, iPlayer, iPnum, iColor, i + vformat(szMessage, charsmax(szMessage), input, 4) + _CC_GetActivityPrefix(id, szPrefix, charsmax(szPrefix)) + + switch(get_pcvar_num(CC_ACTIVITY_POINTER)) + { + case 1: CC_SendMessage(0, "%L: %s", LANG_PLAYER, szPrefix, szMessage) + case 2: CC_SendMessage(0, "%L %s: %s", LANG_PLAYER, szPrefix, name, szMessage) + case 3: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + CC_SetColor(iColor, bForce) + + if(_CC_IsActivityAdmin(iPlayer)) + { + CC_SendMessage(iPlayer, "%L %s: %s", iPlayer, szPrefix, name, szMessage) + } + else + { + CC_SendMessage(iPlayer, "%L: %s", iPlayer, szPrefix, szMessage) + } + } + } + case 4: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + + if(_CC_IsActivityAdmin(iPlayer)) + { + CC_SetColor(iColor, bForce) + CC_SendMessage(iPlayer, "%L %s: %s", iPlayer, szPrefix, name, szMessage) + } + } + } + case 5: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + + if(_CC_IsActivityAdmin(iPlayer)) + { + CC_SetColor(iColor, bForce) + CC_SendMessage(iPlayer, "%L: %s", iPlayer, szPrefix, szMessage) + } + } + } + } +} + +/** + * Sends a colored chat message to a single client that obeys the amx_show_activity cvar. + * + * @note This function is made to mimic the show_activity_id() function, but sends a + * colored chat message instead using the CC_SendMessage() function. This means + * that the default AMXX function can directly be replaced with this one in order + * for it to display a colored chat message rather than a default one. + * @note By default, cromchat.inc will replace all show_activity_id() functions in the file + * with the CC_ShowActivityId() function. You can disable this feature by adding + * #define CC_DONT_OVERWRITE_ACTIVITY before #include in your plugin. + * + * @param target Client index to display message to + * @param id Client index performing the action + * @param name Name of client performing the action + * @param input Formatting rules + * @param ... Variable number of formatting parameters + * + * @noreturn + */ +stock CC_ShowActivityId(target, id, const name[], const input[], any:...) +{ + if(!is_user_connected(target)) + { + return + } + + if(CC_FIRST_TIME_ACTIVITY) + { + _CC_ActivityInit() + } + + static szMessage[CC_MAX_MESSAGE_SIZE], szPrefix[CC_MAX_ACT_PREFIX_SIZE] + vformat(szMessage, charsmax(szMessage), input, 5) + _CC_GetActivityPrefix(id, szPrefix, charsmax(szPrefix)) + + switch(get_pcvar_num(CC_ACTIVITY_POINTER)) + { + case 1: CC_SendMessage(target, "%L: %s", target, szPrefix, szMessage) + case 2: CC_SendMessage(target, "%L %s: %s", target, szPrefix, name, szMessage) + case 3: + { + if(_CC_IsActivityAdmin(target)) + { + CC_SendMessage(target, "%L %s: %s", target, szPrefix, name, szMessage) + } + else + { + CC_SendMessage(target, "%L: %s", target, szPrefix, szMessage) + } + } + case 4: + { + if(_CC_IsActivityAdmin(target)) + { + CC_SendMessage(target, "%L %s: %s", target, szPrefix, name, szMessage) + } + } + case 5: + { + if(_CC_IsActivityAdmin(target)) + { + CC_SendMessage(target, "%L: %s", target, szPrefix, szMessage) + } + } + } +} + +/** + * Sends a colored chat message to all clients using nromal language keys that obeys the amx_show_activity cvar. + * + * @note This function is made to mimic the show_activity_key() function, but sends a + * colored chat message instead using the CC_SendMessage() function. This means + * that the default AMXX function can directly be replaced with this one in order + * for it to display a colored chat message rather than a default one. + * @note By default, cromchat.inc will replace all show_activity_key() functions in the file + * with the CC_ShowActivityKey() function. You can disable this feature by adding + * #define CC_DONT_OVERWRITE_ACTIVITY before #include in your plugin. + * + * @param without The language key that does not have the name field + * @param with The language key that does have the name field + * @param name The name of the person doing the action + * @param ... Pass any extra format arguments for the language key in the variable arguments list + * + * @noreturn + */ +stock CC_ShowActivityKey(const without[], const with[], const name[], any:...) +{ + #pragma unused name + + if(CC_FIRST_TIME_ACTIVITY) + { + _CC_ActivityInit() + } + + static szMessage[CC_MAX_MESSAGE_SIZE], szKey[CC_MAX_MESSAGE_SIZE], iPlayers[CC_MAX_PLAYERS], bool:bForce, iPnum, iPlayer, iColor, i + + switch(get_pcvar_num(CC_ACTIVITY_POINTER)) + { + case 1: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + CC_SetColor(iColor, bForce) + + LookupLangKey(szKey, charsmax(szKey), without, iPlayer) + vformat(szMessage, charsmax(szMessage), szKey, 4) + CC_SendMessage(iPlayer, szMessage) + } + } + case 2: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + CC_SetColor(iColor, bForce) + + LookupLangKey(szKey, charsmax(szKey), with, iPlayer) + vformat(szMessage, charsmax(szMessage), szKey, 3) + CC_SendMessage(iPlayer, szMessage) + } + } + case 3: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + CC_SetColor(iColor, bForce) + + if(_CC_IsActivityAdmin(iPlayer)) + { + LookupLangKey(szKey, charsmax(szKey), with, iPlayer) + vformat(szMessage, charsmax(szMessage), szKey, 3) + } + else + { + LookupLangKey(szKey, charsmax(szKey), without, iPlayer) + vformat(szMessage, charsmax(szMessage), szKey, 4) + } + + CC_SendMessage(iPlayer, szMessage) + } + } + case 4: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + + if(_CC_IsActivityAdmin(iPlayer)) + { + CC_SetColor(iColor, bForce) + LookupLangKey(szKey, charsmax(szKey), with, iPlayer) + vformat(szMessage, charsmax(szMessage), szKey, 3) + CC_SendMessage(iPlayer, szMessage) + } + } + } + case 5: + { + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(bForce = CC_COLOR_FORCE, iColor = CC_COLOR_PLAYER_INDEX, i = 0; i < iPnum; i++) + { + iPlayer = iPlayers[i] + + if(_CC_IsActivityAdmin(iPlayer)) + { + CC_SetColor(iColor, bForce) + LookupLangKey(szKey, charsmax(szKey), without, iPlayer) + vformat(szMessage, charsmax(szMessage), szKey, 4) + CC_SendMessage(iPlayer, szMessage) + } + } + } + } +} + +/** + * Removes the color codes from a message. + * + * @param message The message to remove colors from + * @param len Maximum message length + * @param chat If set to true, it will remove the chat color codes + * @param menu If set to true, it will remove the menu color codes + * + * @noreturn + */ +stock CC_RemoveColors(message[], len, bool:chat = true, bool:menu = false) +{ + static i + + if(chat) + { + for(i = 0; i < sizeof(CC_COLORS_LIST); i++) + { + replace_string(message, len, CC_COLORS_LIST[i], "") + } + } + + if(menu) + { + for(i = 0; i < sizeof(CC_MENU_COLORS); i++) + { + replace_string(message, len, CC_MENU_COLORS[i], "") + } + } +} + +/** + * Removes exploits from the message. + * + * @note You can change the '%' replacement symbol by adding #define CC_PERCENT_REPLACE "symbol here" before #include + * @note It is strongly advised to use this function whenever you're sending messages based on hooking "say" or "say_team" + * + * @param message The message to remove exploits from + * @param len Maximum message length + * @param colors If set to true, it will remove the ETX, EOT & SOH chat color codes; + * this prevents player from manually changing their chat color when they have the chance to + * @param percent If set to true, it will replace the '%' symbol with '%' + * + * @noreturn + */ +stock CC_RemoveExploits(message[], len, bool:colors = true, bool:percent = true) +{ + static i + + if(colors) + { + static const CC_COLOR_EXPLOITS[][] = { "", "", "" } + + for(i = 0; i < sizeof(CC_COLOR_EXPLOITS); i++) + { + replace_string(message, len, CC_COLOR_EXPLOITS[i], "") + } + } + + if(percent) + { + static const CC_PERCENT_FIND[] = "%" + replace_string(message, len, CC_PERCENT_FIND, CC_PERCENT_REPLACE) + } +} + +/** + * Sets a global prefix that will be used for all sent messages. + * + * @note The prefix can be removed in a given message if the prefix-removing symbol is + * used in the beginning of the message. By default, this symbol is equal to &x00. + * + * @param prefix Prefix to set + * + * @noreturn + */ +stock CC_SetPrefix(const prefix[]) +{ + _CC_ModInit() + copy(CC_PREFIX, charsmax(CC_PREFIX), prefix) + + if(!CC_IS_CSCZ) + { + CC_RemoveColors(CC_PREFIX, charsmax(CC_PREFIX)) + } +} + +/** + * Removes the global message prefix. + * + * @noreturn + */ +stock CC_RemovePrefix() +{ + CC_PREFIX[0] = EOS +} + +/** + * Sets the team color for the next message that's going to be sent. + * + * @param index CC_COLOR_* or player index to get color from + * @param force If set to true, custom colors in the code will be ignored + * and the message will be forced to use the color set here + * + * @noreturn + */ +stock CC_SetColor(index, bool:force = false) +{ + CC_COLOR_PLAYER_INDEX = index + CC_COLOR_FORCE = force +} + +/** + * This function is used by the other stocks in order to send a raw message. + * + * @param id Client index + * @param message The message to send + * + * @noreturn + */ +stock _CC_WriteMessage(id, const message[]) +{ + static CC_INIT, CC_MSG_SAYTEXT + + if(!CC_INIT) + { + CC_INIT = true + CC_MSG_SAYTEXT = get_user_msgid("SayText") + + // Credits to WPMGPRoSToTeMa + if(!LibraryExists(CC_LIBRARY_NAME, LibType_Library)) + { + register_library(CC_LIBRARY_NAME) + + if(CC_IS_CSCZ) + { + new iCacheList[] = { CC_COLOR_GREY, CC_COLOR_BLUE, CC_COLOR_RED } + new szCacheList[][] = { "", "CT", "TERRORIST" } + new CC_MSG_TEAMINFO = get_user_msgid("TeamInfo") + + for(new i; i < sizeof(iCacheList); i++) + { + engfunc(EngFunc_MessageBegin, MSG_INIT, CC_MSG_TEAMINFO, 0, 0) + write_byte(iCacheList[i]) + write_string(szCacheList[i]) + message_end() + } + + new iPlayers[CC_MAX_PLAYERS], iPnum + get_players(iPlayers, iPnum, CC_FILTERING_FLAGS) + + for(new iPlayer, i, j; i < iPnum; i++) + { + iPlayer = iPlayers[i] + + for(j = 0; j < sizeof(iCacheList); j++) + { + message_begin(MSG_ONE, CC_MSG_TEAMINFO, _, iPlayer) + write_byte(iCacheList[j]) + write_string(szCacheList[j]) + message_end() + } + } + } + } + } + + static const CC_PLAYER_ITEM_PHRASE[] = "#Spec_PlayerItem" // Credits to WPMGPRoSToTeMa + + message_begin(MSG_ONE, CC_MSG_SAYTEXT, _, id) + + if(CC_IS_CSCZ) + { + write_byte(CC_COLOR_PLAYER_INDEX && CC_COLOR_PLAYER_INDEX != CC_COLOR_TEAM ? CC_COLOR_PLAYER_INDEX : id) + } + else + { + write_byte(id) + } + + write_string(CC_PLAYER_ITEM_PHRASE) + write_string(message) + message_end() +} + +/** + * Checks if the server is running Counter-Strike. + * + * @noreturn + */ +stock _CC_ModInit() +{ + static bool:CC_MOD_INIT + + if(!CC_MOD_INIT) + { + CC_MOD_INIT = true + + static const CC_CSTRIKE_MODNAME[] = "cstrike" + static const CC_CZERO_MODNAME[] = "czero" + + new szModName[sizeof(CC_CSTRIKE_MODNAME)] + get_modname(szModName, charsmax(szModName)) + + if(equal(szModName, CC_CSTRIKE_MODNAME) || equal(szModName, CC_CZERO_MODNAME)) + { + CC_IS_CSCZ = true + } + } +} + +/** + * Stores the amx_show_activity pointer for use with "ShowActivity" functions. + * + * @noreturn + */ +stock _CC_ActivityInit() +{ + CC_FIRST_TIME_ACTIVITY = false + CC_ACTIVITY_POINTER = get_cvar_pointer("amx_show_activity") + + if(!CC_ACTIVITY_POINTER) + { + CC_ACTIVITY_POINTER = register_cvar("amx_show_activity", "2", FCVAR_PROTECTED) + } +} + +/** + * Returns the player prefix used with "ShowActivity" functions. + * + * @param id Client index + * @param buffer Buffer to store the prefix in + * @param len Maximum buffer length + * + * @noreturn + */ +stock _CC_GetActivityPrefix(id, buffer[CC_MAX_ACT_PREFIX_SIZE], len) +{ + copy(buffer, len, _CC_IsActivityAdmin(id) ? CC_ACTIVITY_PREFIX_ADMIN : CC_ACTIVITY_PREFIX_PLAYER) +} + +/** + * Checks whether the client has the required flag to be marked as an admin for the "ShowActivity" functions. + * + * @param id Client index + * + * @return True if he has, false otherwise + */ +stock bool:_CC_IsActivityAdmin(const id) +{ + #if CC_ACTIVITY_FLAG == -1 + static iFlags + iFlags = get_user_flags(id) + return (iFlags > 0 && !(iFlags & ADMIN_USER)) + #else + return bool:(get_user_flags(id) & CC_ACTIVITY_FLAG) + #endif +} \ No newline at end of file diff --git a/addons/amxmodx/scripting/include/csgo_remake.inc b/addons/amxmodx/scripting/include/csgo_remake.inc index 4f80639..9bf1fbf 100644 --- a/addons/amxmodx/scripting/include/csgo_remake.inc +++ b/addons/amxmodx/scripting/include/csgo_remake.inc @@ -24,6 +24,13 @@ enum _:FileSections secSkipChat } +enum _:MVPEvents +{ + MVP_KILLER = 0, + MVP_PLANTER, + MVP_DEFUSER +} + /** * Returns a player's points. * @@ -429,7 +436,8 @@ forward csgor_user_assist(id, killer, victim, head); * @param event Event type. (0 - Top Killer, 1 - Planter, 2 - Defuser) * @param kills Player's kills. * - * @noreturn + * @return PLUGIN_HANDLED to prevent showing integrated MVP announcer, + * PLUGIN_CONTINUE to do nothing */ forward csgor_user_mvp(id, event, kills); diff --git a/addons/amxmodx/scripting/include/dynarrays.inc b/addons/amxmodx/scripting/include/dynarrays.inc new file mode 100644 index 0000000..424341f --- /dev/null +++ b/addons/amxmodx/scripting/include/dynarrays.inc @@ -0,0 +1,62 @@ +#if defined _dynarrays_included + #endinput +#endif +#define _dynarrays_included + +#include + +#if !defined MAX_DYNMEMORY + #define MAX_DYNMEMORY 4096 +#endif + +new any: __DA@Memory[1][MAX_DYNMEMORY]; + +#if !defined NULL + #define NULL 0 +#endif + +#define new[%0] __DA@Allocate(%0) +#define ref<%0> __DA@Reference(%0) + +#define _$%0[ (__DA@Pointer(%0), __DA@Memory[0][0])[ + +stock any: __DA@Allocate(size) +{ + if(size > MAX_DYNMEMORY) + { + server_print("Run-time error: Tried to dynamically allocate more than %d cells of memory.", MAX_DYNMEMORY); + return NULL; + } + + new ptr; + + #emit LOAD.S.pri size // Load "size" value into PRI + #emit SMUL.C 4 // Multiply it by 4 to get number of bytes + #emit MOVE.alt // Move the value to alt + #emit LCTRL 2 // Load HEA into PRI + #emit STOR.S.pri ptr // Load HEA into "ptr" + #emit ADD // Add HEA(pri) and size(alt) together + #emit SCTRL 2 // Allocate memory by moving the heap pointer + + return ptr; +} + +stock __DA@Pointer(any: ptr) +{ + // This is where the magic happens + #emit CONST.alt __DA@Memory // Get "__DA@Memory"'s header address + #emit LOAD.S.pri ptr // Load "ptr" value into PRI + #emit SUB // PRI -= ALT / get the distance between the two + #emit STOR.I // Store the distance in the header +} + +stock any: __DA@Reference(...) +{ + #emit LOAD.S.pri 12 // Load first param's address + #emit RETN +} + +public __DA@WTFIsThisFunctionDoingHere() +{ + __DA@Memory[0][0] = 0; +} diff --git a/addons/amxmodx/scripting/include/most_valuable_player.inc b/addons/amxmodx/scripting/include/most_valuable_player.inc new file mode 100644 index 0000000..b2a1ac5 --- /dev/null +++ b/addons/amxmodx/scripting/include/most_valuable_player.inc @@ -0,0 +1,100 @@ +/* Sublime AMXX Editor v4.2 */ + +#if defined _most_valuable_player_included + #endinput +#endif +#define _most_valuable_player_included + +#pragma reqlib most_valuable_player +#if !defined AMXMODX_NOAUTOLOAD + #pragma loadlib most_valuable_player +#endif + +enum WinScenario +{ + NO_SCENARIO = -1, + TERO_MVP = 0, + CT_MVP, + KILLER_MVP_TERO, + KILLER_MVP_CT, + KILLER_MVP /* Just for default: case in PlayTrack(), unusable */ +} + +/** + * @description Multiforward called when a round end. + * + * @param scenario Scenario index. See WinScenario enum + * + * @return Scenario index. + */ +forward mvp_scenario(WinScenario:scenario); + +/** + * @description Returns player's MVP kills. + * + * @param id Player index. + * + * @return Amount of kills. -1 on error. + */ +native get_user_mvp_kills(id); + +/** + * @description Returns top killer's index. + * + * @param id Top killer index. + * + * @return Top killer's index. -1 on error. + */ +native get_user_mvp_topkiller(id); + +/** + * @description Returns player's MVP damage. + * + * @param id Player index. + * + * @return Player index. -1 on error. + */ +native get_user_mvp_damage(id); + +/** + * @description Returns player's MVP damage made with headshot. + * + * @param id Player index. + * + * @return Player index. -1 on error. + */ +native get_user_mvp_hs_damage(id); + +/** + * @description Returns Player's MVPs. + * + * @param id Player index. + * + * @return Player index. -1 on error. + */ +native get_user_mvps(id); + +/** + * @description Returns Player's selected Track. + * + * @param id Player index. + * + * @return Player index. -1 on error. + */ +native get_user_mvp_track(id); + +/** + * @description Returns informations about certain Track. + * + * @param iTrackID Track index. + * @param szName[] Variable to store track name. + * @param iNameLen Track name lenght. + * @param szPath[] Variable to store track's path. + * @param iPathLen Track path lenght. + * @param iVipOnly Vip only track ( 1 / 0 ) + * @param iCost Track cost + * @param flDuration Track duration + * + * @return 1 on success. -1 if TrackID is invalid or on error. + */ +native get_mvp_track_info(iTrackID, szName[], iNameLen, szPath[], iPathLen, iVipOnly, iCost, Float:flDuration) \ No newline at end of file diff --git a/addons/amxmodx/scripting/include/soundinfo.inc b/addons/amxmodx/scripting/include/soundinfo.inc new file mode 100644 index 0000000..f5b7e98 --- /dev/null +++ b/addons/amxmodx/scripting/include/soundinfo.inc @@ -0,0 +1,340 @@ +/** + * Main informations + * MP3 + * http://www.multiweb.cz/twoinches/mp3inside.htm + * http://www.mp3-tech.org/programmer/frame_header.html + * http://pl.wikipedia.org/wiki/ID3 + * + * WAV + * https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ + */ + +#if defined _soundinfo_included +#endinput +#endif +#define _soundinfo_included + +// + +//Return Values +#define SRES_BAD_PARAMETERS -2 +#define SRES_BAD_SIGNATURE -1 +#define SRES_NOT_EXISTS 0 +#define SRES_OK 1 + +//Type of file +enum SFormat{ + SFILE_UNKNOWN, + SFILE_WAV, + SFILE_MP3 +} + +//About loading info +//new iData[SParam]; +enum SParam{ + SOUND_FREQ, + SOUND_BYTERATE, + SOUND_CHAN_NUM, + SOUND_DURATION_F +} + +//Shortcuts Stocks +stock Float:get_duration(iData[SParam]){ + return Float:iData[SOUND_DURATION_F]; +} +stock Float:sfile_get_duration(const szFilename[]){ + new iData[SParam]; + sfile_loaddata(szFilename, iData); + return get_duration(iData); +} + +stock bool:sfile_is_valid(const szFilename[]){ + switch(sfile_type(szFilename)){ + case SFILE_MP3: { + return true; + } + case SFILE_WAV: { + new iData[SParam]; + sfile_loaddata(szFilename, iData); + + return ((iData[SOUND_CHAN_NUM] == 1) && (iData[SOUND_BYTERATE] == 22050) ); + } + } + return false; +} + +//Main Stocks + +/** + * Checks file extension + * + * @param szFilename[] Path to file + * @return SFormat:SFILE_MP3, SFormat:SFILE_WAV or SFormat:SFILE_UNKNOWN + */ +stock SFormat:sfile_type(const szFilename[]){ + new iSize = strlen(szFilename) - 4; + if(iSize > 0){ + if(equali(szFilename[iSize], ".mp3")) + return SFILE_MP3; + if(equali(szFilename[iSize], ".wav")) + return SFILE_WAV; + } + return SFILE_UNKNOWN; +} + +/** + * Load information about sound in .mp3 or .wav file + * + * @param szFilename Path to file + * @param iData Container for result values + * + * Indexes of Array + * enum SParam{ + * SOUND_FREQ, + * SOUND_BYTERATE, + * SOUND_CHAN_NUM, + * SOUND_DURATION + * } + * @return SRES_OK on success, 0 or less on failure + */ +stock sfile_loaddata(const szFilename[], iData[SParam]){ + switch(sfile_type(szFilename)){ + case SFILE_MP3: return sfile_loaddata_mp3(szFilename, iData); + case SFILE_WAV:return sfile_loaddata_wav(szFilename, iData); + } + return SRES_NOT_EXISTS; +} + +/** + * Load information about sound in .mp3 file + * + * @param szFilename Path to file + * @param iData Container for result values + * + * Indexes of Array + * enum SParam{ + * SOUND_FREQ, + * SOUND_BYTERATE, + * SOUND_CHAN_NUM, + * SOUND_DURATION + * } + * @return SRES_OK on success, 0 or less on failure + */ +stock sfile_loaddata_mp3(const szFilename[], iData[SParam]){ + new iOffsets[2]; + sfile_lenght_offset_mp3(szFilename, iOffsets); + + new fp = fopen(szFilename,"rb"); + if(!fp) return SRES_NOT_EXISTS; + + fseek(fp, iOffsets[0], SEEK_CUR); + + new Header; + fread(fp, Header, BLOCK_INT); + new Version = (Header & 0x00180000); + + new Layer = Header & 0x00060000; + new BitRateIndex = (Header & 0xF000)>>12; + new FreqIndex = (Header & 0x0C00)>>10; + new ChannelIndex = (Header & 0xC0)>>6; + + new BitRateCol, FreqCol = 0; + + + switch(Version){ + case MPEG_V1:{ + FreqCol = 0; + switch(Layer){ + case MPEG_LAYER_1: BitRateCol = 0; + case MPEG_LAYER_2: BitRateCol = 1; + case MPEG_LAYER_3: BitRateCol = 2; + } + } + case MPEG_V2, MPEG_V2_5:{ + FreqCol = (Version == MPEG_V2)?1:2; + switch(Layer){ + case MPEG_LAYER_1:BitRateCol = 3; + case MPEG_LAYER_2, MPEG_LAYER_3: BitRateCol = 4; + default: return SRES_BAD_PARAMETERS; + } + } + } + new BitRate = _MP3_BitRates[BitRateIndex][BitRateCol]; + + if(BitRate == 0) return SRES_BAD_PARAMETERS; + + iData[SOUND_FREQ] = _MP3_Freq[FreqIndex][FreqCol]; + iData[SOUND_BYTERATE] = BitRate >> 3; + iData[SOUND_CHAN_NUM] = _MP3_Channels[ChannelIndex]; + iData[SOUND_DURATION_F] = _:((file_size(szFilename) - iOffsets[0] - iOffsets[1])/ float(iData[SOUND_BYTERATE])); + + fclose(fp); + return SRES_OK; +} +/** + * Load information about sound in .wav file + * + * @param szFilename Path to file + * @param iData Container for result values + * + * Indexes of Array + * enum SParam{ + * SOUND_FREQ, + * SOUND_BYTERATE, + * SOUND_CHAN_NUM, + * SOUND_DURATION + * } + * @return SRES_OK on success, 0 or less on failure + */ +stock sfile_loaddata_wav(const szFilename[], iData[SParam]){ + new iOffsets[2]; + sfile_lenght_offset_wav(iOffsets); + + new fp = fopen(szFilename,"rb"); + if(!fp) return SRES_NOT_EXISTS; + + static const VALID_CHUNKID = 0x46464952; + new const VALID_FORMAT = 0x45564157; + new const VALID_SUBCHUNK = 0x20746d66; + + new ChunkID, ChunkSize; + new Format, Subchunk1ID; + + fread(fp,ChunkID,BLOCK_INT); + if(ChunkID != VALID_CHUNKID) return SRES_BAD_SIGNATURE; + + fread(fp,ChunkSize,BLOCK_INT); + fread(fp,Format,BLOCK_INT); + if(Format != VALID_FORMAT) return SRES_BAD_SIGNATURE; + + fread(fp,Subchunk1ID,BLOCK_INT); + if(Subchunk1ID != VALID_SUBCHUNK) return SRES_BAD_SIGNATURE; + + + fseek(fp, 6 , SEEK_CUR); + + fread(fp, iData[SOUND_CHAN_NUM],BLOCK_SHORT); + fread(fp, iData[SOUND_FREQ],BLOCK_INT); + + fread(fp,iData[SOUND_BYTERATE],BLOCK_INT); + + fclose(fp); + + iData[SOUND_DURATION_F] = _:((file_size(szFilename) - iOffsets[0])/float(iData[SOUND_BYTERATE])); + + return SRES_OK; +} +/** + * Count offset from begin and and of file for non-music data (Wav header) + * + * @param szFilename Path to file + * @param iOffset Container for result values, iOffsets[] = {front, back} + */ +stock sfile_lenght_offset_wav(iOffsets[2]){ + iOffsets[0] = 44; //Front + iOffsets[1] = 0; //End +} + +/** + * Count offset from begin and and of file for non-music data (ID3 Tags) + * + * @param szFilename Path to file + * @param iOffset Container for return values, iOffsets[] = {front, back} + */ +stock sfile_lenght_offset_mp3(const szFilename[], iOffsets[2]){ + new fp = fopen(szFilename,"rb"); + if(!fp) return SRES_NOT_EXISTS; + + new szTemp[5]; + fread_blocks(fp, szTemp, 3, BLOCK_CHAR); + + //ID3v2 + if(equal(szTemp, "ID3")){ + fseek(fp, 3, SEEK_CUR); + new iSize; + fread(fp, iSize, BLOCK_INT); + iSize = swapchars(iSize); + iOffsets[0] = in_8bits(iSize)+10;//Front + } + + //ID3v1 + fseek(fp, -128, SEEK_END); + fread_blocks(fp, szTemp, 3, BLOCK_CHAR); + if(equal(szTemp, "TAG")){ + iOffsets[1] = 128;//End + + //ID3v1 Extended + fseek(fp, -227, SEEK_CUR); + fread_blocks(fp, szTemp, 4, BLOCK_CHAR); + if(equal(szTemp, "TAG+")) + iOffsets[1] += 227; + } + + fclose(fp); + return SRES_OK; +} + +//Inner Stocks + +/** + * Convert seven bits integer format to normal eight bits + * Mp3 use this format to avoid mismatch with header + * 0x0201 = 0000 0010 0000 0001 + * Most significant bit of every byte go out + * (0)000 0010 (0)000 0001 - decimal value = 0000 0001 0000 0001 = 257 + * + * + * @param in_7bits Number in seven bits format + * @return decimal value of argument + */ +stock in_8bits(in_7bits){ + static const iMask = 0xEF; + new iRes = 0; + new j; + for(new i=0;i<4;i++){ + j = i<<3; + iRes |= (in_7bits & (iMask<>(i); + } + return iRes; +} +/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE +*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1045\\ f0\\ fs16 \n\\ par } +*/ diff --git a/sound/csgor_mvp/heroes_tonight.wav b/sound/csgor_mvp/heroes_tonight.wav new file mode 100644 index 0000000..6ce3a36 Binary files /dev/null and b/sound/csgor_mvp/heroes_tonight.wav differ diff --git a/sound/csgor_mvp/invincible.wav b/sound/csgor_mvp/invincible.wav new file mode 100644 index 0000000..c398ae8 Binary files /dev/null and b/sound/csgor_mvp/invincible.wav differ diff --git a/sound/csgor_mvp/on_and_on.wav b/sound/csgor_mvp/on_and_on.wav new file mode 100644 index 0000000..2f57aad Binary files /dev/null and b/sound/csgor_mvp/on_and_on.wav differ