diff --git a/src/zr/playerclasses/apply.inc b/src/zr/playerclasses/apply.inc index 5043268..6934400 100644 --- a/src/zr/playerclasses/apply.inc +++ b/src/zr/playerclasses/apply.inc @@ -74,6 +74,8 @@ bool:ClassApplyModel(client, classindex, cachetpye = ZR_CLASS_CACHE_PLAYER) Format(modelpath, sizeof(modelpath), "%s.mdl", modelpath); } + // TODO: Add support for keeping the default cs model ("default"). + SetPlayerModel(client, modelpath); return true; } diff --git a/src/zr/playerclasses/filtertools.inc b/src/zr/playerclasses/filtertools.inc index e05daae..fa7b7bf 100644 --- a/src/zr/playerclasses/filtertools.inc +++ b/src/zr/playerclasses/filtertools.inc @@ -45,15 +45,138 @@ bool:ClassValidateTeamRequirements(cachetype = ZR_CLASS_CACHE_ORIGINAL) /** * Validates all the class attributes in the original class data array, to - * check if they have invalid values. + * check if they have invalid values. Boolean settings are not validated. * * @param classindex The index of the class to validate. - * @return True if validation was successful, false otherwise. + * @return A value with attribute error flags. */ -bool:ClassValidateAttributes(classindex) +ClassValidateAttributes(classindex) { - return true; - // TODO: Manually check each attribute (hard coded). Better solutions? + // TODO: Validate immunity mode and amount. + // TODO: Validate jump values. + + new flags; + + // Name. + if (strlen(ClassData[classindex][class_name]) == 0) + { + flags += ZR_CLASS_ATTRIB_ERR_NAME; + } + + // Description. + if (strlen(ClassData[classindex][class_description]) == 0) + { + flags += ZR_CLASS_ATTRIB_ERR_DESCRIPTION; + } + + // Model path. + decl String:model_path[256]; + if (strcopy(model_path, sizeof(model_path), ClassData[classindex][class_model_path]) == 0) + { + flags += ZR_CLASS_ATTRIB_ERR_MODEL_PATH; + } + else + { + // Check if default or random model is specified. + if (strcmp(model_path, "random", false) != 0 && strcmp(model_path, "default", false) != 0) + { + // Check if the file exists. + if (!FileExists(model_path)) + { + flags += ZR_CLASS_ATTRIB_ERR_MODEL_PATH; + } + } + } + + // Alpha, initial. + new alpha_initial = ClassData[classindex][class_alpha_initial]; + if (!(alpha_initial >= 0 && alpha_initial <= 255)) + { + flags += ZR_CLASS_ATTRIB_ERR_ALPHA_INITIAL; + } + + // Alpha, damaged. + new alpha_damaged = ClassData[classindex][class_alpha_damaged]; + if (!(alpha_damaged >= 0 && alpha_damaged <= 255)) + { + flags += ZR_CLASS_ATTRIB_ERR_ALPHA_DAMAGED; + } + + // Alpha, damage. + new alpha_damage = ClassData[classindex][class_alpha_damage]; + if (!(alpha_damage >= 0 && alpha_damage <= 65536)) + { + flags += ZR_CLASS_ATTRIB_ERR_ALPHA_DAMAGE; + } + + // Overlay path. + decl String:overlay_path[256]; + if (strcopy(overlay_path, sizeof(overlay_path), ClassData[classindex][class_overlay_path]) != 0) + { + // Check if the file exists. + if (!FileExists(overlay_path)) + { + flags += ZR_CLASS_ATTRIB_ERR_OVERLAY_PATH; + } + } + + // Field of view. + new fov = ClassData[classindex][class_fov]; + if (!(fov > 15 && fov < 180)) + { + flags += ZR_CLASS_ATTRIB_ERR_FOV; + } + + // Napalm time. + new Float:napalm_time = ClassData[classindex][class_napalm_time]; + if (!(napalm_time >= 0.0 && napalm_time <= 900.0)) + { + flags += ZR_CLASS_ATTRIB_ERR_NAPALM_TIME; + } + + // Health regen interval. + new Float:regen_interval = ClassData[classindex][class_health_regen_interval]; + if (!(regen_interval >= 0.0 && regen_interval <= 900.0)) + { + flags += ZR_CLASS_ATTRIB_ERR_HEALTH_REGEN_INTERVAL; + } + + // Health regen amount. + new regen_amount = ClassData[classindex][class_health_regen_amount]; + if (!(regen_amount > 0 && regen_amount <= 65536)) + { + flags += ZR_CLASS_ATTRIB_ERR_HEALTH_REGEN_AMOUNT; + } + + // Health infect gain. + new infect_gain = ClassData[classindex][class_health_infect_gain]; + if (!(infect_gain >= 0 && infect_gain <= 65536)) + { + flags += ZR_CLASS_ATTRIB_ERR_INFECT_GAIN; + } + + // Kill bonus. + new kill_bonus = ClassData[classindex][class_kill_bonus]; + if (!(kill_bonus >= 0 && kill_bonus <= 128)) + { + flags += ZR_CLASS_ATTRIB_ERR_KILL_BONUS; + } + + // Speed. + new Float:speed = ClassData[classindex][class_speed]; + if (!(speed >= 0.0 && speed <= 1024.0)) + { + flags += ZR_CLASS_ATTRIB_ERR_SPEED; + } + + // Knockback. + new Float:knockback = ClassData[classindex][class_knockback]; + if (!(knockback >= -10.0 && knockback <= 50.0)) + { + flags += ZR_CLASS_ATTRIB_ERR_KNOCKBACK; + } + + return flags; } /** @@ -65,12 +188,7 @@ bool:ClassValidateAttributes(classindex) */ bool:ClassValidateIndex(classindex) { - if (ClassCount == 0) - { - return false; - } - - if (classindex >= 0 && classid < ClassCount) + if (classindex >= 0 && classindex < ClassCount) { return true; } diff --git a/src/zr/playerclasses/playerclasses.inc b/src/zr/playerclasses/playerclasses.inc index 7b0b148..2509331 100644 --- a/src/zr/playerclasses/playerclasses.inc +++ b/src/zr/playerclasses/playerclasses.inc @@ -129,6 +129,34 @@ * @endsection */ +/** + * @section Error flags for invalid class attributes. + */ +#define ZR_CLASS_ATTRIB_ERR_OK 0 +#define ZR_CLASS_ATTRIB_ERR_NAME 1 +#define ZR_CLASS_ATTRIB_ERR_DESCRIPTION 2 +#define ZR_CLASS_ATTRIB_ERR_MODEL_PATH 4 +#define ZR_CLASS_ATTRIB_ERR_ALPHA_INITIAL 8 +#define ZR_CLASS_ATTRIB_ERR_ALPHA_DAMAGED 16 +#define ZR_CLASS_ATTRIB_ERR_ALPHA_DAMAGE 32 +#define ZR_CLASS_ATTRIB_ERR_OVERLAY_PATH 64 +#define ZR_CLASS_ATTRIB_ERR_FOV 128 +#define ZR_CLASS_ATTRIB_ERR_NAPALM_TIME 256 +#define ZR_CLASS_ATTRIB_ERR_IMMUNITY_MODE 512 +#define ZR_CLASS_ATTRIB_ERR_IMMUNITY_AMOUNT 1024 +#define ZR_CLASS_ATTRIB_ERR_HEALTH_REGEN_INTERVAL 2048 +#define ZR_CLASS_ATTRIB_ERR_HEALTH_REGEN_AMOUNT 4096 +#define ZR_CLASS_ATTRIB_ERR_INFECT_GAIN 8192 +#define ZR_CLASS_ATTRIB_ERR_KILL_BONUS 16384 +#define ZR_CLASS_ATTRIB_ERR_SPEED 32768 +#define ZR_CLASS_ATTRIB_ERR_KNOCKBACK 65536 +#define ZR_CLASS_ATTRIB_ERR_JUMP_HEIGHT 131072 +#define ZR_CLASS_ATTRIB_ERR_JUMP_DISTANCE 262144 +/** + * @endsection + */ + + /** * Generic player attributes. */ @@ -249,6 +277,7 @@ ClassLoad(const String:classfile[256] = "configs/zr/playerclasses.txt") decl String:overlay_path[256]; ClassCount = 0; + new ClassErrorFlags; // Loop through all classes and store attributes in the ClassData array. do @@ -313,17 +342,20 @@ ClassLoad(const String:classfile[256] = "configs/zr/playerclasses.txt") ClassData[ClassCount][class_jump_distance] = KvGetFloat(kvClassData, "jump_distance", ZR_CLASS_DEFAULT_JUMP_DISTANCE); // Validate the class attributes. - if (!ClassValidateAttributes(ClassCount)) + ClassErrorFlags = ClassValidateAttributes(ClassCount); + if (ClassErrorFlags > 0) { - // TODO: There's an invalid class, what do we do? - // Skip it (clearing data too), disable it and give a log warning, - // or set the plugin in a failed state? - } - else - { - // The class is valid. Update the counter. - ClassCount++; + // There's one or more invalid class attributes. Disable the class + // and log an error message. + ClassData[ClassCount][class_enabled] = false; + if (LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_CLASSES)) + { + ZR_LogMessageFormatted(-1, "classes", "load", "Invalid class at index %d. Class error flags: %d.", LOG_FORMAT_TYPE_ERROR, ClassCount, ClassErrorFlags); + } } + + // Update the counter. + ClassCount++; } while (KvGotoNextKey(kvClassData)); // Validate team requirements.