Made config module, recoded models.inc and added validations, added a cvar to flag any sayhook as quiet to hide from chat, hooked mp_limitteams, fixed menu handle function, moved file paths into cvars and updated all modules but classes to use it
This commit is contained in:
		| @@ -13,7 +13,7 @@ | ||||
| 			"EyeAngles" | ||||
| 			{ | ||||
| 				"windows"	"206" | ||||
| 				"osx"		"207" | ||||
| 				"linux"		"207" | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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); | ||||
|          | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -1,117 +1,250 @@ | ||||
| /** | ||||
|  * ==================== | ||||
| /* | ||||
|  * ============================================================================ | ||||
|  * | ||||
|  *   Zombie:Reloaded | ||||
|  * | ||||
|  *   File:        models.inc | ||||
|  *   Author: Greyscale | ||||
|  * ====================  | ||||
|  *   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]; | ||||
|      | ||||
|     while(!IsEndOfFile(file) && ReadFileLine(file, line, sizeof(line))) | ||||
|     { | ||||
|         if (StrContains(line, ";") == -1) | ||||
|         { | ||||
|             if (StrContains(line, "//") > -1) | ||||
|             { | ||||
|                 SplitString(line, "//", line, sizeof(line)); | ||||
|             } | ||||
|             TrimString(line); | ||||
|              | ||||
|             if (!StrEqual(line, "", false)) | ||||
|             { | ||||
|                 PushArrayString(array, line); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     // Add download entries to downloads table and validate. | ||||
|     ModelsPrepDownloads(); | ||||
| } | ||||
|  | ||||
| LoadModelData() | ||||
| /** | ||||
|  * Validate model paths and add to downloads table. | ||||
|  */ | ||||
| ModelsPrepModels() | ||||
| { | ||||
|     decl String:path[PLATFORM_MAX_PATH]; | ||||
|     BuildPath(Path_SM, path, sizeof(path), "configs/zr/models.txt"); | ||||
|     // Get models file path. | ||||
|     decl String:pathmodels[PLATFORM_MAX_PATH]; | ||||
|     new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_MODELS, pathmodels); | ||||
|      | ||||
|     if (arrayModels != INVALID_HANDLE) | ||||
|     // If file doesn't exist, then log and stop. | ||||
|     if (!exists) | ||||
|     { | ||||
|         CloseHandle(arrayModels); | ||||
|     } | ||||
|      | ||||
|     arrayModels = CreateArray(256, 0); | ||||
|      | ||||
|     new Handle:fileModels = OpenFile(path, "r"); | ||||
|     if (fileModels == INVALID_HANDLE) | ||||
|         // Log failure and stop plugin. | ||||
|         if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) | ||||
|         { | ||||
|         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++) | ||||
|         { | ||||
|             GetArrayString(arrayModels, x, model, sizeof(model)); | ||||
|             Format(modelpath, sizeof(modelpath), "%s%s", model, modelSuffix[y]); | ||||
|             if (FileExists(modelpath)) | ||||
|             { | ||||
|                 PrecacheModel(modelpath); | ||||
|                 AddFileToDownloadsTable(modelpath); | ||||
|             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); | ||||
|     } | ||||
|      | ||||
|     CloseHandle(fileModels); | ||||
| } | ||||
|     arrayModelsList = ConfigLinesToArray(pathmodels); | ||||
|      | ||||
| 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) | ||||
|     // If array couldn't be created, then fail. | ||||
|     if (arrayModelsList == INVALID_HANDLE) | ||||
|     { | ||||
|         SetFailState("\"%s\" missing from server", path); | ||||
|         LogMessageFormatted(-1, "Models", "Config Validation", "Error parsing %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels); | ||||
|     } | ||||
|      | ||||
|     new Handle:arrayDownloads = CreateArray(256, 0); | ||||
|     new modelcount; | ||||
|     new modelvalidcount; | ||||
|     new modelfilecount; | ||||
|      | ||||
|     FileLinesToArray(arrayDownloads, fileDownloads); | ||||
|     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]; | ||||
|      | ||||
|     decl String:file[256]; | ||||
|     new String:baseexploded[MODELS_PATH_MAX_DEPTH][MODELS_PATH_DIR_MAX_LENGTH]; | ||||
|      | ||||
|     new downloadsize = GetArraySize(arrayDownloads); | ||||
|     for (new x = 0; x < downloadsize; x++) | ||||
|     new FileType:type; | ||||
|      | ||||
|     new models = modelcount = GetArraySize(arrayModelsList); | ||||
|      | ||||
|     // x = model array index. | ||||
|     for (new x = 0; x < models; x++) | ||||
|     { | ||||
|         GetArrayString(arrayDownloads, x, file, sizeof(file)); | ||||
|         if (FileExists(file)) | ||||
|         // 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)) | ||||
|         { | ||||
|             AddFileToDownloadsTable(file); | ||||
|             // If entry isn't a file, then stop. | ||||
|             if (type != FileType_File) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|              | ||||
|             // 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)) | ||||
|             { | ||||
|                 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++; | ||||
|         } | ||||
|          | ||||
|         // Increment modelvalidcount if model files are valid. | ||||
|         if (modelfilecount) | ||||
|         { | ||||
|             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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     CloseHandle(fileDownloads); | ||||
|     CloseHandle(arrayDownloads); | ||||
|     // 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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 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); | ||||
| } | ||||
| @@ -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); | ||||
|     } | ||||
|      | ||||
|   | ||||
| @@ -261,6 +261,9 @@ public ClassMenuSelectHandle(Handle:menu, MenuAction:action, client, slot) | ||||
|             { | ||||
|                 ClassMenuMain(client); | ||||
|             } | ||||
|              | ||||
|             // Stop so menu doesn't reopen. | ||||
|             return; | ||||
|         } | ||||
|         case MenuAction_End: | ||||
|         { | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|     { | ||||
|         // 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); | ||||
|         } | ||||
|      | ||||
|     // If client triggered the zmenu keyword, then send menu. | ||||
|     else if (StrEqual(args, SAYHOOKS_KEYWORD_ZCLASS, false)) | ||||
|         // Client triggered ZClass flag. | ||||
|         case SAYHOOKS_KEYWORD_FLAG_ZCLASS: | ||||
|         { | ||||
|             // Send class menu. | ||||
|             ClassMenuMain(client); | ||||
|         } | ||||
|      | ||||
|     // If client triggered the zmenu keyword, then send menu. | ||||
|     else if (StrEqual(args, SAYHOOKS_KEYWORD_ZSPAWN, false)) | ||||
|         // Client triggered ZSpawn flag. | ||||
|         case SAYHOOKS_KEYWORD_FLAG_ZSPAWN: | ||||
|         { | ||||
|             // 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)) | ||||
|         // Client triggered ZTele flag. | ||||
|         case SAYHOOKS_KEYWORD_FLAG_ZTELE: | ||||
|         { | ||||
|             ZTele(client); | ||||
|         } | ||||
|      | ||||
|     // If client triggered the zmenu keyword, then send menu. | ||||
|     else if (StrEqual(args, SAYHOOKS_KEYWORD_ZHP, false)) | ||||
|         // Client triggered ZHP flag. | ||||
|         case SAYHOOKS_KEYWORD_FLAG_ZHP: | ||||
|         { | ||||
|             // Toggle ZHP. | ||||
|             ZHPToggle(client); | ||||
|         } | ||||
|      | ||||
|     // If client triggered the zmenu keyword, then send menu. | ||||
|     else if (StrEqual(args, SAYHOOKS_KEYWORD_ZMARKET, false)) | ||||
|         // Client triggered ZMarket flag. | ||||
|         case SAYHOOKS_KEYWORD_FLAG_ZMARKET: | ||||
|         { | ||||
|             // Send market menu. | ||||
|         ZMarketSend(client); | ||||
|             ZMarketMenu(client); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // If quiet cvar is disabled, then continue. | ||||
|     new bool:quiet = GetConVarBool(g_hCvarsList[CVAR_SAYHOOKS_QUIET]); | ||||
|     if (!quiet) | ||||
|     { | ||||
|         return Plugin_Continue; | ||||
|     } | ||||
|      | ||||
|     // If word is flagged to be quieted, then stop. | ||||
|     new quietflags = GetConVarInt(g_hCvarsList[CVAR_SAYHOOKS_QUIET_FLAGS]); | ||||
|     if (quietflags & chatflag) | ||||
|     { | ||||
|         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; | ||||
| } | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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(); | ||||
|      | ||||
|   | ||||
		Reference in New Issue
	
	Block a user