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.
This commit is contained in:
richard 2009-05-10 18:49:47 +02:00
parent 969aa19b85
commit 4117519b39
9 changed files with 793 additions and 121 deletions

View File

@ -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"
}
}

View File

@ -202,6 +202,7 @@ public OnConfigsExecuted()
ClassLoad();
ConfigOnModulesLoaded();
ClassOnModulesLoaded();
}
/**

View File

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

View File

@ -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.

View File

@ -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;
}

View File

@ -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 <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)
{
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
*
* ------------------------------------
*/

View File

@ -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.

View File

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