sm-zombiereloaded-3/src/zr/playerclasses/filtertools.inc

474 lines
15 KiB
PHP
Raw Normal View History

/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: filtertools.inc
* Description: Class system: Validating, getting indexes or lists
* Author: Richard Helgeby
*
* ============================================================================
*/
/**
* Validates the team requirements in a class cache and check that theres at
* least one class for each team. Minium team requirements are zombies and
* humans. The admin team is optinal.
*
* @param cachetype Optional. Specifies what class cache to validate. Options:
* ZR_CLASS_CACHE_ORIGINAL (default, unchanged class data),
* ZR_CLASS_CACHE_MODIFIED (modified class data).
* @return True if validation was successful, false otherwise.
*/
bool:ClassValidateTeamRequirements(cachetype = ZR_CLASS_CACHE_ORIGINAL)
{
new zombieindex;
new humanindex;
// Check if there are no classes.
if (ClassCount == 0)
{
return false;
}
// Test if a zombie and human class was found.
zombieindex = ClassGetFirstClass(ZR_CLASS_TEAM_ZOMBIES, _, cachetype);
humanindex = ClassGetFirstClass(ZR_CLASS_TEAM_HUMANS, _, cachetype);
if (zombieindex > -1 && humanindex > -1)
{
return true;
}
return false;
}
/**
* Validates all the class attributes in the original class data array, to
* check if they have invalid values.
*
* @param classindex The index of the class to validate.
* @return True if validation was successful, false otherwise.
*/
bool:ClassValidateAttributes(classindex)
{
return true;
// TODO: Manually check each attribute (hard coded). Better solutions?
}
/**
* Checks if the specified class index points to a existing class in the
* ClassData array.
*
* @param classindex The class index to validate.
* @return True if the class exist, false otherwise.
*/
bool:ClassValidateIndex(classindex)
{
if (ClassCount == 0)
{
return false;
}
if (classindex >= 0 && classid < ClassCount)
{
return true;
}
else
{
return false;
}
}
/**
* Compares the class team ID with a team ID.
*
* @param index Index of the class in a class cache or a client index,
* depending on the cache type specified.
* @param teamid The team ID to compare with the class.
* @param cachetype Optional. Specifies what class cache to read from. Options:
* ZR_CLASS_CACHE_ORIGINAL - Unchanced class data.
* ZR_CLASS_CACHE_MODIFIED (default) - Changed/newest class
* data.
* ZR_CLASS_CACHE_PLAYER - Player cache. If this one is used,
* index will be used as a client index.
* @return True if equal, false otherwise.
*/
bool:ClassTeamCompare(index, teamid, cachetype = ZR_CLASS_CACHE_MODIFIED)
{
switch (cachetype)
{
case ZR_CLASS_CACHE_ORIGINAL:
{
if (ClassData[index][class_team] == teamid)
{
return true;
}
}
case ZR_CLASS_CACHE_MODIFIED:
{
if (ClassDataCache[index][class_team] == teamid)
{
return true;
}
}
case ZR_CLASS_CACHE_PLAYER:
{
if (ClassPlayerCache[index][class_team] == teamid)
{
return true;
}
}
}
return false;
}
/**
* Gets the first class index of a class with the specified name (not a case
* sensitive search).
*
* @param name The name to search for.
* @param cachetype Optional. Specifies what class cache to read from. Options:
* ZR_CLASS_CACHE_ORIGINAL - Unchanced class data.
* ZR_CLASS_CACHE_MODIFIED (default) - Changed/newest class
* data.
* @return The class index if successful, -1 otherwise.
*/
ClassGetIndex(const String:name[], cachetype = ZR_CLASS_CACHE_MODIFIED)
{
decl String:current_name[64];
// Check if there are no classes.
if (ClassCount == 0)
{
return false;
}
// Loop through all classes.
for (new classindex = 0; classindex < ClassCount; classindex++)
{
// Get its name and compare it with the specified class name.
ClassesGetName(classindex, current_name, sizeof(current_name), cachetype);
if (strcmp(name, current_name, false) == 0)
{
return classindex;
}
}
// The class index wasn't found.
return -1;
}
/**
* Gets the currently active class index that the player is using.
* Note: Does not check if the player is dead.
*
* @param client The client index.
* @return The active class index. -1 on error or if a spectactor.
*/
ClassGetActiveIndex(client)
{
new teamid = GetClientTeam(client);
if (teamid == CS_TEAM_SPECTACTOR || teamid == CS_TEAM_NONE)
{
// No active team.
return -1;
}
if (IsPlayerHuman(client))
{
teamid = ZR_TEAM_HUMANS;
}
else
{
teamid = ZR_TEAM_ZOMBIES;
}
// TODO: How to detect that virtual admin team?
// Return the active class for the current team.
return ClassActive[client][teamid];
}
/**
* Gets all class indexes or from a specified team, and adds them to the
* specified array.
*
* @param array The destination array to add class indexes.
* @param teamfilter Optional. The team ID to filter. A negative value for
* no filter (default).
* @param ignoreEnabled Optional. Ignore the class's enabled attribute. Default
* is false.
* @param cachetype Optional. Specifies what class cache to read from.
* Options:
* ZR_CLASS_CACHE_ORIGINAL - Unchanced class data.
* ZR_CLASS_CACHE_MODIFIED (default) - Changed/newest
* class data.
* @return True on success. False on error or if no classes were added or
* found.
*/
bool:ClassAddToArray(Handle:array, teamfilter = -1, bool:ignoreEnabled = false, cachetype = ZR_CLASS_CACHE_MODIFIED)
{
// Validate the array.
if (array == INVALID_HANDLE)
{
return false;
}
// Check if there are no classes.
if (ClassCount == 0)
{
return false;
}
// Store a local boolean that says if the user specified a team filter or not.
new bool:has_filter = bool:(teamfilter >= 0);
new classes_added;
// Loop through all classes.
for (new classindex = 0; classindex < ClassCount; classindex++)
{
if (!ignoreEnabled && !ClassIsEnabled(classindex, cachetype))
{
// The class is disabled and the enabled attribute is NOT ignored.
// Skip to the next class.
continue;
}
// Check team filtering.
if (has_filter)
{
// Only add classes with matching team ID.
if (ClassGetTeamID(classindex, cachetype) == teamfilter)
{
// Team ID match. Add class index to array.
PushArrayCell(array, classindex);
classes_added++;
}
}
else
{
// No filter. Add any class to the array.
PushArrayCell(array, classindex);
classes_added++;
}
}
if (classes_added)
{
return true;
}
else
{
// No classes were found/added.
return false;
}
}
/**
* Gets a random class index from a specified team or from all classes.
*
* @param teamfilter Optional. The team ID to filter. A negative value for
* no filter (default).
* @param ignoreEnabled Optional. Ignore the class's enabled attribute. Default
* is false.
* @param cachetype Optional. Specifies what class cache to read from.
* Options:
* ZR_CLASS_CACHE_ORIGINAL - Unchanced class data.
* ZR_CLASS_CACHE_MODIFIED (default) - Changed/newest
* class data.
* @return The class index if successful, or -1 on error.
*/
ClassGetRandomClass(teamfilter = -1, bool:ignoreEnabled = false, cachetype = ZR_CLASS_CACHE_MODIFIED)
{
new Handle:classarray;
new arraycount;
new randnum;
classarray = CreateArray();
// Try to get a class list.
if (ClassAddToArray(classarray, teamfilter, ignoreEnabled, cachetype))
{
// Get a random index from the new class array.
arraycount = GetArraySize(classarray);
randnum = GetRandomInt(0, arraycount - 1);
// Return the value at the random index.
return GetArrayCell(classarray, randnum);
}
else
{
// Failed to get a random class.
return -1;
}
}
/**
* Gets the first class index, or the first class index with the specified team
* ID.
*
* @param teamfilter Optional. The team ID to filter. A negative value for
* no filter (default).
* @param ignoreEnabled Optional. Ignore the class's enabled attribute. Default
* is false.
* @param cachetype Optional. Specifies what class cache to read from.
* Options:
* ZR_CLASS_CACHE_ORIGINAL - Unchanced class data.
* ZR_CLASS_CACHE_MODIFIED (default) - Changed/newest
* class data.
* @return The first class index, or the first class index with the specified
* team ID. -1 on error.
*/
ClassGetFirstClass(teamfilter = -1, bool:ignoreEnabled = false, cachetype = ZR_CLASS_CACHE_MODIFIED)
{
// Check if there are no classes.
if (ClassCount == 0)
{
return false;
}
new bool:has_filter = bool:(teamfilter >= 0);
// Loop through all classes.
for (new classindex = 0; classindex < ClassCount; classindex++)
{
if (!ignoreEnabled && !ClassIsEnabled(classindex, cachetype))
{
continue;
}
if (has_filter)
{
if (teamfilter == ClassGetTeamID(classindex, cachetype))
{
// Team ID match. Return the class index.
return classindex;
}
}
else
{
// No team filter. Return the class index.
return classindex;
}
}
return -1;
}
/**
* Gets the default class index for the specified team configured to be used
* when players join the server.
*
* @param teamid The team ID.
* @param cachetype Optional. Specifies what class cache to read from. Options:
* ZR_CLASS_CACHE_ORIGINAL - Unchanced class data.
* ZR_CLASS_CACHE_MODIFIED (default) - Changed/newest class
* data.
* @return The class index of the default class for the specified team if
* successful. -1 on critical errors. Otherwise it will try to fall
* back on the first class in the specified team.
*/
ClassGetDefaultSpawnClass(teamid, cachetype = ZR_CLASS_CACHE_MODIFIED)
{
decl String:classname[64];
new classindex;
new Handle:classarray;
new arraycount;
// Get the default class name from the correct CVAR depending on teamid.
switch (teamid)
{
case ZR_CLASS_TEAM_ZOMBIES:
{
GetConVarString(gCvars[CVAR_CLASSES_DEFAULT_ZOMBIE], classname, sizeof(classname));
}
case ZR_CLASS_TEAM_HUMANS:
{
GetConVarString(gCvars[CVAR_CLASSES_DEFAULT_HUMAN], classname, sizeof(classname));
}
case ZR_CLASS_TEAM_ADMINS:
{
GetConVarString(gCvars[CVAR_CLASSES_DEFAULT_ADMIN], classname, sizeof(classname));
}
default:
{
// Invalid team ID.
return -1;
}
}
// Check if the class name isn't empty.
if (strlen(class_name) > 0)
{
// Check if the user set "random" as default class.
if (strcmp(classname, "random", false) == 0)
{
// Get a list of all classes with the specified team ID.
classindex = ClassGetRandomClass(teamid, cachetype);
// Validate the result, in case there were errors.
if (ClassValidateIndex(classindex))
{
return classindex;
}
else
{
// Invalid index. The ClassGetRandomClass function is pretty
// failsafe. So if we can't get a class index here, it's a
// critical error. No reason to fall back on other solutions.
return -1;
}
}
else
{
// The user set a spesific class.
// Try to get the class index with the specified class name.
classindex = ClassGetClassIndex(classname, cachetype);
// Validate the class index and check if the team IDs match.
if (ClassValidateIndex(classindex) && (teamid == ClassGetTeamID(classindex, cachetype)))
{
return classindex;
}
else
{
// The class index is invalid or the team IDs didn't match.
// Because it's user input, we'll fall back to the first class
// in the specified team, and log a warning.
classindex = ClassGetFirstClass(teamid, cachetype);
if (LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_CLASSES))
{
ZR_LogMessageFormatted(-1, "classes", "default spawn class", "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);
}
// Validate the new index.
if (ClassValidateIndex(classindex))
{
// Log a warning.
if (LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_CLASSES))
{
ZR_LogMessageFormatted(-1, "classes", "default spawn class", "Warning: The default class name \"%s\" does not exist or matches the team ID.", _, classname);
}
return classindex;
}
else
{
// Something went wrong. This is a critical error.
return -1;
}
}
}
}
else
{
// Blank class name, return a error code.
return -1;
}
}