From 969aa19b853001aeb78aeaab1f9d9a5afd91b4a1 Mon Sep 17 00:00:00 2001 From: richard Date: Sat, 9 May 2009 17:45:19 +0200 Subject: [PATCH 1/3] Added support for post map configs (with workaround for SourceMod bug 3803). Log cleanup. Minior fixes. Removed log check in fatal errors. Those must always log. Stored LogCheckFlag result in a boolean where log is executed more than once. Fixed invalid translation string used in menu title. Fixed index out of bounds in zspawn when a client disconnects. --- src/zombiereloaded.sp | 2 ++ src/zr/config.inc | 50 ++++++++++++++++++++++++++ src/zr/log.inc | 1 + src/zr/menu.inc | 2 +- src/zr/models.inc | 39 ++++++++++++-------- src/zr/playerclasses/filtertools.inc | 7 ++-- src/zr/playerclasses/playerclasses.inc | 34 ++++++++++++------ src/zr/soundeffects/ambientsounds.inc | 11 +++--- src/zr/zspawn.inc | 6 ++++ 9 files changed, 120 insertions(+), 32 deletions(-) diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index ceb36ac..12245b8 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -200,6 +200,8 @@ public OnConfigsExecuted() VEffectsLoad(); SEffectsLoad(); ClassLoad(); + + ConfigOnModulesLoaded(); } /** diff --git a/src/zr/config.inc b/src/zr/config.inc index d582631..bdc7c4b 100644 --- a/src/zr/config.inc +++ b/src/zr/config.inc @@ -41,6 +41,9 @@ */ #define CONFIG_OPTION_MAX_LENGTH 32 +/** + * Actions to use when working on key/values. + */ enum ConfigKeyvalueAction { Create, /** Create a key. */ @@ -48,6 +51,9 @@ enum ConfigKeyvalueAction Set, /** Modify setting of a key. */ Get, /** Get setting of a key. */ } +/** + * @endsection + */ /** * @section Global data handle initializations. @@ -57,6 +63,7 @@ new Handle:kvClassData = INVALID_HANDLE; new Handle:kvWeapons = INVALID_HANDLE; new Handle:kvWeaponGroups = INVALID_HANDLE; new Handle:kvHitgroups = INVALID_HANDLE; + /** * Load plugin configs. */ @@ -88,6 +95,48 @@ ConfigLoad() } } +/** + * Executed when modules are done loading. After all init calls in + * OnConfigsExecuted. + * + * Executes post map configs if they exist. + */ +ConfigOnModulesLoaded() +{ + decl String:mapname[256]; + decl String:mapconfig[PLATFORM_MAX_PATH]; + decl String:path[PLATFORM_MAX_PATH]; + new bool:cfgexists; + + // Get map name and format into config path. + GetCurrentMap(mapname, sizeof(mapname)); + Format(mapconfig, sizeof(mapconfig), "sourcemod/zombiereloaded/%s.post.cfg", mapname); + + // Prepend cfg to path. + Format(path, sizeof(path), "cfg/%s", mapconfig); + + // Workaround for bug 3083 in SourceMod compiler. Having FileExist directly + // in the if in this function makes it crash. Storing the result in a + // boolean first works. + + // Check if the file exist. + cfgexists = FileExists(path); + if (!cfgexists) + { + // File doesn't exist, then stop. + return; + } + + // Execute config file. + ServerCommand("exec %s", mapconfig); + + // Log action. + if (LogCheckFlag(LOG_CORE_EVENTS)) + { + LogMessageFormatted(-1, "", "", "Executed post map config file: %s.", LOG_FORMAT_TYPE_SIMPLE, mapconfig); + } +} + /** * Load config file. * @@ -106,6 +155,7 @@ bool:ConfigGetFilePath(CvarsList:cvar, String:path[]) return FileExists(path); } + /** * Creates, deletes, sets, or gets any key/setting of any ZR config keyvalue file in memory. * Only use when interacting with a command or manipulating single keys/values, diff --git a/src/zr/log.inc b/src/zr/log.inc index 5101de6..6544ae9 100644 --- a/src/zr/log.inc +++ b/src/zr/log.inc @@ -92,6 +92,7 @@ LogInit() * LOG_FORMAT_TYPE_SIMPLE - Simple, no module or block info. * LOG_FORMAT_TYPE_FULL - Full, with module and block info, printed in normal log. * LOG_FORMAT_TYPE_ERROR - Full, printed in error log. + * LOG_FORMAT_TYPE_FATALERROR - Full, stops the plugin. * @param any... Formatting parameters. */ LogMessageFormatted(client, const String:module[], const String:block[], const String:message[], type = LOG_FORMAT_TYPE_FULL, any:...) diff --git a/src/zr/menu.inc b/src/zr/menu.inc index 5c05bea..21b952d 100644 --- a/src/zr/menu.inc +++ b/src/zr/menu.inc @@ -24,7 +24,7 @@ MenuMain(client) SetGlobalTransTarget(client); // Set menu title. - SetMenuTitle(menu_main, "%t\n ", "!zmenu title"); + SetMenuTitle(menu_main, "%t\n ", "Menu main title"); // Initialize menu lines. decl String:zadmin[64]; diff --git a/src/zr/models.inc b/src/zr/models.inc index 7b2da1c..2de1e33 100644 --- a/src/zr/models.inc +++ b/src/zr/models.inc @@ -40,6 +40,9 @@ ModelsLoad() */ ModelsPrepModels() { + // Initialize log boolean. + new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE); + // Get models file path. decl String:pathmodels[PLATFORM_MAX_PATH]; new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_MODELS, pathmodels); @@ -48,10 +51,7 @@ ModelsPrepModels() if (!exists) { // Log failure and stop plugin. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) - { - LogMessageFormatted(-1, "Models", "Config Validation", "Missing models file: %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels); - } + LogMessageFormatted(-1, "Models", "Config Validation", "Fatal error: Missing models file: \"%s\"", LOG_FORMAT_TYPE_FATALERROR, pathmodels); } // If model array exists, then destroy it. @@ -65,7 +65,7 @@ ModelsPrepModels() // 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); + LogMessageFormatted(-1, "Models", "Config Validation", "Fatal error: Error parsing \"%s\"", LOG_FORMAT_TYPE_FATALERROR, pathmodels); } new modelcount; @@ -155,7 +155,7 @@ ModelsPrepModels() x--; // Log missing model files. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + if (enablelog) { LogMessageFormatted(-1, "Models", "Config Validation", "Missing model files on server (%s)", LOG_FORMAT_TYPE_ERROR, modelbase); } @@ -163,12 +163,15 @@ ModelsPrepModels() } // Log model validation info. - LogMessageFormatted(-1, "Models", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", LOG_FORMAT_TYPE_FULL, modelcount, modelvalidcount, modelcount - modelvalidcount); + if (enablelog) + { + 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)) + if (enablelog) { LogMessageFormatted(-1, "Models", "Config Validation", "No usable model paths in %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels); } @@ -180,6 +183,9 @@ ModelsPrepModels() */ ModelsPrepDownloads() { + // Initialize log boolean. + new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE); + // Get downloads file path. decl String:pathdownloads[PLATFORM_MAX_PATH]; new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_DOWNLOADS, pathdownloads); @@ -188,9 +194,9 @@ ModelsPrepDownloads() if (!exists) { // Log error, then stop. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + if (enablelog) { - LogMessageFormatted(-1, "Downloads", "Config Validation", "Missing downloads file: %s", LOG_FORMAT_TYPE_ERROR, pathdownloads); + LogMessageFormatted(-1, "Downloads", "Config Validation", "Missing downloads file: \"%s\"", LOG_FORMAT_TYPE_ERROR, pathdownloads); } return; @@ -201,9 +207,9 @@ ModelsPrepDownloads() // If array couldn't be created, then fail. if (arrayModelsList == INVALID_HANDLE) { - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + if (enablelog) { - LogMessageFormatted(-1, "Downloads", "Config Validation", "Error parsing %s", LOG_FORMAT_TYPE_ERROR, pathdownloads); + LogMessageFormatted(-1, "Downloads", "Config Validation", "Error parsing \"%s\"", LOG_FORMAT_TYPE_ERROR, pathdownloads); } } @@ -232,9 +238,9 @@ ModelsPrepDownloads() // Backtrack one index, because we deleted it out from under the loop. x--; - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) + if (enablelog) { - LogMessageFormatted(-1, "Downloads", "Config Validation", "Missing file (%s)", LOG_FORMAT_TYPE_ERROR, downloadpath); + LogMessageFormatted(-1, "Downloads", "Config Validation", "Missing file \"%s\"", LOG_FORMAT_TYPE_ERROR, downloadpath); } continue; @@ -248,5 +254,8 @@ ModelsPrepDownloads() } // Log model validation info. - LogMessageFormatted(-1, "Downloads", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", LOG_FORMAT_TYPE_FULL, downloadcount, downloadvalidcount, downloadcount - downloadvalidcount); + if (enablelog) + { + LogMessageFormatted(-1, "Downloads", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", LOG_FORMAT_TYPE_FULL, downloadcount, downloadvalidcount, downloadcount - downloadvalidcount); + } } diff --git a/src/zr/playerclasses/filtertools.inc b/src/zr/playerclasses/filtertools.inc index a84759f..d5230db 100644 --- a/src/zr/playerclasses/filtertools.inc +++ b/src/zr/playerclasses/filtertools.inc @@ -660,6 +660,9 @@ ClassGetDefaultSpawnClass(teamid, cachetype = ZR_CLASS_CACHE_MODIFIED) decl String:classname[64]; new classindex; + // Initialize log boolean. + new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CLASSES); + // Get the default class name from the correct CVAR depending on teamid. switch (teamid) { @@ -723,7 +726,7 @@ ClassGetDefaultSpawnClass(teamid, cachetype = ZR_CLASS_CACHE_MODIFIED) // in the specified team, and log a warning. classindex = ClassGetFirstClass(teamid, _, cachetype); - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CLASSES)) + if (enablelog) { LogMessageFormatted(-1, "Classes", "DefaultSpawnClass", "Warning: Failed to set \"%s\" as default spawn class for team %d. The class doesn't exist or the team IDs doesn't match. Falling back to the first class in the team.", _, classname, teamid); } @@ -732,7 +735,7 @@ ClassGetDefaultSpawnClass(teamid, cachetype = ZR_CLASS_CACHE_MODIFIED) if (ClassValidateIndex(classindex)) { // Log a warning. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CLASSES)) + if (enablelog) { LogMessageFormatted(-1, "Classes", "DefaultSpawnClass", "Warning: The default class name \"%s\" does not exist or matches the team ID.", _, classname); } diff --git a/src/zr/playerclasses/playerclasses.inc b/src/zr/playerclasses/playerclasses.inc index 02b6ee1..b6e8a28 100644 --- a/src/zr/playerclasses/playerclasses.inc +++ b/src/zr/playerclasses/playerclasses.inc @@ -300,6 +300,9 @@ new ClassPlayerNextAdminClass[MAXPLAYERS + 1]; */ ClassLoad() { + // Initialize log boolean. + new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS); + // Make sure kvClassData is ready to use. if (kvClassData != INVALID_HANDLE) { @@ -311,14 +314,16 @@ ClassLoad() decl String:pathclasses[PLATFORM_MAX_PATH]; new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_PLAYERCLASSES, pathclasses); + // Log what class file that is loaded. + if (enablelog) + { + LogMessageFormatted(-1, "Classes", "Load", "Loading classes from file \"%s\".", LOG_FORMAT_TYPE_SIMPLE, pathclasses); + } + // If file doesn't exist, then log and stop. if (!exists) { - // Log failure. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) - { - LogMessageFormatted(-1, "Classes", "Config Validation", "Missing playerclasses config file: %s", LOG_FORMAT_TYPE_FATALERROR, pathclasses); - } + LogMessageFormatted(-1, "Classes", "Load", "Fatal error: Missing playerclasses config file \"%s\"", LOG_FORMAT_TYPE_FATALERROR, pathclasses); return; } @@ -330,7 +335,7 @@ ClassLoad() KvRewind(kvClassData); if (!KvGotoFirstSubKey(kvClassData)) { - LogMessageFormatted(-1, "Classes", "Config Validation", "Can't find any classes in %s", LOG_FORMAT_TYPE_FATALERROR, pathclasses); + LogMessageFormatted(-1, "Classes", "Load", "Fatal error: Can't find any classes in \"%s\"", LOG_FORMAT_TYPE_FATALERROR, pathclasses); } decl String:name[64]; @@ -339,6 +344,7 @@ ClassLoad() decl String:overlay_path[PLATFORM_MAX_PATH]; ClassCount = 0; + new failedcount; new ClassErrorFlags; // Loop through all classes and store attributes in the ClassData array. @@ -347,7 +353,7 @@ ClassLoad() if (ClassCount > ZR_CLASS_MAX) { // Maximum classes reached. Write a warning and exit the loop. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CLASSES)) + if (enablelog) { LogMessageFormatted(-1, "Classes", "Load", "Warning: Maximum classes reached (%d). Skipping other classes.", _, ZR_CLASS_MAX + 1); } @@ -411,10 +417,12 @@ ClassLoad() // There's one or more invalid class attributes. Disable the class // and log an error message. ClassData[ClassCount][class_enabled] = false; - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CLASSES)) + if (enablelog) { LogMessageFormatted(-1, "Classes", "Config Validation", "Warning: Invalid class at index %d, disabled class. Class error flags: %d.", LOG_FORMAT_TYPE_ERROR, ClassCount, ClassErrorFlags); } + + failedcount++; } // Update the counter. @@ -424,17 +432,23 @@ ClassLoad() // Validate team requirements. if (!ClassValidateTeamRequirements()) { - LogMessageFormatted(-1, "Classes", "Config Validation", "The class configuration doesn't match the team requirements.", LOG_FORMAT_TYPE_FATALERROR); + LogMessageFormatted(-1, "Classes", "Config Validation", "Fatal error: The class configuration doesn't match the team requirements.", LOG_FORMAT_TYPE_FATALERROR); } // Validate team default requirements. if (!ClassValidateTeamDefaults()) { - LogMessageFormatted(-1, "Classes", "Config Validation", "Couldn't find a default class for one or more teams. At least one class per team must be marked as default.", LOG_FORMAT_TYPE_FATALERROR); + LogMessageFormatted(-1, "Classes", "Config Validation", "Fatal error: Couldn't find a default class for one or more teams. At least one class per team must be marked as default.", LOG_FORMAT_TYPE_FATALERROR); } // Cache class data. ClassReloadDataCache(); + + // Log summary. + if (enablelog) + { + LogMessageFormatted(-1, "Classes", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", _, ClassCount, ClassCount - failedcount, failedcount); + } } /** diff --git a/src/zr/soundeffects/ambientsounds.inc b/src/zr/soundeffects/ambientsounds.inc index e76b17b..2c201a1 100644 --- a/src/zr/soundeffects/ambientsounds.inc +++ b/src/zr/soundeffects/ambientsounds.inc @@ -57,6 +57,9 @@ bool:AmbientSoundsValidateConfig() return false; } + // Initialize log boolean. + new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_AMBIENTSOUNDS); + // Get ambient sound file. decl String:sound[SOUND_MAX_PATH]; GetConVarString(g_hCvarsList[CVAR_AMBIENTSOUNDS_FILE], sound, sizeof(sound)); @@ -66,7 +69,7 @@ bool:AmbientSoundsValidateConfig() if (!FileExists(sound, true)) { // Log invalid sound file error. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_AMBIENTSOUNDS)) + if (enablelog) { LogMessageFormatted(-1, "Ambient Sounds", "Config Validation", "Invalid sound file specified in zr_ambientsounds_file.", LOG_FORMAT_TYPE_ERROR); } @@ -79,7 +82,7 @@ bool:AmbientSoundsValidateConfig() if (ambientvolume <= 0.0) { // Log invalid ambient sound volume error. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_AMBIENTSOUNDS)) + if (enablelog) { LogMessageFormatted(-1, "Ambient Sounds", "Config Validation", "Ambient sound is either muted or invalid.", LOG_FORMAT_TYPE_ERROR); } @@ -92,9 +95,9 @@ bool:AmbientSoundsValidateConfig() if (ambientlength <= 0.0) { // Log invalid ambient sound length error. - if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_AMBIENTSOUNDS)) + if (enablelog) { - LogMessageFormatted(-1, "Ambient Sounds", "Config Validation", "Ambient sound length is invalid.", LOG_FORMAT_TYPE_ERROR); + LogMessageFormatted(-1, "Ambient Sounds", "Config Validation", "Specified ambient sound length is invalid.", LOG_FORMAT_TYPE_ERROR); } return false; diff --git a/src/zr/zspawn.inc b/src/zr/zspawn.inc index 904fc7a..5b336cb 100644 --- a/src/zr/zspawn.inc +++ b/src/zr/zspawn.inc @@ -36,6 +36,12 @@ ZSpawnOnMapStart() */ ZSpawnOnClientDisconnect(client) { + // Check if client is a bot. + if (!IsFakeClient(client)) + { + return; + } + // Get client's unique serial number. new serial = GetClientSerial(client); From e145e8cd0e88b221e32f77a37d3c7d71969ecf05 Mon Sep 17 00:00:00 2001 From: richard Date: Sun, 10 May 2009 01:32:53 +0200 Subject: [PATCH 2/3] Fixed logic mistake. --- src/zr/zspawn.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zr/zspawn.inc b/src/zr/zspawn.inc index 5b336cb..a3e2e46 100644 --- a/src/zr/zspawn.inc +++ b/src/zr/zspawn.inc @@ -37,7 +37,7 @@ ZSpawnOnMapStart() ZSpawnOnClientDisconnect(client) { // Check if client is a bot. - if (!IsFakeClient(client)) + if (IsFakeClient(client)) { return; } From 4117519b393a2086325f9b99e6ecf8e407c24e08 Mon Sep 17 00:00:00 2001 From: richard Date: Sun, 10 May 2009 18:49:47 +0200 Subject: [PATCH 3/3] Added command for modifying or scaling class attributes. Minior fixes, see details. Fixed error getting default classes on early player connect (bots, source tv, etc.). Fixed jump boost not resetting height velocity. Changed to add to velocity. Jump from boost platform still doesn't work because the velocity is set too early. Added check for reserved class names when validating. Updated class default attributes and jump limits. --- .../sourcemod/configs/zr/playerclasses.txt | 42 +- src/zombiereloaded.sp | 1 + src/zr/commands.inc | 56 +- src/zr/jumpboost.inc | 4 +- src/zr/playerclasses/attributes.inc | 174 ++++++ src/zr/playerclasses/classcommands.inc | 496 ++++++++++++++++++ src/zr/playerclasses/classevents.inc | 38 +- src/zr/playerclasses/filtertools.inc | 16 +- src/zr/playerclasses/playerclasses.inc | 87 +-- 9 files changed, 793 insertions(+), 121 deletions(-) diff --git a/cstrike/addons/sourcemod/configs/zr/playerclasses.txt b/cstrike/addons/sourcemod/configs/zr/playerclasses.txt index 6d50103..44144ea 100644 --- a/cstrike/addons/sourcemod/configs/zr/playerclasses.txt +++ b/cstrike/addons/sourcemod/configs/zr/playerclasses.txt @@ -36,8 +36,8 @@ // kill_bonus number How many points to give per kill. Humans only. // speed decimal The player speed. // knockback decimal Force of the knockback when shot at. Zombies only. -// jump_height decimal Extra upwards jump boost. -// jump_distance decimal Extra forwards jump boost. +// jump_height decimal Extra upwards jump boost in units. 0.0 for no extra boost. +// jump_distance decimal Extra forwards jump boost multiplier. 0.2 is normal distance. "classes" { @@ -75,16 +75,16 @@ "immunity_amount" "0.0" "no_fall_damage" "1" - "health" "3000" + "health" "2500" "health_regen_interval" "0.0" "health_regen_amount" "0" - "health_infect_gain" "800" + "health_infect_gain" "700" "kill_bonus" "2" "speed" "350" - "knockback" "3" - "jump_height" "40.0" - "jump_distance" "1.5" + "knockback" "4" + "jump_height" "10.0" + "jump_distance" "0.3" } "fast" @@ -123,9 +123,9 @@ "kill_bonus" "2" "speed" "380" - "knockback" "3.5" - "jump_height" "60.0" - "jump_distance" "2.0" + "knockback" "4.5" + "jump_height" "30.0" + "jump_distance" "0.4" } "mutated" @@ -157,16 +157,16 @@ "immunity_amount" "0.0" "no_fall_damage" "1" - "health" "5000" + "health" "3500" "health_regen_interval" "0.0" "health_regen_amount" "0" - "health_infect_gain" "1000" + "health_infect_gain" "850" "kill_bonus" "2" "speed" "275" "knockback" "3.5" - "jump_height" "40.0" - "jump_distance" "1.3" + "jump_height" "20.0" + "jump_distance" "0.4" } "heavy" @@ -198,16 +198,16 @@ "immunity_amount" "0.0" "no_fall_damage" "1" - "health" "5000" + "health" "4000" "health_regen_interval" "0.0" "health_regen_amount" "0" "health_infect_gain" "1000" "kill_bonus" "2" "speed" "280" - "knockback" "2.0" + "knockback" "2.5" "jump_height" "0.0" - "jump_distance" "0.8" + "jump_distance" "0.2" } // ------------------------------------------ @@ -254,7 +254,7 @@ "speed" "300" "knockback" "0" "jump_height" "0.0" - "jump_distance" "1.0" + "jump_distance" "0.2" } "human_speedy" @@ -295,7 +295,7 @@ "speed" "380" "knockback" "0" "jump_height" "0.0" - "jump_distance" "1.0" + "jump_distance" "0.2" } "human_light" @@ -335,7 +335,7 @@ "speed" "300" "knockback" "0" - "jump_height" "64.0" - "jump_distance" "2.0" + "jump_height" "30.0" + "jump_distance" "0.4" } } diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 12245b8..5124c56 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -202,6 +202,7 @@ public OnConfigsExecuted() ClassLoad(); ConfigOnModulesLoaded(); + ClassOnModulesLoaded(); } /** diff --git a/src/zr/commands.inc b/src/zr/commands.inc index 6cac4f1..a98183e 100644 --- a/src/zr/commands.inc +++ b/src/zr/commands.inc @@ -26,7 +26,9 @@ CreateCommands() RegAdminCmd("zr_anticamp_list", Command_AnticampList, ADMFLAG_GENERIC, "List current volumes."); RegConsoleCmd("zr_log_flags", Command_LogFlags, "List available logging flags."); + RegConsoleCmd("zr_class_dump", Command_ClassDump, "Dumps class data at a specified index in the specified cache. Usage: zr_class_dump "); + RegAdminCmd("zr_class_modify", Command_ClassModify, ADMFLAG_GENERIC, "Modify class data on one or more classes. Usage: zr_class_modify [is_multiplier]"); } public Action:Command_Infect(client, argc) @@ -229,60 +231,6 @@ public Action:Command_Unrestrict(client, argc) return Plugin_Handled; } -/*public Action:Command_SetClassKnockback(client, argc) -{ - if (argc < 2) - { - ReplyToCommand(client, "Sets the specified class knockback. Usage: zr_set_class_knockback "); - return Plugin_Handled; - } - - decl String:classname[64]; - decl String:knockback_arg[8]; - new classindex; - new Float:knockback; - - GetCmdArg(1, classname, sizeof(classname)); - GetCmdArg(2, knockback_arg, sizeof(knockback_arg)); - classindex = GetClassIndex(classname); - knockback = StringToFloat(knockback_arg); - - if (classindex < 0) - { - ReplyToCommand(client, "Could not find the class %s.", classname); - return Plugin_Handled; - } - - arrayClasses[classindex][data_knockback] = knockback; - return Plugin_Handled; -} - -public Action:Command_GetClassKnockback(client, argc) -{ - if (argc < 1) - { - ReplyToCommand(client, "Gets the specified class knockback. Usage: zr_get_class_knockback "); - return Plugin_Handled; - } - - decl String:classname[64]; - new classindex; - new Float:knockback; - - GetCmdArg(1, classname, sizeof(classname)); - classindex = GetClassIndex(classname); - - if (classindex < 0) - { - ReplyToCommand(client, "Could not find the class %s.", classname); - return Plugin_Handled; - } - - knockback = arrayClasses[classindex][data_knockback]; - ReplyToCommand(client, "Current knockback for %s: %f", classname, knockback); - - return Plugin_Handled; -}*/ public Action:Command_AdminMenu(client, argc) { diff --git a/src/zr/jumpboost.inc b/src/zr/jumpboost.inc index 7105b57..5ac4cbf 100644 --- a/src/zr/jumpboost.inc +++ b/src/zr/jumpboost.inc @@ -28,13 +28,13 @@ JumpBoostOnClientJump(client) // Apply jump values. vecVelocity[0] *= distance; vecVelocity[1] *= distance; - vecVelocity[2] = height; + vecVelocity[2] += height; JumpBoostSetClientVelocity(client, vecVelocity); } /** - * Apply jump boost force on client. (Special method separate from ToolsClientVelocity) + * Set new velocity on client. (Special method separate from ToolsClientVelocity) * * @param client The client index. * @param vecVelocity Velocity to set on client. diff --git a/src/zr/playerclasses/attributes.inc b/src/zr/playerclasses/attributes.inc index b5ba255..5f6fbb5 100644 --- a/src/zr/playerclasses/attributes.inc +++ b/src/zr/playerclasses/attributes.inc @@ -875,3 +875,177 @@ Float:ClassGetJumpDistance(index, cachetype = ZR_CLASS_CACHE_PLAYER) } return -1.0; } + +/** + * Gets the attribute flag that represent the specified attribute. + * + * @param attributename The attribute name. + * @return The flag that reporesent the specified attribute. + * -1 on error. + */ +ClassAttributeNameToFlag(const String:attributename[]) +{ + // Check attribute names. + if (StrEqual(attributename, "enabled", false)) + { + return ZR_CLASS_FLAG_ENABLED; + } + else if (StrEqual(attributename, "team", false)) + { + return ZR_CLASS_FLAG_TEAM; + } + else if (StrEqual(attributename, "team_default", false)) + { + return ZR_CLASS_FLAG_TEAM_DEFAULT; + } + else if (StrEqual(attributename, "name", false)) + { + return ZR_CLASS_FLAG_NAME; + } + else if (StrEqual(attributename, "description", false)) + { + return ZR_CLASS_FLAG_DESCRIPTION; + } + else if (StrEqual(attributename, "model_path", false)) + { + return ZR_CLASS_FLAG_MODEL_PATH; + } + else if (StrEqual(attributename, "alpha_initial", false)) + { + return ZR_CLASS_FLAG_ALPHA_INITIAL; + } + else if (StrEqual(attributename, "alpha_damaged", false)) + { + return ZR_CLASS_FLAG_ALPHA_DAMAGED; + } + else if (StrEqual(attributename, "alpha_damage", false)) + { + return ZR_CLASS_FLAG_ALPHA_DAMAGE; + } + else if (StrEqual(attributename, "overlay_path", false)) + { + return ZR_CLASS_FLAG_OVERLAY_PATH; + } + else if (StrEqual(attributename, "nvgs", false)) + { + return ZR_CLASS_FLAG_NVGS; + } + else if (StrEqual(attributename, "fov", false)) + { + return ZR_CLASS_FLAG_FOV; + } + else if (StrEqual(attributename, "napalm_time", false)) + { + return ZR_CLASS_FLAG_NAPALM_TIME; + } + else if (StrEqual(attributename, "immunity_mode", false)) + { + return ZR_CLASS_FLAG_IMMUNITY_MODE; + } + else if (StrEqual(attributename, "immunity_amount", false)) + { + return ZR_CLASS_FLAG_IMMUNITY_AMOUNT; + } + else if (StrEqual(attributename, "no_fall_damage", false)) + { + return ZR_CLASS_FLAG_NO_FALL_DAMAGE; + } + else if (StrEqual(attributename, "health", false)) + { + return ZR_CLASS_FLAG_HEALTH; + } + else if (StrEqual(attributename, "health_regen_interval", false)) + { + return ZR_CLASS_FLAG_HEALTH_REGEN_INTERVAL; + } + else if (StrEqual(attributename, "health_regen_amount", false)) + { + return ZR_CLASS_FLAG_HEALTH_REGEN_AMOUNT; + } + else if (StrEqual(attributename, "health_infect_gain", false)) + { + return ZR_CLASS_FLAG_HEALTH_INFECT_GAIN; + } + else if (StrEqual(attributename, "kill_bonus", false)) + { + return ZR_CLASS_FLAG_KILL_BONUS; + } + else if (StrEqual(attributename, "speed", false)) + { + return ZR_CLASS_FLAG_SPEED; + } + else if (StrEqual(attributename, "knockback", false)) + { + return ZR_CLASS_FLAG_KNOCKBACK; + } + else if (StrEqual(attributename, "jump_height", false)) + { + return ZR_CLASS_FLAG_JUMP_HEIGHT; + } + else if (StrEqual(attributename, "jump_distance", false)) + { + return ZR_CLASS_FLAG_JUMP_DISTANCE; + } + + // Invalid attribute name. + return -1; +} + +/** + * Returns the datatype used in the specified attribute. + * + * @param attributeflag A flag specifying the attribute to check. + * @return The data type used in the specified attribute, or + * ClassType_InvalidType if failed. + */ +ClassDataTypes:ClassGetAttributeType(attributeflag) +{ + switch (attributeflag) + { + // Boolean. + case ZR_CLASS_FLAG_ENABLED, + ZR_CLASS_FLAG_NVGS, + ZR_CLASS_FLAG_NO_FALL_DAMAGE: + { + return ClassDataType_Boolean; + } + + // Integer. + case ZR_CLASS_FLAG_ALPHA_INITIAL, + ZR_CLASS_FLAG_ALPHA_DAMAGED, + ZR_CLASS_FLAG_ALPHA_DAMAGE, + ZR_CLASS_FLAG_FOV, + ZR_CLASS_FLAG_IMMUNITY_MODE, + ZR_CLASS_FLAG_HEALTH, + ZR_CLASS_FLAG_HEALTH_REGEN_AMOUNT, + ZR_CLASS_FLAG_HEALTH_INFECT_GAIN, + ZR_CLASS_FLAG_KILL_BONUS: + { + return ClassDataType_Integer; + } + + // Float. + case ZR_CLASS_FLAG_NAPALM_TIME, + ZR_CLASS_FLAG_IMMUNITY_AMOUNT, + ZR_CLASS_FLAG_HEALTH_REGEN_INTERVAL, + ZR_CLASS_FLAG_SPEED, + ZR_CLASS_FLAG_KNOCKBACK, + ZR_CLASS_FLAG_JUMP_HEIGHT, + ZR_CLASS_FLAG_JUMP_DISTANCE: + { + return ClassDataType_Float; + } + + // String. + case ZR_CLASS_FLAG_NAME, + ZR_CLASS_FLAG_DESCRIPTION, + ZR_CLASS_FLAG_MODEL_PATH, + ZR_CLASS_FLAG_OVERLAY_PATH: + { + return ClassDataType_String; + } + } + + // Invalid flag or multiple flags combined. + return ClassDataType_InvalidType; +} diff --git a/src/zr/playerclasses/classcommands.inc b/src/zr/playerclasses/classcommands.inc index 02e48f6..9048aef 100644 --- a/src/zr/playerclasses/classcommands.inc +++ b/src/zr/playerclasses/classcommands.inc @@ -97,3 +97,499 @@ public Action:Command_ClassDump(client, argc) return Plugin_Handled; } + +/** + * Modifies class data on one or more classes. + * + * Syntax: zr_class_modify [is_multiplier] + * + * class: The class to modify. Can be any class name, or one of the + * following team names; "all", "humans", "zombies" or + * "admins". + * attribute: The name of the class attribute. + * value: Value to set. Use quotes if value is a string. + * is_multiplier: Optional. specifies wether the original value should be + * multiplied by the specified value. Defaults to false. + * + * Note: Original values are retrieved from the original class cache, not the + * modified class cache. + */ +public Action:Command_ClassModify(client, argc) +{ + decl String:syntax[1024]; + syntax[0] = 0; + + if (argc < 3) + { + // Write syntax info. + StrCat(syntax, sizeof(syntax), "Modifies class data on one or more classes. Usage: zr_class_modify [is_multiplier]\n\n"); + StrCat(syntax, sizeof(syntax), "class: The class to modify. Can be any class name, or one of the following team names; all, humans, zombies or admins.\n"); + StrCat(syntax, sizeof(syntax), "attribute: The name of the class attribute.\n"); + StrCat(syntax, sizeof(syntax), "value: Value to set. Use quotes if value is a string.\n"); + StrCat(syntax, sizeof(syntax), "is_multiplier: Optional. specifies wether the original value should be multiplied by the specified value. Not all attributes support multiplying. Defaults to false.\n\n"); + StrCat(syntax, sizeof(syntax), "Note: Original values are retrieved from the original class cache, not the modified class cache."); + ReplyToCommand(client, syntax); + + return Plugin_Handled; + } + + decl String:classname[64]; + decl String:attributename[128]; + decl String:value[256]; + decl String:ismultiplier[4]; + + new attributeflag; + new ClassDataTypes:attributetype; + new bool:isgroup; + new bool:hasmultiplier; + new Handle:classlist; + + new classindex; + new bool:listresult; + classlist = CreateArray(); + + // Get command arguments. + GetCmdArg(1, classname, sizeof(classname)); + GetCmdArg(2, attributename, sizeof(attributename)); + GetCmdArg(3, value, sizeof(value)); + + // Get last command argument if specified. + if (argc == 4) + { + GetCmdArg(4, ismultiplier, sizeof(ismultiplier)); + if (StringToInt(ismultiplier)) + { + hasmultiplier = true; + } + } + + // Get attribute flag. + attributeflag = ClassAttributeNameToFlag(attributename); + + // Validate attribute flag. + if (attributeflag < 0) + { + ReplyToCommand(client, "Invalid class attribute specified."); + return Plugin_Handled; + } + + // Get attribute data type. + attributetype = ClassGetAttributeType(attributeflag); + + // Check if classname is a group. Add classes to the class list + // and use the specified team filter. + if (StrEqual(classname, "all", false)) + { + listresult = ClassAddToArray(classlist); + isgroup = true; + } + else if (StrEqual(classname, "humans", false)) + { + listresult = ClassAddToArray(classlist, ZR_CLASS_TEAM_HUMANS); + isgroup = true; + } + else if (StrEqual(classname, "zombies", false)) + { + listresult = ClassAddToArray(classlist, ZR_CLASS_TEAM_ZOMBIES); + isgroup = true; + } + else if (StrEqual(classname, "admins", false)) + { + listresult = ClassAddToArray(classlist, ZR_CLASS_TEAM_ADMINS); + isgroup = true; + } + + // Check if classname is a group. + if (isgroup) + { + // Check if the list is valid. + if (!listresult) + { + ReplyToCommand(client, "Failed to get classes in the specified team: \"%s\".", classname); + return Plugin_Handled; + } + + // Loop through all classes in the list. + new listsize = GetArraySize(classlist); + + for (new i = 0; i < listsize; i++) + { + classindex = GetArrayCell(classlist, i); + + switch (attributetype) + { + case ClassDataType_Boolean: + { + if (!ClassModifyBoolean(classindex, attributeflag, bool:StringToInt(value))) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + case ClassDataType_Integer: + { + if (hasmultiplier) + { + if (!ClassModifyInteger(classindex, attributeflag, StringToInt(value), StringToFloat(value))) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + else + { + if (!ClassModifyInteger(classindex, attributeflag, StringToInt(value))) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + } + case ClassDataType_Float: + { + if (!ClassModifyFloat(classindex, attributeflag, StringToFloat(value), hasmultiplier)) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + case ClassDataType_String: + { + if (!ClassModifyString(classindex, attributeflag, value)) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + } + } + } + else + { + // It's a single class. + classindex = ClassGetIndex(classname); + + // Validate classindex. + if (!ClassValidateIndex(classindex)) + { + ReplyToCommand(client, "Invalid class name specified."); + return Plugin_Handled; + } + + switch (attributetype) + { + case ClassDataType_Boolean: + { + if (!ClassModifyBoolean(classindex, attributeflag, bool:StringToInt(value))) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + case ClassDataType_Integer: + { + if (hasmultiplier) + { + if (!ClassModifyInteger(classindex, attributeflag, StringToInt(value), StringToFloat(value))) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + else + { + if (!ClassModifyInteger(classindex, attributeflag, StringToInt(value))) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + } + case ClassDataType_Float: + { + if (!ClassModifyFloat(classindex, attributeflag, StringToFloat(value)), hasmultiplier) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + case ClassDataType_String: + { + if (!ClassModifyString(classindex, attributeflag, value)) + { + ReplyToCommand(client, "Failed to set \"%s\" to \"%s\" in class \"%d\".", attributename, value, classindex); + } + } + } + } + + return Plugin_Handled; +} + +/** + * Modify class boolean attribute on a class. + * + * @param classindex The class index. + * @param attributeflag Attribute to modify (a single attribute flag). + * @param value New value to set. + * @return True on success, false otherwise. + */ +bool:ClassModifyBoolean(classindex, attributeflag, bool:value) +{ + // Validate class index. + if (!ClassValidateIndex(classindex)) + { + return false; + } + + switch (attributeflag) + { + case ZR_CLASS_FLAG_ENABLED: + { + ClassDataCache[classindex][class_enabled] = bool:value; + return true; + } + case ZR_CLASS_FLAG_NVGS: + { + ClassDataCache[classindex][class_nvgs] = bool:value; + return true; + } + case ZR_CLASS_FLAG_NO_FALL_DAMAGE: + { + ClassDataCache[classindex][class_no_fall_damage] = bool:value; + return true; + } + } + + // Invalid flag or multiple flags combined. + return false; +} + +/** + * Modify class integer attribute on a class. + * + * @param classindex The class index. + * @param attributeflag Attribute to modify (a single attribute flag). + * @param value New value to set, or multiply with. + * @param multiplier Optional. Use a multiplier instead of the value, + * that multiplies with the original class value. + * Not all attributes support multipliers. 0.0 to + * disable. Value is ignored if this is non-zero. + * @return True on success, false otherwise. + */ +ClassModifyInteger(classindex, attributeflag, value, Float:multiplier = 0.0) +{ + // Validate class index. + if (!ClassValidateIndex(classindex)) + { + return false; + } + + // Check if multiplier is specified. + new bool:ismultiplier = (multiplier != 0.0) ? true : false; + + switch (attributeflag) + { + case ZR_CLASS_FLAG_ALPHA_INITIAL: + { + if (ismultiplier) + { + value = RoundToNearest(float(ClassData[classindex][class_alpha_initial]) * multiplier); + } + ClassDataCache[classindex][class_alpha_initial] = value; + return true; + } + case ZR_CLASS_FLAG_ALPHA_DAMAGED: + { + if (ismultiplier) + { + value = RoundToNearest(float(ClassData[classindex][class_alpha_damaged]) * multiplier); + } + ClassDataCache[classindex][class_alpha_damaged] = value; + return true; + } + case ZR_CLASS_FLAG_ALPHA_DAMAGE: + { + if (ismultiplier) + { + value = RoundToNearest(float(ClassData[classindex][class_alpha_damage]) * multiplier); + } + ClassDataCache[classindex][class_alpha_damage] = value; + return true; + } + case ZR_CLASS_FLAG_FOV: + { + ClassDataCache[classindex][class_fov] = value; + return true; + } + case ZR_CLASS_FLAG_IMMUNITY_MODE: + { + ClassDataCache[classindex][class_fov] = value; + return true; + } + case ZR_CLASS_FLAG_HEALTH: + { + if (ismultiplier) + { + value = RoundToNearest(float(ClassData[classindex][class_health]) * multiplier); + } + ClassDataCache[classindex][class_health] = value; + return true; + } + case ZR_CLASS_FLAG_HEALTH_REGEN_AMOUNT: + { + if (ismultiplier) + { + value = RoundToNearest(float(ClassData[classindex][class_health_regen_amount]) * multiplier); + } + ClassDataCache[classindex][class_health_regen_amount] = value; + return true; + } + case ZR_CLASS_FLAG_HEALTH_INFECT_GAIN: + { + if (ismultiplier) + { + value = RoundToNearest(float(ClassData[classindex][class_health_infect_gain]) * multiplier); + } + ClassDataCache[classindex][class_health_infect_gain] = value; + return true; + } + case ZR_CLASS_FLAG_KILL_BONUS: + { + if (ismultiplier) + { + value = RoundToNearest(float(ClassData[classindex][class_kill_bonus]) * multiplier); + } + ClassDataCache[classindex][class_kill_bonus] = value; + return true; + } + } + + // Invalid flag or multiple flags combined. + return false; +} + +/** + * Modify class float attribute on a class. + * + * @param classindex The class index. + * @param attributeflag Attribute to modify (a single attribute flag). + * @param value New value to set, or multiply with. + * @param ismultiplier Optional. Specifies wether to value as a multiplier + * that multiplies with the original class value. + * Not all attributes support multipliers. + * @return True on success, false otherwise. + */ +ClassModifyFloat(classindex, attributeflag, Float:value, bool:ismultiplier = false) +{ + // Validate class index. + if (!ClassValidateIndex(classindex)) + { + return false; + } + + switch (attributeflag) + { + case ZR_CLASS_FLAG_NAPALM_TIME: + { + if (ismultiplier) + { + value = ClassData[classindex][class_napalm_time] * value; + } + ClassDataCache[classindex][class_napalm_time] = value; + return true; + } + case ZR_CLASS_FLAG_IMMUNITY_AMOUNT: + { + if (ismultiplier) + { + value = ClassData[classindex][class_immunity_amount] * value; + } + ClassDataCache[classindex][class_immunity_amount] = value; + return true; + } + case ZR_CLASS_FLAG_HEALTH_REGEN_INTERVAL: + { + if (ismultiplier) + { + value = ClassData[classindex][class_health_regen_interval] * value; + } + ClassDataCache[classindex][class_health_regen_interval] = value; + return true; + } + case ZR_CLASS_FLAG_SPEED: + { + if (ismultiplier) + { + value = ClassData[classindex][class_speed] * value; + } + ClassDataCache[classindex][class_speed] = value; + return true; + } + case ZR_CLASS_FLAG_KNOCKBACK: + { + if (ismultiplier) + { + value = ClassData[classindex][class_knockback] * value; + } + ClassDataCache[classindex][class_knockback] = value; + return true; + } + case ZR_CLASS_FLAG_JUMP_HEIGHT: + { + if (ismultiplier) + { + value = ClassData[classindex][class_jump_height] * value; + } + ClassDataCache[classindex][class_jump_height] = value; + return true; + } + case ZR_CLASS_FLAG_JUMP_DISTANCE: + { + if (ismultiplier) + { + value = ClassData[classindex][class_jump_distance] * value; + } + ClassDataCache[classindex][class_jump_distance] = value; + return true; + } + } + + // Invalid flag or multiple flags combined. + return false; +} + +/** + * Modify class string attribute on a class. + * + * @param classindex The class index. + * @param attributeflag Attribute to modify (a single attribute flag). + * @param value New value to set. + * @return True on success, false otherwise. + */ +ClassModifyString(classindex, attributeflag, const String:value[]) +{ + // Validate class index. + if (!ClassValidateIndex(classindex)) + { + return false; + } + + switch (attributeflag) + { + case ZR_CLASS_FLAG_NAME: + { + strcopy(ClassDataCache[classindex][class_name], 64, value); + return true; + } + case ZR_CLASS_FLAG_DESCRIPTION: + { + strcopy(ClassDataCache[classindex][class_description], 256, value); + return true; + } + case ZR_CLASS_FLAG_MODEL_PATH: + { + strcopy(ClassDataCache[classindex][class_model_path], PLATFORM_MAX_PATH, value); + return true; + } + case ZR_CLASS_FLAG_OVERLAY_PATH: + { + strcopy(ClassDataCache[classindex][class_overlay_path], PLATFORM_MAX_PATH, value); + return true; + } + } + + // Invalid flag or multiple flags combined. + return false; +} diff --git a/src/zr/playerclasses/classevents.inc b/src/zr/playerclasses/classevents.inc index c13d63b..944b21d 100644 --- a/src/zr/playerclasses/classevents.inc +++ b/src/zr/playerclasses/classevents.inc @@ -23,24 +23,42 @@ */ ClassClientInit(client) { - if (ZRIsClientValid(client)) + // Check if there are valid classes and the client is valid. + if (ClassValidated && ZRIsClientValid(client)) { // Set default class indexes on the player. ClassClientSetDefaultIndexes(client); } } +/** + * Called when all modules are done loading. + */ +ClassOnModulesLoaded() +{ + // Set default classes on all player slots. + ClassClientSetDefaultIndexes(); +} + ClassOnClientDisconnect(client) { - // Stop timers related to class attributes. + // Disable class attributes with timers. + ClassHealthRegenStop(client); ClassOverlayStop(client); } ClassOnClientSpawn(client) { + // Check if the player is alive. if (!IsPlayerAlive(client)) { - // The client isn't alive. + return; + } + + // Check if there are valid classes. Block this event if classes aren't + // done loading. + if (!ClassValidated) + { return; } @@ -97,7 +115,7 @@ ClassOnClientSpawn(client) ClassOnClientDeath(client) { - // Reset certain attributes to not make spectating disorted. + // Disable class attributes with timers. ClassHealthRegenStop(client); ClassOverlayStop(client); @@ -109,17 +127,13 @@ ClassOnClientInfected(client, bool:motherzombie = false) { new classindex = ClassGetActiveIndex(client); + // Disable class attributes with timers. + ClassHealthRegenStop(client); + ClassOverlayStop(client); + // Update the players cache with zombie attributes. ClassReloadPlayerCache(client, classindex); // Apply the new attributes. ClassApplyAttributes(client, motherzombie); } - -/* ------------------------------------ - * - * PLAYER COMMANDS - * - * ------------------------------------ - */ - diff --git a/src/zr/playerclasses/filtertools.inc b/src/zr/playerclasses/filtertools.inc index d5230db..d389ee7 100644 --- a/src/zr/playerclasses/filtertools.inc +++ b/src/zr/playerclasses/filtertools.inc @@ -96,6 +96,20 @@ ClassValidateAttributes(classindex) { flags += ZR_CLASS_FLAG_NAME; } + else + { + decl String:name[64]; + strcopy(name, sizeof(name), ClassData[classindex][class_name]); + + // Check for reserved name keyworks. + if (StrEqual(name, "all", false) || + StrEqual(name, "humans", false) || + StrEqual(name, "zombies", false) || + StrEqual(name, "admins", false)) + { + flags += ZR_CLASS_FLAG_NAME; + } + } // Description. if (strlen(ClassData[classindex][class_description]) < ZR_CLASS_DESCRIPTION_MIN) @@ -195,7 +209,7 @@ ClassValidateAttributes(classindex) new infect_gain = ClassData[classindex][class_health_infect_gain]; if (!(infect_gain >= ZR_CLASS_HEALTH_INFECT_GAIN_MIN && infect_gain <= ZR_CLASS_HEALTH_INFECT_GAIN_MAX)) { - flags += ZR_CLASS_FLAG_INFECT_GAIN; + flags += ZR_CLASS_FLAG_HEALTH_INFECT_GAIN; } // Kill bonus. diff --git a/src/zr/playerclasses/playerclasses.inc b/src/zr/playerclasses/playerclasses.inc index b6e8a28..24a06d0 100644 --- a/src/zr/playerclasses/playerclasses.inc +++ b/src/zr/playerclasses/playerclasses.inc @@ -156,40 +156,44 @@ #define ZR_CLASS_KNOCKBACK_MAX 30.0 #define ZR_CLASS_JUMP_HEIGHT_MIN -500.0 #define ZR_CLASS_JUMP_HEIGHT_MAX 500.0 -#define ZR_CLASS_JUMP_DISTANCE_MIN -500.0 -#define ZR_CLASS_JUMP_DISTANCE_MAX 500.0 +#define ZR_CLASS_JUMP_DISTANCE_MIN -5.0 +#define ZR_CLASS_JUMP_DISTANCE_MAX 5.0 /** * @endsection */ /** - * @section Error flags for invalid class attributes. + * @section Flags used for specifying one or more attributes. */ -#define ZR_CLASS_FLAG_NAME (1<<0) -#define ZR_CLASS_FLAG_DESCRIPTION (1<<1) -#define ZR_CLASS_FLAG_MODEL_PATH (1<<2) -#define ZR_CLASS_FLAG_ALPHA_INITIAL (1<<3) -#define ZR_CLASS_FLAG_ALPHA_DAMAGED (1<<4) -#define ZR_CLASS_FLAG_ALPHA_DAMAGE (1<<5) -#define ZR_CLASS_FLAG_OVERLAY_PATH (1<<6) -#define ZR_CLASS_FLAG_FOV (1<<7) -#define ZR_CLASS_FLAG_NAPALM_TIME (1<<8) -#define ZR_CLASS_FLAG_IMMUNITY_MODE (1<<9) -#define ZR_CLASS_FLAG_IMMUNITY_AMOUNT (1<<10) -#define ZR_CLASS_FLAG_HEALTH (1<<11) -#define ZR_CLASS_FLAG_HEALTH_REGEN_INTERVAL (1<<12) -#define ZR_CLASS_FLAG_HEALTH_REGEN_AMOUNT (1<<13) -#define ZR_CLASS_FLAG_INFECT_GAIN (1<<14) -#define ZR_CLASS_FLAG_KILL_BONUS (1<<15) -#define ZR_CLASS_FLAG_SPEED (1<<16) -#define ZR_CLASS_FLAG_KNOCKBACK (1<<17) -#define ZR_CLASS_FLAG_JUMP_HEIGHT (1<<18) -#define ZR_CLASS_FLAG_JUMP_DISTANCE (1<<19) +#define ZR_CLASS_FLAG_ENABLED (1<<0) +#define ZR_CLASS_FLAG_TEAM (1<<1) +#define ZR_CLASS_FLAG_TEAM_DEFAULT (1<<2) +#define ZR_CLASS_FLAG_NAME (1<<3) +#define ZR_CLASS_FLAG_DESCRIPTION (1<<4) +#define ZR_CLASS_FLAG_MODEL_PATH (1<<5) +#define ZR_CLASS_FLAG_ALPHA_INITIAL (1<<6) +#define ZR_CLASS_FLAG_ALPHA_DAMAGED (1<<7) +#define ZR_CLASS_FLAG_ALPHA_DAMAGE (1<<8) +#define ZR_CLASS_FLAG_OVERLAY_PATH (1<<9) +#define ZR_CLASS_FLAG_NVGS (1<<10) +#define ZR_CLASS_FLAG_FOV (1<<11) +#define ZR_CLASS_FLAG_NAPALM_TIME (1<<12) +#define ZR_CLASS_FLAG_IMMUNITY_MODE (1<<13) +#define ZR_CLASS_FLAG_IMMUNITY_AMOUNT (1<<14) +#define ZR_CLASS_FLAG_NO_FALL_DAMAGE (1<<15) +#define ZR_CLASS_FLAG_HEALTH (1<<16) +#define ZR_CLASS_FLAG_HEALTH_REGEN_INTERVAL (1<<17) +#define ZR_CLASS_FLAG_HEALTH_REGEN_AMOUNT (1<<18) +#define ZR_CLASS_FLAG_HEALTH_INFECT_GAIN (1<<19) +#define ZR_CLASS_FLAG_KILL_BONUS (1<<20) +#define ZR_CLASS_FLAG_SPEED (1<<21) +#define ZR_CLASS_FLAG_KNOCKBACK (1<<22) +#define ZR_CLASS_FLAG_JUMP_HEIGHT (1<<23) +#define ZR_CLASS_FLAG_JUMP_DISTANCE (1<<24) /** * @endsection */ - /** * Generic player attributes. */ @@ -231,7 +235,19 @@ enum ClassAttributes Float:class_speed, Float:class_knockback, Float:class_jump_height, - Float:class_jump_distance, + Float:class_jump_distance +} + +/** + * Data types used in class attributes. + */ +enum ClassDataTypes +{ + ClassDataType_InvalidType, /** Invalid type */ + ClassDataType_Boolean, /** Boolean value */ + ClassDataType_Integer, /** Integer value */ + ClassDataType_Float, /** Floating point value */ + ClassDataType_String /** String value */ } /** @@ -264,6 +280,12 @@ new ClassPlayerCache[MAXPLAYERS + 1][ClassAttributes]; */ new ClassCount; +/** + * Specifies wether the class team requirement and attributes are valid or not. + * Used to block events that happend before the module is done loading. + */ +new bool:ClassValidated; + /** * Stores what class that the player have selected, for each team. */ @@ -314,12 +336,6 @@ ClassLoad() decl String:pathclasses[PLATFORM_MAX_PATH]; new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_PLAYERCLASSES, pathclasses); - // Log what class file that is loaded. - if (enablelog) - { - LogMessageFormatted(-1, "Classes", "Load", "Loading classes from file \"%s\".", LOG_FORMAT_TYPE_SIMPLE, pathclasses); - } - // If file doesn't exist, then log and stop. if (!exists) { @@ -328,6 +344,12 @@ ClassLoad() return; } + // Log what class file that is loaded. + if (enablelog) + { + LogMessageFormatted(-1, "Classes", "Load", "Loading classes from file \"%s\".", LOG_FORMAT_TYPE_SIMPLE, pathclasses); + } + // Put file data into memory. FileToKeyValues(kvClassData, pathclasses); @@ -444,6 +466,9 @@ ClassLoad() // Cache class data. ClassReloadDataCache(); + // Mark classes as valid. + ClassValidated = true; + // Log summary. if (enablelog) {