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) {