Merged heads.

This commit is contained in:
Greyscale 2009-05-11 04:47:56 +02:00
commit 67ec1f8433
15 changed files with 907 additions and 147 deletions

View File

@ -36,8 +36,8 @@
// kill_bonus number How many points to give per kill. Humans only. // kill_bonus number How many points to give per kill. Humans only.
// speed decimal The player speed. // speed decimal The player speed.
// knockback decimal Force of the knockback when shot at. Zombies only. // knockback decimal Force of the knockback when shot at. Zombies only.
// jump_height decimal Extra upwards jump boost. // jump_height decimal Extra upwards jump boost in units. 0.0 for no extra boost.
// jump_distance decimal Extra forwards jump boost. // jump_distance decimal Extra forwards jump boost multiplier. 0.2 is normal distance.
"classes" "classes"
{ {
@ -75,16 +75,16 @@
"immunity_amount" "0.0" "immunity_amount" "0.0"
"no_fall_damage" "1" "no_fall_damage" "1"
"health" "3000" "health" "2500"
"health_regen_interval" "0.0" "health_regen_interval" "0.0"
"health_regen_amount" "0" "health_regen_amount" "0"
"health_infect_gain" "800" "health_infect_gain" "700"
"kill_bonus" "2" "kill_bonus" "2"
"speed" "350" "speed" "350"
"knockback" "3" "knockback" "4"
"jump_height" "40.0" "jump_height" "10.0"
"jump_distance" "1.5" "jump_distance" "0.3"
} }
"fast" "fast"
@ -123,9 +123,9 @@
"kill_bonus" "2" "kill_bonus" "2"
"speed" "380" "speed" "380"
"knockback" "3.5" "knockback" "4.5"
"jump_height" "60.0" "jump_height" "30.0"
"jump_distance" "2.0" "jump_distance" "0.4"
} }
"mutated" "mutated"
@ -157,16 +157,16 @@
"immunity_amount" "0.0" "immunity_amount" "0.0"
"no_fall_damage" "1" "no_fall_damage" "1"
"health" "5000" "health" "3500"
"health_regen_interval" "0.0" "health_regen_interval" "0.0"
"health_regen_amount" "0" "health_regen_amount" "0"
"health_infect_gain" "1000" "health_infect_gain" "850"
"kill_bonus" "2" "kill_bonus" "2"
"speed" "275" "speed" "275"
"knockback" "3.5" "knockback" "3.5"
"jump_height" "40.0" "jump_height" "20.0"
"jump_distance" "1.3" "jump_distance" "0.4"
} }
"heavy" "heavy"
@ -198,16 +198,16 @@
"immunity_amount" "0.0" "immunity_amount" "0.0"
"no_fall_damage" "1" "no_fall_damage" "1"
"health" "5000" "health" "4000"
"health_regen_interval" "0.0" "health_regen_interval" "0.0"
"health_regen_amount" "0" "health_regen_amount" "0"
"health_infect_gain" "1000" "health_infect_gain" "1000"
"kill_bonus" "2" "kill_bonus" "2"
"speed" "280" "speed" "280"
"knockback" "2.0" "knockback" "2.5"
"jump_height" "0.0" "jump_height" "0.0"
"jump_distance" "0.8" "jump_distance" "0.2"
} }
// ------------------------------------------ // ------------------------------------------
@ -254,7 +254,7 @@
"speed" "300" "speed" "300"
"knockback" "0" "knockback" "0"
"jump_height" "0.0" "jump_height" "0.0"
"jump_distance" "1.0" "jump_distance" "0.2"
} }
"human_speedy" "human_speedy"
@ -295,7 +295,7 @@
"speed" "380" "speed" "380"
"knockback" "0" "knockback" "0"
"jump_height" "0.0" "jump_height" "0.0"
"jump_distance" "1.0" "jump_distance" "0.2"
} }
"human_light" "human_light"
@ -335,7 +335,7 @@
"speed" "300" "speed" "300"
"knockback" "0" "knockback" "0"
"jump_height" "64.0" "jump_height" "30.0"
"jump_distance" "2.0" "jump_distance" "0.4"
} }
} }

