diff --git a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt index 1248c94..1289a0e 100644 --- a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt +++ b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt @@ -13,7 +13,7 @@ "EyeAngles" { "windows" "206" - "osx" "207" + "linux" "207" } } diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 9b2c96a..82a4bfb 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -24,6 +24,7 @@ #include "zr/zombiereloaded" #include "zr/log" #include "zr/cvars" +#include "zr/config" #include "zr/translation" #include "zr/tools" #include "zr/models" @@ -166,9 +167,6 @@ public OnLibraryAdded(const String:name[]) */ public OnMapStart() { - LoadModelData(); - LoadDownloadData(); - // Forward event to modules. RoundEndOnMapStart(); InfectOnMapStart(); @@ -191,26 +189,9 @@ public OnMapEnd() */ public OnConfigsExecuted() { - // TODO: move to config module when made. - decl String:mapconfig[PLATFORM_MAX_PATH]; - - GetCurrentMap(mapconfig, sizeof(mapconfig)); - Format(mapconfig, sizeof(mapconfig), "sourcemod/zombiereloaded/%s.cfg", mapconfig); - - decl String:path[PLATFORM_MAX_PATH]; - Format(path, sizeof(path), "cfg/%s", mapconfig); - - if (FileExists(path)) - { - ServerCommand("exec %s", mapconfig); - - if (LogCheckFlag(LOG_CORE_EVENTS)) - { - LogMessageFormatted(-1, "", "", "Executed map config file: %s.", LOG_FORMAT_TYPE_SIMPLE, mapconfig); - } - } - // Forward event to modules. + ConfigLoad(); + ModelsLoad(); WeaponsLoad(); HitgroupsLoad(); InfectLoad(); diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index 6cd6119..19d3589 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -24,6 +24,12 @@ enum CvarsList { Handle:CVAR_ENABLE, + Handle:CVAR_CONFIG_PATH_MODELS, + Handle:CVAR_CONFIG_PATH_DOWNLOADS, + Handle:CVAR_CONFIG_PATH_PLAYERCLASSES, + Handle:CVAR_CONFIG_PATH_WEAPONS, + Handle:CVAR_CONFIG_PATH_WEAPONGROUPS, + Handle:CVAR_CONFIG_PATH_HITGROUPS, Handle:CVAR_CLASSES_SPAWN, Handle:CVAR_CLASSES_RANDOM, Handle:CVAR_CLASSES_DEFAULT_ZOMBIE, @@ -40,6 +46,8 @@ enum CvarsList Handle:CVAR_DAMAGE_SUICIDE_ZOMBIE, Handle:CVAR_DAMAGE_SUICIDE_HUMAN, Handle:CVAR_DAMAGE_SUICIDE_CMDS, + Handle:CVAR_SAYHOOKS_QUIET, + Handle:CVAR_SAYHOOKS_QUIET_FLAGS, Handle:CVAR_ROUNDEND_OVERLAY, Handle:CVAR_ROUNDEND_OVERLAY_ZOMBIE, Handle:CVAR_ROUNDEND_OVERLAY_HUMAN, @@ -177,6 +185,17 @@ CvarsCreate() // (None) + // =========================== + // Config (core) + // =========================== + + g_hCvarsList[CVAR_CONFIG_PATH_MODELS] = CreateConVar("zr_config_path_models", "configs/zr/models.txt", ""); + g_hCvarsList[CVAR_CONFIG_PATH_DOWNLOADS] = CreateConVar("zr_config_path_downloads", "configs/zr/downloads.txt"); + g_hCvarsList[CVAR_CONFIG_PATH_PLAYERCLASSES] = CreateConVar("zr_config_path_playerclasses", "configs/zr/playerclasses.txt"); + g_hCvarsList[CVAR_CONFIG_PATH_WEAPONS] = CreateConVar("zr_config_path_weapons", "configs/zr/weapons/weapons.txt"); + g_hCvarsList[CVAR_CONFIG_PATH_WEAPONGROUPS] = CreateConVar("zr_config_path_weapongroups", "configs/zr/weapons/weapongroups.txt"); + g_hCvarsList[CVAR_CONFIG_PATH_HITGROUPS] = CreateConVar("zr_config_path_hitgroups", "configs/zr/hitgroups.txt"); + // =========================== // Tools (core) // =========================== @@ -290,6 +309,22 @@ CvarsCreate() g_hCvarsList[CVAR_DAMAGE_SUICIDE_CMDS] = CreateConVar("zr_damage_suicide_cmds", "kill, spectate, jointeam", ""); // Old Desc: List of suicide commands to intercept. (Delimited by \", \" + // =========================== + // Say Hooks (core) + // =========================== + + g_hCvarsList[CVAR_SAYHOOKS_QUIET] = CreateConVar("zr_sayhooks_quiet", "1", ""); + g_hCvarsList[CVAR_SAYHOOKS_QUIET_FLAGS] = CreateConVar("zr_sayhooks_quiet_flags", "58", ""); + // Flags (default: 2 + 8 + 16 + 32) + // 0 Allow all. + // 1 Quiet "!zmenu" say hook. + // 2 Quiet "!zadmin" say hook. + // 4 Quiet "!zclass" say hook. + // 8 Quiet "!zspawn" say hook. + // 16 Quiet "!ztele" say hook. + // 32 Quiet "!zhp" say hook. + // 64 Quiet "!zmarket" say hook. + // =========================== // Account (module) // =========================== @@ -465,7 +500,7 @@ CvarsHook(bool:unhook = false) // Hook cvar to prevent it from changing. HookConVarChange(g_hAutoTeamBalance, CvarsHookLocked); - //HookConVarChange(hLimitTeams, CvarsHookLocked); + HookConVarChange(g_hLimitTeams, CvarsHookLocked); HookConVarChange(g_hRestartGame, CvarsHookRestartGame); // Anticamp shtuff. (needs to be moved to anticamp if these hooks are necessary) @@ -486,6 +521,12 @@ public CvarsHookLocked(Handle:cvar, const String:oldvalue[], const String:newval // If cvar is mp_autoteambalance, then continue. if (cvar == g_hAutoTeamBalance) { + // If plugin is reverting value, then stop. + if (StringToInt(newvalue) == CVARS_AUTOTEAMBALANCE_LOCKED) + { + return; + } + // Revert to locked value. SetConVarInt(g_hAutoTeamBalance, CVARS_AUTOTEAMBALANCE_LOCKED); @@ -498,6 +539,12 @@ public CvarsHookLocked(Handle:cvar, const String:oldvalue[], const String:newval // If cvar is mp_limitteams, then continue. else if (cvar == g_hLimitTeams) { + // If plugin is reverting value, then stop. + if (StringToInt(newvalue) == CVARS_LIMITTEAMS_LOCKED) + { + return; + } + // Revert to locked value. SetConVarInt(g_hLimitTeams, CVARS_LIMITTEAMS_LOCKED); diff --git a/src/zr/event.inc b/src/zr/event.inc index c96b359..7fbc79d 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -174,6 +174,7 @@ public Action:EventPlayerSpawn(Handle:event, const String:name[], bool:dontBroad // Forward event to modules. InfectOnClientSpawn(index); ClassOnClientSpawn(index); // Module event depends on infect module. + RestrictOnClientSpawn(index); SEffectsOnClientSpawn(index); AccountOnClientSpawn(index); SpawnProtectOnClientSpawn(index); diff --git a/src/zr/hitgroups.inc b/src/zr/hitgroups.inc index 8432772..18ae3d4 100644 --- a/src/zr/hitgroups.inc +++ b/src/zr/hitgroups.inc @@ -17,10 +17,10 @@ new Handle:kvHitgroups = INVALID_HANDLE; /** * @section Player hitgroup values. */ -#define HITGROUP_GENERIC 0 -#define HITGROUP_HEAD 1 -#define HITGROUP_CHEST 2 -#define HITGROUP_STOMACH 3 +#define HITGROUP_GENERIC 0 +#define HITGROUP_HEAD 1 +#define HITGROUP_CHEST 2 +#define HITGROUP_STOMACH 3 #define HITGROUP_LEFTARM 4 #define HITGROUP_RIGHTARM 5 #define HITGROUP_LEFTLEG 6 @@ -59,20 +59,25 @@ HitgroupsLoad() return; } - decl String:path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "configs/zr/hitgroups.txt"); + // Get hitgroups config path. + decl String:pathhitgroups[PLATFORM_MAX_PATH]; + new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_HITGROUPS, pathhitgroups); - // If file isn't found, stop plugin. - if (!FileToKeyValues(kvHitgroups, path)) + // If file doesn't exist, then log and stop. + if (!exists) { + // Log failure. if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_HITGROUPS)) { - LogMessageFormatted(-1, "Hitgroups", "Config Validation", "Missing file hitgroups.txt, disabling hitgroup-based modules.", LOG_FORMAT_TYPE_FULL); + LogMessageFormatted(-1, "Hitgroups", "Config Validation", "Missing hitgroups config file: %s", LOG_FORMAT_TYPE_ERROR, pathhitgroups); } return; } + // Put file data into memory. + FileToKeyValues(kvHitgroups, pathhitgroups); + // Validate hitgroups config. HitgroupsValidateConfig(); } diff --git a/src/zr/menu.inc b/src/zr/menu.inc index 00c9f92..b2ac16f 100644 --- a/src/zr/menu.inc +++ b/src/zr/menu.inc @@ -82,6 +82,7 @@ public MenuMainHandle(Handle:menu, MenuAction:action, client, slot) // Copy return to resend variable. resend = !ZRAdminMenu(client); } + // Select zclass. case 1: { // Send class menu @@ -90,26 +91,30 @@ public MenuMainHandle(Handle:menu, MenuAction:action, client, slot) // Don't resend this menu. resend = false; } + // Select zspawn. case 2: - { - // Copy return to resend variable. - resend = !ZMarketSend(client); - } - case 3: { // Send zspawn command from client. ZSpawnClient(client); } - case 4: + // Select ztele. + case 3: { // Copy return to resend variable. resend = !ZTele(client); } - case 5: + // Select zhp. + case 4: { // Toggle ZHP. ZHPToggle(client); } + // Select zmarket. + case 5: + { + // Copy return to resend variable. + resend = !ZMarketMenu(client); + } } // Resend is still true, then resend menu. diff --git a/src/zr/models.inc b/src/zr/models.inc index 5d06222..268f76d 100644 --- a/src/zr/models.inc +++ b/src/zr/models.inc @@ -1,117 +1,250 @@ -/** - * ==================== +/* + * ============================================================================ + * * Zombie:Reloaded - * File: models.inc - * Author: Greyscale - * ==================== + * + * File: models.inc + * Description: Model validation and API + * + * ============================================================================ */ -new String:modelSuffix[8][16] = {".dx80.vtx", ".dx90.vtx", ".mdl", ".phy", ".sw.vtx", ".vvd", ".xbox", ".xbox.vtx"}; +/** + * Maximum folder depth a model file can be located. + */ +#define MODELS_PATH_MAX_DEPTH 8 -new Handle:arrayModels = INVALID_HANDLE; +/** + * Maximum string length of a folder a model file is located under. + */ +#define MODELS_PATH_DIR_MAX_LENGTH 32 -FileLinesToArray(Handle:array, const Handle:file) +/** + * Array that stores a list of validated models. + */ +new Handle:arrayModelsList = INVALID_HANDLE; + +ModelsLoad() { - ClearArray(array); + // Add models to downloads table and validate. + ModelsPrepModels(); - decl String:line[128]; + // Add download entries to downloads table and validate. + ModelsPrepDownloads(); +} + +/** + * Validate model paths and add to downloads table. + */ +ModelsPrepModels() +{ + // Get models file path. + decl String:pathmodels[PLATFORM_MAX_PATH]; + new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_MODELS, pathmodels); - while(!IsEndOfFile(file) && ReadFileLine(file, line, sizeof(line))) + // If file doesn't exist, then log and stop. + if (!exists) { - if (StrContains(line, ";") == -1) + // Log failure and stop plugin. + if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) { - if (StrContains(line, "//") > -1) + LogMessageFormatted(-1, "Models", "Config Validation", "Missing models file: %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels); + } + } + + // If model array exists, then destroy it. + if (arrayModelsList != INVALID_HANDLE) + { + CloseHandle(arrayModelsList); + } + + arrayModelsList = ConfigLinesToArray(pathmodels); + + // If array couldn't be created, then fail. + if (arrayModelsList == INVALID_HANDLE) + { + LogMessageFormatted(-1, "Models", "Config Validation", "Error parsing %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels); + } + + new modelcount; + new modelvalidcount; + new modelfilecount; + + decl String:modelbase[PLATFORM_MAX_PATH]; + decl String:modelpath[PLATFORM_MAX_PATH]; + decl String:modelname[MODELS_PATH_DIR_MAX_LENGTH]; + decl String:modelfile[MODELS_PATH_DIR_MAX_LENGTH]; + decl String:modeldiskname[MODELS_PATH_DIR_MAX_LENGTH]; + decl String:modelfullpath[PLATFORM_MAX_PATH]; + + new String:baseexploded[MODELS_PATH_MAX_DEPTH][MODELS_PATH_DIR_MAX_LENGTH]; + + new FileType:type; + + new models = modelcount = GetArraySize(arrayModelsList); + + // x = model array index. + for (new x = 0; x < models; x++) + { + // Get base model path (rawline in models.txt) + GetArrayString(arrayModelsList, x, modelbase, sizeof(modelbase)); + + // Explode path into pieces. (separated by "/") + new strings = ExplodeString(modelbase, "/", baseexploded, MODELS_PATH_MAX_DEPTH, MODELS_PATH_DIR_MAX_LENGTH); + + // Get model file name. + strcopy(modelname, sizeof(modelname), baseexploded[strings - 1]); + + // Get the path to the file. + // Works by truncating original path by the length of the file name. + strcopy(modelpath, strlen(modelbase) - strlen(modelname), modelbase); + + // Open dir containing model files. + new Handle:modeldir = OpenDirectory(modelpath); + + // Reset model file count. + modelfilecount = 0; + + while (ReadDirEntry(modeldir, modelfile, sizeof(modelfile), type)) + { + // If entry isn't a file, then stop. + if (type != FileType_File) { - SplitString(line, "//", line, sizeof(line)); + continue; } - TrimString(line); - if (!StrEqual(line, "", false)) + // Find break point index in the string to get model name. + // Add one because it seems to break on the character before. + new breakpoint = FindCharInString(modelfile, '.') + 1; + strcopy(modeldiskname, breakpoint, modelfile); + + // If this file doesn't match, then stop. + if (!StrEqual(modelname, modeldiskname, false)) { - PushArrayString(array, line); + continue; } + + // Format a full path string. + strcopy(modelfullpath, sizeof(modelfullpath), modelpath); + Format(modelfullpath, sizeof(modelfullpath), "%s/%s", modelfullpath, modelfile); + + // Precache model file and add to downloads table. + PrecacheModel(modelfullpath); + AddFileToDownloadsTable(modelfullpath); + + // Increment modelfilecount + modelfilecount++; } - } -} - -LoadModelData() -{ - decl String:path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "configs/zr/models.txt"); - - if (arrayModels != INVALID_HANDLE) - { - CloseHandle(arrayModels); - } - - arrayModels = CreateArray(256, 0); - - new Handle:fileModels = OpenFile(path, "r"); - if (fileModels == INVALID_HANDLE) - { - SetFailState("\"%s\" missing from server", path); - } - - FileLinesToArray(arrayModels, fileModels); - - if (!GetArraySize(arrayModels)) - { - SetFailState("No models listed in models.txt, please add some models then restart"); - } - - decl String:model[256]; - decl String:modelpath[256]; - - new modelsize = GetArraySize(arrayModels); - for (new x = 0; x < modelsize; x++) - { - for (new y = 0; y < 8; y++) + + // Increment modelvalidcount if model files are valid. + if (modelfilecount) { - GetArrayString(arrayModels, x, model, sizeof(model)); - Format(modelpath, sizeof(modelpath), "%s%s", model, modelSuffix[y]); - if (FileExists(modelpath)) - { - PrecacheModel(modelpath); - AddFileToDownloadsTable(modelpath); - } - } - } - - CloseHandle(fileModels); -} - -LoadDownloadData() -{ - decl String:path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "configs/zr/downloads.txt"); - - new Handle:fileDownloads = OpenFile(path, "r"); - - if (fileDownloads == INVALID_HANDLE) - { - SetFailState("\"%s\" missing from server", path); - } - - new Handle:arrayDownloads = CreateArray(256, 0); - - FileLinesToArray(arrayDownloads, fileDownloads); - - decl String:file[256]; - - new downloadsize = GetArraySize(arrayDownloads); - for (new x = 0; x < downloadsize; x++) - { - GetArrayString(arrayDownloads, x, file, sizeof(file)); - if (FileExists(file)) - { - AddFileToDownloadsTable(file); + modelvalidcount++; } else { - ZR_LogMessage("File load failed", file); + // Remove client from array. + RemoveFromArray(arrayModelsList, x); + + // Subtract one from count. + models--; + + // Backtrack one index, because we deleted it out from under the loop. + x--; + + // Log missing model files. + if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + { + LogMessageFormatted(-1, "Models", "Config Validation", "Missing model files on server (%s)", LOG_FORMAT_TYPE_ERROR, modelbase); + } + } + } + + // Log model validation info. + LogMessageFormatted(-1, "Models", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", LOG_FORMAT_TYPE_FULL, modelcount, modelvalidcount, modelcount - modelvalidcount); + + // If none of the model paths are valid, then log and fail. + if (!modelvalidcount) + { + if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + { + LogMessageFormatted(-1, "Models", "Config Validation", "No usable model paths in %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels); } } - - CloseHandle(fileDownloads); - CloseHandle(arrayDownloads); } + +/** + * Validate custom download paths and add to downloads table. + */ +ModelsPrepDownloads() +{ + // Get downloads file path. + decl String:pathdownloads[PLATFORM_MAX_PATH]; + new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_DOWNLOADS, pathdownloads); + + // If file doesn't exist, then log. + if (!exists) + { + // Log error, then stop. + if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + { + LogMessageFormatted(-1, "Downloads", "Config Validation", "Missing downloads file: %s", LOG_FORMAT_TYPE_ERROR, pathdownloads); + } + + return; + } + + new Handle:arrayDownloadsList = ConfigLinesToArray(pathdownloads); + + // If array couldn't be created, then fail. + if (arrayModelsList == INVALID_HANDLE) + { + if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + { + LogMessageFormatted(-1, "Downloads", "Config Validation", "Error parsing %s", LOG_FORMAT_TYPE_ERROR, pathdownloads); + } + } + + new downloadcount; + new downloadvalidcount; + + decl String:downloadpath[PLATFORM_MAX_PATH]; + + new downloads = downloadcount = GetArraySize(arrayDownloadsList); + + // x = download array index. + for (new x = 0; x < downloads; x++) + { + // Get base model path (rawline in models.txt) + GetArrayString(arrayDownloadsList, x, downloadpath, sizeof(downloadpath)); + + // If file doesn't exist, then remove, log, and stop. + if (!FileExists(downloadpath)) + { + // Remove client from array. + RemoveFromArray(arrayDownloadsList, x); + + // Subtract one from count. + downloads--; + + // Backtrack one index, because we deleted it out from under the loop. + x--; + + if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + { + LogMessageFormatted(-1, "Downloads", "Config Validation", "Missing file (%s)", LOG_FORMAT_TYPE_ERROR, downloadpath); + } + + continue; + } + + // Increment downloadvalidcount + downloadvalidcount++; + + // Precache model file and add to downloads table. + AddFileToDownloadsTable(downloadpath); + } + + // Log model validation info. + LogMessageFormatted(-1, "Downloads", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", LOG_FORMAT_TYPE_FULL, downloadcount, downloadvalidcount, downloadcount - downloadvalidcount); +} \ No newline at end of file diff --git a/src/zr/playerclasses/apply.inc b/src/zr/playerclasses/apply.inc index 044b570..dede0e4 100644 --- a/src/zr/playerclasses/apply.inc +++ b/src/zr/playerclasses/apply.inc @@ -70,8 +70,8 @@ bool:ClassApplyModel(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER) if (strcmp(modelpath, "random", false) == 0) { // TODO: Make a function that gets a random model from the specified team. - new randmodel = GetRandomInt(0, GetArraySize(arrayModels) - 1); - GetArrayString(arrayModels, randmodel, modelpath, sizeof(modelpath)); + new randmodel = GetRandomInt(0, GetArraySize(arrayModelsList) - 1); + GetArrayString(arrayModelsList, randmodel, modelpath, sizeof(modelpath)); Format(modelpath, sizeof(modelpath), "%s.mdl", modelpath); } diff --git a/src/zr/playerclasses/classmenus.inc b/src/zr/playerclasses/classmenus.inc index 323c173..da58b56 100644 --- a/src/zr/playerclasses/classmenus.inc +++ b/src/zr/playerclasses/classmenus.inc @@ -261,6 +261,9 @@ public ClassMenuSelectHandle(Handle:menu, MenuAction:action, client, slot) { ClassMenuMain(client); } + + // Stop so menu doesn't reopen. + return; } case MenuAction_End: { diff --git a/src/zr/roundend.inc b/src/zr/roundend.inc index e5b30d6..a1233f4 100644 --- a/src/zr/roundend.inc +++ b/src/zr/roundend.inc @@ -251,6 +251,12 @@ RoundEndOutcome:RoundEndReasonToOutcome(reason) */ public Action:RoundEndTimer(Handle:timer) { + // If there aren't clients on both teams, then stop. + if (ZRTeamHasClients()) + { + return; + } + // Terminate the round with humans as the winner. RoundEndTerminateRound(ROUNDEND_DELAY, HumansWin); } diff --git a/src/zr/sayhooks.inc b/src/zr/sayhooks.inc index ccf377b..280d8ae 100644 --- a/src/zr/sayhooks.inc +++ b/src/zr/sayhooks.inc @@ -28,6 +28,20 @@ * @endsection */ +/** + * @section Say hook quiet flags. + */ +#define SAYHOOKS_KEYWORD_FLAG_ZMENU 1 +#define SAYHOOKS_KEYWORD_FLAG_ZADMIN 2 +#define SAYHOOKS_KEYWORD_FLAG_ZCLASS 4 +#define SAYHOOKS_KEYWORD_FLAG_ZSPAWN 8 +#define SAYHOOKS_KEYWORD_FLAG_ZTELE 16 +#define SAYHOOKS_KEYWORD_FLAG_ZHP 32 +#define SAYHOOKS_KEYWORD_FLAG_ZMARKET 64 +/** + * @endsection + */ + /** * Say hooks module init function. */ @@ -55,50 +69,114 @@ public Action:SayHooksCmdSay(client, argc) // Strip away the quotes. ReplaceString(args, sizeof(args), "\"", ""); - // If client triggered the zmenu keyword, then send menu. - if (StrEqual(args, SAYHOOKS_KEYWORD_ZMENU, false)) + new chatflag = SayHooksChatToFlag(args); + + // If chatflag is invalid, then continue. + if (!chatflag) { - MenuMain(client); + return Plugin_Continue; } - // If client triggered the zmenu keyword, then send menu. - else if (StrEqual(args, SAYHOOKS_KEYWORD_ZADMIN, false)) + switch(chatflag) { - ZRAdminMenu(client); + // Client triggered ZMenu flag. + case SAYHOOKS_KEYWORD_FLAG_ZMENU: + { + // Send main menu. + MenuMain(client); + } + // Client triggered ZAdmin flag. + case SAYHOOKS_KEYWORD_FLAG_ZADMIN: + { + ZRAdminMenu(client); + } + // Client triggered ZClass flag. + case SAYHOOKS_KEYWORD_FLAG_ZCLASS: + { + // Send class menu. + ClassMenuMain(client); + } + // Client triggered ZSpawn flag. + case SAYHOOKS_KEYWORD_FLAG_ZSPAWN: + { + // Spawns a late-joining client into the game. + ZSpawnClient(client); + } + // Client triggered ZTele flag. + case SAYHOOKS_KEYWORD_FLAG_ZTELE: + { + ZTele(client); + } + // Client triggered ZHP flag. + case SAYHOOKS_KEYWORD_FLAG_ZHP: + { + // Toggle ZHP. + ZHPToggle(client); + } + // Client triggered ZMarket flag. + case SAYHOOKS_KEYWORD_FLAG_ZMARKET: + { + // Send market menu. + ZMarketMenu(client); + } } - // If client triggered the zmenu keyword, then send menu. - else if (StrEqual(args, SAYHOOKS_KEYWORD_ZCLASS, false)) + // If quiet cvar is disabled, then continue. + new bool:quiet = GetConVarBool(g_hCvarsList[CVAR_SAYHOOKS_QUIET]); + if (!quiet) { - ClassMenuMain(client); + return Plugin_Continue; } - // If client triggered the zmenu keyword, then send menu. - else if (StrEqual(args, SAYHOOKS_KEYWORD_ZSPAWN, false)) + // If word is flagged to be quieted, then stop. + new quietflags = GetConVarInt(g_hCvarsList[CVAR_SAYHOOKS_QUIET_FLAGS]); + if (quietflags & chatflag) { - // Spawns a late-joining client into the game. - ZSpawnClient(client); - } - - // If client triggered the zmenu keyword, then send menu. - else if (StrEqual(args, SAYHOOKS_KEYWORD_ZTELE, false)) - { - ZTele(client); - } - - // If client triggered the zmenu keyword, then send menu. - else if (StrEqual(args, SAYHOOKS_KEYWORD_ZHP, false)) - { - // Toggle ZHP. - ZHPToggle(client); - } - - // If client triggered the zmenu keyword, then send menu. - else if (StrEqual(args, SAYHOOKS_KEYWORD_ZMARKET, false)) - { - // Send market menu. - ZMarketSend(client); + return Plugin_Handled; } return Plugin_Continue; +} + +/** + * Convert chat text into a defined flag. + * + * @param chat The chat text to convert. + * @return Returns flag for word given, returns 0 if matches none. + */ +SayHooksChatToFlag(const String:chat[]) +{ + // Return flag for chatstring. + + if (StrEqual(chat, SAYHOOKS_KEYWORD_ZMENU, false)) + { + return SAYHOOKS_KEYWORD_FLAG_ZMENU; + } + else if (StrEqual(chat, SAYHOOKS_KEYWORD_ZADMIN, false)) + { + return SAYHOOKS_KEYWORD_FLAG_ZADMIN; + } + else if (StrEqual(chat, SAYHOOKS_KEYWORD_ZCLASS, false)) + { + return SAYHOOKS_KEYWORD_FLAG_ZCLASS; + } + else if (StrEqual(chat, SAYHOOKS_KEYWORD_ZSPAWN, false)) + { + return SAYHOOKS_KEYWORD_FLAG_ZSPAWN; + } + else if (StrEqual(chat, SAYHOOKS_KEYWORD_ZTELE, false)) + { + return SAYHOOKS_KEYWORD_FLAG_ZTELE; + } + else if (StrEqual(chat, SAYHOOKS_KEYWORD_ZHP, false)) + { + return SAYHOOKS_KEYWORD_FLAG_ZHP; + } + else if (StrEqual(chat, SAYHOOKS_KEYWORD_ZMARKET, false)) + { + return SAYHOOKS_KEYWORD_FLAG_ZMARKET; + } + + // Return 0. + return 0; } \ No newline at end of file diff --git a/src/zr/weapons/markethandler.inc b/src/zr/weapons/markethandler.inc index 0c94e34..01919a1 100644 --- a/src/zr/weapons/markethandler.inc +++ b/src/zr/weapons/markethandler.inc @@ -19,7 +19,7 @@ new bool:g_bMarket; * * @param client The client index. */ -bool:ZMarketSend(client) +bool:ZMarketMenu(client) { // If market is disabled, then stop. if (!g_bMarket) @@ -151,5 +151,5 @@ public Market_PostOnWeaponSelected(client, &bool:allowed) } // Resend market menu. - ZMarketSend(client); + ZMarketMenu(client); } \ No newline at end of file diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index 456fee8..29753df 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -48,16 +48,7 @@ WeaponsMenuMain(client) AddMenuItem(menu_weapons_main, "toggleweaponrestriction", toggleweaponrestriction); AddMenuItem(menu_weapons_main, "togglewgrouprestriction", togglewgrouprestriction); - - // Disable market option if market isn't installed. - if (g_bMarket) - { - AddMenuItem(menu_weapons_main, "zmarket", zmarket); - } - else - { - AddMenuItem(menu_weapons_main, "zmarket", zmarket, ITEMDRAW_DISABLED); - } + AddMenuItem(menu_weapons_main, "zmarket", zmarket, MenuGetItemDraw(g_bMarket)); // Create a "Back" button to the weapons main menu. SetMenuExitBackButton(menu_weapons_main, true); diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index ef672a6..29c5c01 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -82,20 +82,26 @@ RestrictOnMapStart() // Restrict default restrictions. (set in weapons.txt) RestrictDefaultRestrictions(); - decl String:path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "configs/zr/weapons/weapongroups.txt"); + // Get weapon groups config path. + decl String:pathweapongroups[PLATFORM_MAX_PATH]; + new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_WEAPONGROUPS, pathweapongroups); - // If file isn't found, stop plugin. - if (!FileToKeyValues(kvWeaponGroups, path)) + // If file doesn't exist, then log and stop. + if (!exists) { + // Log failure. if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) { - LogMessageFormatted(-1, "Weapons", "Config Validation", "Missing file weapongroups.txt.", LOG_FORMAT_TYPE_ERROR); + LogMessageFormatted(-1, "Weapons", "Config Validation", "Missing weapon groups config file: %s", LOG_FORMAT_TYPE_ERROR, pathweapongroups); } return; } + // Put file data into memory. + FileToKeyValues(kvWeaponGroups, pathweapongroups); + + // Validate weapon groups config. RestrictValidateWeaponGroups(); } @@ -197,6 +203,7 @@ RestrictWeaponUnrestrictAll() */ RestrictClientInit(client) { + // Hook "canuse" on client. gCanUseHookID[client] = Hacks_Hook(client, HACKS_HTYPE_WEAPON_CANUSE, RestrictCanUse, false); } @@ -207,9 +214,22 @@ RestrictClientInit(client) */ RestrictOnClientDisconnect(client) { + // Unhook "canuse" on client. Hacks_Unhook(gCanUseHookID[client]); } +/** + * Client is spawning into the game. + * + * @param client The client index. + */ +RestrictOnClientSpawn(client) +{ + // Re-hook "canuse" on client. + Hacks_Unhook(gCanUseHookID[client]); + gCanUseHookID[client] = Hacks_Hook(client, HACKS_HTYPE_WEAPON_CANUSE, RestrictCanUse, false); +} + /** * Command callback function for the "buy" command * Used to block use of this command under certain conditions. diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index 759af5f..676da91 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -82,20 +82,25 @@ WeaponsLoad() return; } - decl String:path[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, path, sizeof(path), "configs/zr/weapons/weapons.txt"); + // Get weapons config path. + decl String:pathweapons[PLATFORM_MAX_PATH]; + new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_WEAPONS, pathweapons); - // If file isn't found, stop plugin. - if (!FileToKeyValues(kvWeapons, path)) + // If file doesn't exist, then log and stop. + if (!exists) { + // Log failure. if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) { - LogMessageFormatted(-1, "Weapons", "Config Validation", "Missing file weapons.txt.", LOG_FORMAT_TYPE_ERROR); + LogMessageFormatted(-1, "Weapons", "Config Validation", "Missing weapons config file: %s", LOG_FORMAT_TYPE_ERROR, pathweapons); } return; } + // Put file data into memory. + FileToKeyValues(kvWeapons, pathweapons); + // Validate weapons config. WeaponsValidateConfig();