View File

@ -200,6 +200,9 @@ public OnConfigsExecuted()
VEffectsLoad(); VEffectsLoad();
SEffectsLoad(); SEffectsLoad();
ClassLoad(); ClassLoad();
ConfigOnModulesLoaded();
ClassOnModulesLoaded();
} }
/** /**

View File

@ -26,7 +26,9 @@ CreateCommands()
RegAdminCmd("zr_anticamp_list", Command_AnticampList, ADMFLAG_GENERIC, "List current volumes."); RegAdminCmd("zr_anticamp_list", Command_AnticampList, ADMFLAG_GENERIC, "List current volumes.");
RegConsoleCmd("zr_log_flags", Command_LogFlags, "List available logging flags."); 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 <cachetype> <index|targetname>"); RegConsoleCmd("zr_class_dump", Command_ClassDump, "Dumps class data at a specified index in the specified cache. Usage: zr_class_dump <cachetype> <index|targetname>");
RegAdminCmd("zr_class_modify", Command_ClassModify, ADMFLAG_GENERIC, "Modify class data on one or more classes. Usage: zr_class_modify <classname|\"zombies\"|\"humans\"|\"admins\"> <attribute> <value> [is_multiplier]");
} }
public Action:Command_Infect(client, argc) public Action:Command_Infect(client, argc)
@ -229,60 +231,6 @@ public Action:Command_Unrestrict(client, argc)
return Plugin_Handled; return Plugin_Handled;
} }
/*public Action:Command_SetClassKnockback(client, argc)
{
if (argc < 2)
{
ReplyToCommand(client, "Sets the specified class knockback. Usage: zr_set_class_knockback <classname> <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 <classname>");
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) public Action:Command_AdminMenu(client, argc)
{ {

View File

@ -41,6 +41,9 @@
*/ */
#define CONFIG_OPTION_MAX_LENGTH 32 #define CONFIG_OPTION_MAX_LENGTH 32
/**
* Actions to use when working on key/values.
*/
enum ConfigKeyvalueAction enum ConfigKeyvalueAction
{ {
Create, /** Create a key. */ Create, /** Create a key. */
@ -48,6 +51,9 @@ enum ConfigKeyvalueAction
Set, /** Modify setting of a key. */ Set, /** Modify setting of a key. */
Get, /** Get setting of a key. */ Get, /** Get setting of a key. */
} }
/**
* @endsection
*/
/** /**
* @section Global data handle initializations. * @section Global data handle initializations.
@ -57,6 +63,7 @@ new Handle:kvClassData = INVALID_HANDLE;
new Handle:kvWeapons = INVALID_HANDLE; new Handle:kvWeapons = INVALID_HANDLE;
new Handle:kvWeaponGroups = INVALID_HANDLE; new Handle:kvWeaponGroups = INVALID_HANDLE;
new Handle:kvHitgroups = INVALID_HANDLE; new Handle:kvHitgroups = INVALID_HANDLE;
/** /**
* Load plugin configs. * 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. * Load config file.
* *
@ -106,6 +155,7 @@ bool:ConfigGetFilePath(CvarsList:cvar, String:path[])
return FileExists(path); return FileExists(path);
} }
/** /**
* Creates, deletes, sets, or gets any key/setting of any ZR config keyvalue file in memory. * 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, * Only use when interacting with a command or manipulating single keys/values,

View File

@ -28,13 +28,13 @@ JumpBoostOnClientJump(client)
// Apply jump values. // Apply jump values.
vecVelocity[0] *= distance; vecVelocity[0] *= distance;
vecVelocity[1] *= distance; vecVelocity[1] *= distance;
vecVelocity[2] = height; vecVelocity[2] += height;
JumpBoostSetClientVelocity(client, vecVelocity); 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 client The client index.
* @param vecVelocity Velocity to set on client. * @param vecVelocity Velocity to set on client.

View File

@ -92,6 +92,7 @@ LogInit()
* LOG_FORMAT_TYPE_SIMPLE - Simple, no module or block info. * 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_FULL - Full, with module and block info, printed in normal log.
* LOG_FORMAT_TYPE_ERROR - Full, printed in error log. * LOG_FORMAT_TYPE_ERROR - Full, printed in error log.
* LOG_FORMAT_TYPE_FATALERROR - Full, stops the plugin.
* @param any... Formatting parameters. * @param any... Formatting parameters.
*/ */
LogMessageFormatted(client, const String:module[], const String:block[], const String:message[], type = LOG_FORMAT_TYPE_FULL, any:...) LogMessageFormatted(client, const String:module[], const String:block[], const String:message[], type = LOG_FORMAT_TYPE_FULL, any:...)

View File

@ -24,7 +24,7 @@ MenuMain(client)
SetGlobalTransTarget(client); SetGlobalTransTarget(client);
// Set menu title. // Set menu title.
SetMenuTitle(menu_main, "%t\n ", "!zmenu title"); SetMenuTitle(menu_main, "%t\n ", "Menu main title");
// Initialize menu lines. // Initialize menu lines.
decl String:zadmin[64]; decl String:zadmin[64];

View File

@ -40,6 +40,9 @@ ModelsLoad()
*/ */
ModelsPrepModels() ModelsPrepModels()
{ {
// Initialize log boolean.
new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE);
// Get models file path. // Get models file path.
decl String:pathmodels[PLATFORM_MAX_PATH]; decl String:pathmodels[PLATFORM_MAX_PATH];
new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_MODELS, pathmodels); new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_MODELS, pathmodels);
@ -48,10 +51,7 @@ ModelsPrepModels()
if (!exists) if (!exists)
{ {
// Log failure and stop plugin. // Log failure and stop plugin.
if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE)) LogMessageFormatted(-1, "Models", "Config Validation", "Fatal error: Missing models file: \"%s\"", LOG_FORMAT_TYPE_FATALERROR, pathmodels);
{
LogMessageFormatted(-1, "Models", "Config Validation", "Missing models file: %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels);
}
} }
// If model array exists, then destroy it. // If model array exists, then destroy it.
@ -65,7 +65,7 @@ ModelsPrepModels()
// If array couldn't be created, then fail. // If array couldn't be created, then fail.
if (arrayModelsList == INVALID_HANDLE) 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; new modelcount;
@ -155,7 +155,7 @@ ModelsPrepModels()
x--; x--;
// Log missing model files. // 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); 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. // 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 none of the model paths are valid, then log and fail.
if (!modelvalidcount) 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); LogMessageFormatted(-1, "Models", "Config Validation", "No usable model paths in %s", LOG_FORMAT_TYPE_FATALERROR, pathmodels);
} }
@ -180,6 +183,9 @@ ModelsPrepModels()
*/ */
ModelsPrepDownloads() ModelsPrepDownloads()
{ {
// Initialize log boolean.
new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CORE);
// Get downloads file path. // Get downloads file path.
decl String:pathdownloads[PLATFORM_MAX_PATH]; decl String:pathdownloads[PLATFORM_MAX_PATH];
new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_DOWNLOADS, pathdownloads); new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_DOWNLOADS, pathdownloads);
@ -188,9 +194,9 @@ ModelsPrepDownloads()
if (!exists) if (!exists)
{ {
// Log error, then stop. // 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; return;
@ -201,9 +207,9 @@ ModelsPrepDownloads()
// If array couldn't be created, then fail. // If array couldn't be created, then fail.
if (arrayModelsList == INVALID_HANDLE) 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. // Backtrack one index, because we deleted it out from under the loop.
x--; 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; continue;
@ -248,5 +254,8 @@ ModelsPrepDownloads()
} }
// Log model validation info. // 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);
}
} }

View File

@ -875,3 +875,177 @@ Float:ClassGetJumpDistance(index, cachetype = ZR_CLASS_CACHE_PLAYER)
} }
return -1.0; 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;
}

View File

@ -97,3 +97,499 @@ public Action:Command_ClassDump(client, argc)
return Plugin_Handled; return Plugin_Handled;
} }
/**
* Modifies class data on one or more classes.
*
* Syntax: zr_class_modify <class> <attribute> <value> [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 <class> <attribute> <value> [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;
}

View File

@ -23,24 +23,42 @@
*/ */
ClassClientInit(client) 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. // Set default class indexes on the player.
ClassClientSetDefaultIndexes(client); ClassClientSetDefaultIndexes(client);
} }
} }
/**
* Called when all modules are done loading.
*/
ClassOnModulesLoaded()
{
// Set default classes on all player slots.
ClassClientSetDefaultIndexes();
}
ClassOnClientDisconnect(client) ClassOnClientDisconnect(client)
{ {
// Stop timers related to class attributes. // Disable class attributes with timers.
ClassHealthRegenStop(client);
ClassOverlayStop(client); ClassOverlayStop(client);
} }
ClassOnClientSpawn(client) ClassOnClientSpawn(client)
{ {
// Check if the player is alive.
if (!IsPlayerAlive(client)) 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; return;
} }
@ -97,7 +115,7 @@ ClassOnClientSpawn(client)
ClassOnClientDeath(client) ClassOnClientDeath(client)
{ {
// Reset certain attributes to not make spectating disorted. // Disable class attributes with timers.
ClassHealthRegenStop(client); ClassHealthRegenStop(client);
ClassOverlayStop(client); ClassOverlayStop(client);
@ -109,17 +127,13 @@ ClassOnClientInfected(client, bool:motherzombie = false)
{ {
new classindex = ClassGetActiveIndex(client); new classindex = ClassGetActiveIndex(client);
// Disable class attributes with timers.
ClassHealthRegenStop(client);
ClassOverlayStop(client);
// Update the players cache with zombie attributes. // Update the players cache with zombie attributes.
ClassReloadPlayerCache(client, classindex); ClassReloadPlayerCache(client, classindex);
// Apply the new attributes. // Apply the new attributes.
ClassApplyAttributes(client, motherzombie); ClassApplyAttributes(client, motherzombie);
} }
/* ------------------------------------
*
* PLAYER COMMANDS
*
* ------------------------------------
*/

View File

@ -96,6 +96,20 @@ ClassValidateAttributes(classindex)
{ {
flags += ZR_CLASS_FLAG_NAME; 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. // Description.
if (strlen(ClassData[classindex][class_description]) < ZR_CLASS_DESCRIPTION_MIN) 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]; 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)) 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. // Kill bonus.
@ -660,6 +674,9 @@ ClassGetDefaultSpawnClass(teamid, cachetype = ZR_CLASS_CACHE_MODIFIED)
decl String:classname[64]; decl String:classname[64];
new classindex; 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. // Get the default class name from the correct CVAR depending on teamid.
switch (teamid) switch (teamid)
{ {
@ -723,7 +740,7 @@ ClassGetDefaultSpawnClass(teamid, cachetype = ZR_CLASS_CACHE_MODIFIED)
// in the specified team, and log a warning. // in the specified team, and log a warning.
classindex = ClassGetFirstClass(teamid, _, cachetype); 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); 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 +749,7 @@ ClassGetDefaultSpawnClass(teamid, cachetype = ZR_CLASS_CACHE_MODIFIED)
if (ClassValidateIndex(classindex)) if (ClassValidateIndex(classindex))
{ {
// Log a warning. // 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); LogMessageFormatted(-1, "Classes", "DefaultSpawnClass", "Warning: The default class name \"%s\" does not exist or matches the team ID.", _, classname);
} }

View File

@ -156,40 +156,44 @@
#define ZR_CLASS_KNOCKBACK_MAX 30.0 #define ZR_CLASS_KNOCKBACK_MAX 30.0
#define ZR_CLASS_JUMP_HEIGHT_MIN -500.0 #define ZR_CLASS_JUMP_HEIGHT_MIN -500.0
#define ZR_CLASS_JUMP_HEIGHT_MAX 500.0 #define ZR_CLASS_JUMP_HEIGHT_MAX 500.0
#define ZR_CLASS_JUMP_DISTANCE_MIN -500.0 #define ZR_CLASS_JUMP_DISTANCE_MIN -5.0
#define ZR_CLASS_JUMP_DISTANCE_MAX 500.0 #define ZR_CLASS_JUMP_DISTANCE_MAX 5.0
/** /**
* @endsection * @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_ENABLED (1<<0)
#define ZR_CLASS_FLAG_DESCRIPTION (1<<1) #define ZR_CLASS_FLAG_TEAM (1<<1)
#define ZR_CLASS_FLAG_MODEL_PATH (1<<2) #define ZR_CLASS_FLAG_TEAM_DEFAULT (1<<2)
#define ZR_CLASS_FLAG_ALPHA_INITIAL (1<<3) #define ZR_CLASS_FLAG_NAME (1<<3)
#define ZR_CLASS_FLAG_ALPHA_DAMAGED (1<<4) #define ZR_CLASS_FLAG_DESCRIPTION (1<<4)
#define ZR_CLASS_FLAG_ALPHA_DAMAGE (1<<5) #define ZR_CLASS_FLAG_MODEL_PATH (1<<5)
#define ZR_CLASS_FLAG_OVERLAY_PATH (1<<6) #define ZR_CLASS_FLAG_ALPHA_INITIAL (1<<6)
#define ZR_CLASS_FLAG_FOV (1<<7) #define ZR_CLASS_FLAG_ALPHA_DAMAGED (1<<7)
#define ZR_CLASS_FLAG_NAPALM_TIME (1<<8) #define ZR_CLASS_FLAG_ALPHA_DAMAGE (1<<8)
#define ZR_CLASS_FLAG_IMMUNITY_MODE (1<<9) #define ZR_CLASS_FLAG_OVERLAY_PATH (1<<9)
#define ZR_CLASS_FLAG_IMMUNITY_AMOUNT (1<<10) #define ZR_CLASS_FLAG_NVGS (1<<10)
#define ZR_CLASS_FLAG_HEALTH (1<<11) #define ZR_CLASS_FLAG_FOV (1<<11)
#define ZR_CLASS_FLAG_HEALTH_REGEN_INTERVAL (1<<12) #define ZR_CLASS_FLAG_NAPALM_TIME (1<<12)
#define ZR_CLASS_FLAG_HEALTH_REGEN_AMOUNT (1<<13) #define ZR_CLASS_FLAG_IMMUNITY_MODE (1<<13)
#define ZR_CLASS_FLAG_INFECT_GAIN (1<<14) #define ZR_CLASS_FLAG_IMMUNITY_AMOUNT (1<<14)
#define ZR_CLASS_FLAG_KILL_BONUS (1<<15) #define ZR_CLASS_FLAG_NO_FALL_DAMAGE (1<<15)
#define ZR_CLASS_FLAG_SPEED (1<<16) #define ZR_CLASS_FLAG_HEALTH (1<<16)
#define ZR_CLASS_FLAG_KNOCKBACK (1<<17) #define ZR_CLASS_FLAG_HEALTH_REGEN_INTERVAL (1<<17)
#define ZR_CLASS_FLAG_JUMP_HEIGHT (1<<18) #define ZR_CLASS_FLAG_HEALTH_REGEN_AMOUNT (1<<18)
#define ZR_CLASS_FLAG_JUMP_DISTANCE (1<<19) #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 * @endsection
*/ */
/** /**
* Generic player attributes. * Generic player attributes.
*/ */
@ -231,7 +235,19 @@ enum ClassAttributes
Float:class_speed, Float:class_speed,
Float:class_knockback, Float:class_knockback,
Float:class_jump_height, 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; 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. * Stores what class that the player have selected, for each team.
*/ */
@ -300,6 +322,9 @@ new ClassPlayerNextAdminClass[MAXPLAYERS + 1];
*/ */
ClassLoad() ClassLoad()
{ {
// Initialize log boolean.
new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS);
// Make sure kvClassData is ready to use. // Make sure kvClassData is ready to use.
if (kvClassData != INVALID_HANDLE) if (kvClassData != INVALID_HANDLE)
{ {
@ -314,15 +339,17 @@ ClassLoad()
// If file doesn't exist, then log and stop. // If file doesn't exist, then log and stop.
if (!exists) if (!exists)
{ {
// Log failure. LogMessageFormatted(-1, "Classes", "Load", "Fatal error: Missing playerclasses config file \"%s\"", LOG_FORMAT_TYPE_FATALERROR, pathclasses);
if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS))
{
LogMessageFormatted(-1, "Classes", "Config Validation", "Missing playerclasses config file: %s", LOG_FORMAT_TYPE_FATALERROR, pathclasses);
}
return; 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. // Put file data into memory.
FileToKeyValues(kvClassData, pathclasses); FileToKeyValues(kvClassData, pathclasses);
@ -330,7 +357,7 @@ ClassLoad()
KvRewind(kvClassData); KvRewind(kvClassData);
if (!KvGotoFirstSubKey(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]; decl String:name[64];
@ -339,6 +366,7 @@ ClassLoad()
decl String:overlay_path[PLATFORM_MAX_PATH]; decl String:overlay_path[PLATFORM_MAX_PATH];
ClassCount = 0; ClassCount = 0;
new failedcount;
new ClassErrorFlags; new ClassErrorFlags;
// Loop through all classes and store attributes in the ClassData array. // Loop through all classes and store attributes in the ClassData array.
@ -347,7 +375,7 @@ ClassLoad()
if (ClassCount > ZR_CLASS_MAX) if (ClassCount > ZR_CLASS_MAX)
{ {
// Maximum classes reached. Write a warning and exit the loop. // 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); LogMessageFormatted(-1, "Classes", "Load", "Warning: Maximum classes reached (%d). Skipping other classes.", _, ZR_CLASS_MAX + 1);
} }
@ -411,10 +439,12 @@ ClassLoad()
// There's one or more invalid class attributes. Disable the class // There's one or more invalid class attributes. Disable the class
// and log an error message. // and log an error message.
ClassData[ClassCount][class_enabled] = false; 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); 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. // Update the counter.
@ -424,17 +454,26 @@ ClassLoad()
// Validate team requirements. // Validate team requirements.
if (!ClassValidateTeamRequirements()) 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. // Validate team default requirements.
if (!ClassValidateTeamDefaults()) 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. // Cache class data.
ClassReloadDataCache(); ClassReloadDataCache();
// Mark classes as valid.
ClassValidated = true;
// Log summary.
if (enablelog)
{
LogMessageFormatted(-1, "Classes", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", _, ClassCount, ClassCount - failedcount, failedcount);
}
} }
/** /**

View File

@ -57,6 +57,9 @@ bool:AmbientSoundsValidateConfig()
return false; return false;
} }
// Initialize log boolean.
new bool:enablelog = LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_AMBIENTSOUNDS);
// Get ambient sound file. // Get ambient sound file.
decl String:sound[SOUND_MAX_PATH]; decl String:sound[SOUND_MAX_PATH];
GetConVarString(g_hCvarsList[CVAR_AMBIENTSOUNDS_FILE], sound, sizeof(sound)); GetConVarString(g_hCvarsList[CVAR_AMBIENTSOUNDS_FILE], sound, sizeof(sound));
@ -66,7 +69,7 @@ bool:AmbientSoundsValidateConfig()
if (!FileExists(sound, true)) if (!FileExists(sound, true))
{ {
// Log invalid sound file error. // 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); 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) if (ambientvolume <= 0.0)
{ {
// Log invalid ambient sound volume error. // 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); 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) if (ambientlength <= 0.0)
{ {
// Log invalid ambient sound length error. // 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; return false;

View File

@ -36,6 +36,12 @@ ZSpawnOnMapStart()
*/ */
ZSpawnOnClientDisconnect(client) ZSpawnOnClientDisconnect(client)
{ {
// Check if client is a bot.
if (IsFakeClient(client))
{
return;
}
// Get client's unique serial number. // Get client's unique serial number.
new serial = GetClientSerial(client); new serial = GetClientSerial(client);