Fixed humans winning on round end when no humans present, removed classes file cvar and made it use the config module, replaced SetFailState with LogMessageFormatted with fail flag, made the base config manipulator function.

This commit is contained in:
Greyscale 2009-05-01 07:09:18 +02:00
parent 8da309e4f4
commit 0404230fc8
10 changed files with 378 additions and 74 deletions

331
src/zr/config.inc Normal file
View File

@ -0,0 +1,331 @@
/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: config.inc
* Description: Config API and executing.
*
* ============================================================================
*/
/**
* @section List of config files under this modules control.
*/
#define CONFIG_FILE_MODELS 0
#define CONFIG_FILE_DOWNLOADS 1
#define CONFIG_FILE_PLAYERCLASSES 2
#define CONFIG_FILE_WEAPONS 3
#define CONFIG_FILE_WEAPONGROUPS 4
#define CONFIG_FILE_HITGROUPS 5
/**
* @endsection
*/
/**
* @section Config file flags.
*/
#define CONFIG_FILE_FLAG_MODELS 1
#define CONFIG_FILE_FLAG_DOWNLOADS 2
#define CONFIG_FILE_FLAG_PLAYERCLASSES 4
#define CONFIG_FILE_FLAG_WEAPONS 8
#define CONFIG_FILE_FLAG_WEAPONGROUPS 16
#define CONFIG_FILE_FLAG_HITGROUPS 32
/**
* @endsection
*/
/**
* The max length of a config/value string.
*/
#define CONFIG_OPTION_MAX_LENGTH 32
enum ConfigKeyvalueAction
{
Create, /** Create a key. */
Delete, /** Delete a key. */
Set, /** Modify setting of a key. */
Get, /** Get setting of a key. */
}
/**
* @section Global data handle initializations.
*/
new Handle:arrayModelsList = INVALID_HANDLE;
new Handle:kvClassData = INVALID_HANDLE;
new Handle:kvWeapons = INVALID_HANDLE;
new Handle:kvWeaponGroups = INVALID_HANDLE;
new Handle:kvHitgroups = INVALID_HANDLE;
/**
* Load plugin configs.
*/
ConfigLoad()
{
decl String:mapconfig[PLATFORM_MAX_PATH];
// Get map name and format into config path.
GetCurrentMap(mapconfig, sizeof(mapconfig));
Format(mapconfig, sizeof(mapconfig), "sourcemod/zombiereloaded/%s.cfg", mapconfig);
// Prepend cfg to path.
decl String:path[PLATFORM_MAX_PATH];
Format(path, sizeof(path), "cfg/%s", mapconfig);
// File doesn't exist, then stop.
if (!FileExists(path))
{
return;
}
// Execute config file.
ServerCommand("exec %s", mapconfig);
// Log action.
if (LogCheckFlag(LOG_CORE_EVENTS))
{
LogMessageFormatted(-1, "", "", "Executed map config file: %s.", LOG_FORMAT_TYPE_SIMPLE, mapconfig);
}
}
/**
* Load config file.
*
* @param file The cvar define of the path to the file.
* @return True if the file exists, false if not.
*/
bool:ConfigGetFilePath(CvarsList:cvar, String:path[])
{
// Get cvar's path.
decl String:filepath[PLATFORM_MAX_PATH];
GetConVarString(g_hCvarsList[cvar], filepath, sizeof(filepath));
// Build full path in return string.
BuildPath(Path_SM, path, PLATFORM_MAX_PATH, filepath);
return FileExists(path);
}
/**
* 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,
* using this function everywhere would be EXTREMELY inefficient.
*
* @param config Config index of config to modify. (see CONFIG_FILE_* defines)
* @param action Action to perform on keyvalue tree. (see enum ConfigKeyvalueAction)
* @param keys Array containing keys to traverse into.
* @param keysMax The size of the 'keys' array.
* @param setting (Optional) The name of the setting to modify.
* @param value (Optional) The new value to set.
* @param maxlen (Optional) The maxlength of the gotten value.
* @return True if the change was made successfully, false otherwise.
*/
bool:ConfigKeyvalueTreeSetting(config, ConfigKeyvalueAction:action = Create, const String:keys[][], keysMax, const String:setting[] = "", String:value[] = "", maxlen = 0)
{
// Retrieve handle of the keyvalue tree.
new Handle:hConfig = ConfigGetFileHandle(config);
// If handle is invalid, then stop.
if (hConfig == INVALID_HANDLE)
{
return false;
}
// Rewind keyvalue tree.
KvRewind(hConfig);
// x = keys index.
// Traverse into the keygroup, stop if it fails.
for (new x = 0; x < keysMax; x++)
{
// If key is empty, then break the loop.
if (!keys[x][0])
{
break;
}
// Try to jump to next level in the transversal stack, create key if specified.
new bool:exists = KvJumpToKey(hConfig, keys[x], (action == Create));
// If exists is false, then stop.
if (!exists)
{
// Key doesn't exist.
return false;
}
}
switch(action)
{
case Create:
{
if (!setting[0] || !value[0])
{
// We created the key already, so return true.
return true;
}
// Set new value.
KvSetString(hConfig, setting, value);
}
case Delete:
{
// Return deletion result.
return KvDeleteKey(hConfig, setting);
}
case Set:
{
// Set new value.
KvSetString(hConfig, setting, value);
}
case Get:
{
// Get current value.
KvGetString(hConfig, setting, value, maxlen);
}
}
// We successfully set or got the value.
return true;
}
/**
* Return handle to array or keygroup for globally stored data.
*
* @param configindex Index of the config. (see CONFIG_FILE_* defines)
*/
Handle:ConfigGetFileHandle(config)
{
switch(config)
{
case CONFIG_FILE_MODELS:
{
// Return model list array handle.
return arrayModelsList;
}
case CONFIG_FILE_DOWNLOADS:
{
// We don't store download data.
return INVALID_HANDLE;
}
case CONFIG_FILE_PLAYERCLASSES:
{
// Return class config keyvalue file handle.
return kvClassData;
}
case CONFIG_FILE_WEAPONS:
{
// Return weapon config keyvalue file handle.
return kvWeapons;
}
case CONFIG_FILE_WEAPONGROUPS:
{
// Return weapon groups config keyvalue file handle.
return kvWeaponGroups;
}
case CONFIG_FILE_HITGROUPS:
{
// Return hitgroups config keyvalue file handle.
return kvHitgroups;
}
}
// Invalid config index.
return INVALID_HANDLE;
}
/**
* Iterate through a file and store each line in an array.
*
* @param path Path to the file to iterate through.
* @return The handle of the array, don't forget to call CloseHandle
* on it when finished!
*/
Handle:ConfigLinesToArray(const String:path[])
{
new Handle:arrayLines = CreateArray(PLATFORM_MAX_PATH);
decl String:line[PLATFORM_MAX_PATH];
// Open file.
new Handle:hFile = OpenFile(path, "r");
// If file couldn't be opened, then stop.
if (hFile == INVALID_HANDLE)
{
return INVALID_HANDLE;
}
while(!IsEndOfFile(hFile))
{
// Get current line text.
ReadFileLine(hFile, line, sizeof(line));
// If line contains a ";", then stop.
if (StrContains(line, ";") > -1)
{
continue;
}
// Cut out comments at the end of a line.
if (StrContains(line, "//") > -1)
{
SplitString(line, "//", line, sizeof(line));
}
// Trim off whitespace.
TrimString(line);
// If line is empty, then stop.
if (!line[0])
{
continue;
}
// Push line into array.
PushArrayString(arrayLines, line);
}
// Close file handle.
CloseHandle(hFile);
// Return array handle.
return arrayLines;
}
/**
* Converts string of "yes" or "no" to a boolean value.
*
* @param option "yes" or "no" string to be converted.
* @return True if string is "yes", false otherwise.
*/
bool:ConfigSettingToBool(const String:option[])
{
// If option is equal to "yes," then return true.
if (StrEqual(option, "yes", false))
{
return true;
}
// Option isn't "yes."
return false;
}
/**
* Converts boolean value to "yes" or "no".
*
* @param bOption True/false value to be converted to "yes"/"no", respectively.
* @param option Variable to store "yes" or "no" in.
* @param maxlen Max length of return string, (can't be more than 4)
*/
ConfigBoolToSetting(bool:bOption, String:option[], maxlen)
{
// If option is true, then copy "yes" to return string.
if (bOption)
{
strcopy(option, maxlen, "yes");
}
// If option is false, then copy "no" to return string.
else
{
strcopy(option, maxlen, "no");
}
}

View File

@ -35,7 +35,6 @@ enum CvarsList
Handle:CVAR_CLASSES_DEFAULT_ZOMBIE,
Handle:CVAR_CLASSES_DEFAULT_HUMAN,
Handle:CVAR_CLASSES_DEFAULT_ADMIN,
Handle:CVAR_CLASSES_FILE,
Handle:CVAR_WEAPONS,
Handle:CVAR_WEAPONS_RESTRICT,
Handle:CVAR_WEAPONS_ZMARKET_BUYZONE,
@ -222,8 +221,6 @@ CvarsCreate()
// Old Desc:
g_hCvarsList[CVAR_CLASSES_DEFAULT_ADMIN] = CreateConVar("zr_classes_default_admin", "random", "");
// Old Desc: Default admin-only class selected for admins when they connect. Use \"random\" to select a random class, or blank to use class config defaults.
g_hCvarsList[CVAR_CLASSES_FILE] = CreateConVar("zr_classes_file", "configs/zr/playerclasses.txt", "");
// Old Desc: Class data file to read from, in Valves key/values format. The path is relative to the \"sourcemod\" folder.
// ===========================
// Weapons (core)

View File

@ -10,9 +10,10 @@
*/
/**
* Array to store keyvalue data.
* Keyvalue handle to store hitgroups data.
*
* @redir config.inc
*/
new Handle:kvHitgroups = INVALID_HANDLE;
/**
* @section Player hitgroup values.
@ -155,7 +156,7 @@ bool:HitgroupsCanDamageHitgroup(hitgroup)
KvGetString(kvHitgroups, "damage", damage, sizeof(damage), "yes");
// Return hitgroup's damage setting.
return ZRConfigSettingToBool(damage);
return ConfigSettingToBool(damage);
}
} while (KvGotoNextKey(kvHitgroups));
}

View File

@ -21,8 +21,9 @@
/**
* Array that stores a list of validated models.
*
* @redir config.inc
*/
new Handle:arrayModelsList = INVALID_HANDLE;
ModelsLoad()
{

View File

@ -233,7 +233,11 @@ enum ClassAttributes
Float:class_jump_distance
}
new Handle:kvClassData;
/**
* Keyvalue handle to store class data.
*
* @redir config.inc
*/
/**
* The original class data. This array only changed when class data is loaded.
@ -302,23 +306,30 @@ ClassLoad()
}
kvClassData = CreateKeyValues("classes");
decl String:classfile[PLATFORM_MAX_PATH];
GetConVarString(g_hCvarsList[CVAR_CLASSES_FILE], classfile, sizeof(classfile));
// Get weapons config path.
decl String:pathclasses[PLATFORM_MAX_PATH];
new bool:exists = ConfigGetFilePath(CVAR_CONFIG_PATH_PLAYERCLASSES, pathclasses);
// Try to load the class configuration file.
decl String:path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), classfile);
if (!FileToKeyValues(kvClassData, path))
// If file doesn't exist, then log and stop.
if (!exists)
{
SetFailState("Could not load class data file (\"%s\"). Check path in zr_classes_file in the configuration file.", path);
// Log failure.
if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS))
{
LogMessageFormatted(-1, "Classes", "Config Validation", "Missing playerclasses config file: %s", LOG_FORMAT_TYPE_FATALERROR, pathclasses);
}
return;
}
// Put file data into memory.
FileToKeyValues(kvClassData, pathclasses);
// Try to find the first class.
KvRewind(kvClassData);
if (!KvGotoFirstSubKey(kvClassData))
{
SetFailState("Cannot find any classes in \"%s\".", path);
LogMessageFormatted(-1, "Classes", "Config Validation", "Can't find any classes in %s", LOG_FORMAT_TYPE_FATALERROR, pathclasses);
}
decl String:name[64];
@ -401,7 +412,7 @@ ClassLoad()
ClassData[ClassCount][class_enabled] = false;
if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CLASSES))
{
LogMessageFormatted(-1, "Classes", "Load", "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);
}
}
@ -412,13 +423,13 @@ ClassLoad()
// Validate team requirements.
if (!ClassValidateTeamRequirements())
{
SetFailState("The class configuration doesn't match the team requirements.");
LogMessageFormatted(-1, "Classes", "Config Validation", "The class configuration doesn't match the team requirements.", LOG_FORMAT_TYPE_FATALERROR);
}
// Validate team default requirements.
if (!ClassValidateTeamDefaults())
{
SetFailState("Couldn't find a default class for one or more teams. At least one class per team must be marked as default.");
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);
}
// Cache class data.

View File

@ -252,7 +252,7 @@ RoundEndOutcome:RoundEndReasonToOutcome(reason)
public Action:RoundEndTimer(Handle:timer)
{
// If there aren't clients on both teams, then stop.
if (ZRTeamHasClients())
if (!ZRTeamHasClients())
{
return;
}

View File

@ -413,7 +413,7 @@ WeaponsMenuMarket(client)
decl String:togglebuyzone[64];
decl String:curSetting[8];
ZRBoolToConfigSetting(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]), curSetting, sizeof(curSetting));
ConfigBoolToSetting(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]), curSetting, sizeof(curSetting));
Format(togglebuyzone, sizeof(togglebuyzone), "%t", "Weapons menu market toggle buyzone", curSetting);

View File

@ -12,9 +12,10 @@
new Handle:gRestrictedWeapons = INVALID_HANDLE;
/**
* Array to store keyvalue data.
* Keyvalue handle to store weapon groups data.
*
* @redir config.inc
*/
new Handle:kvWeaponGroups = INVALID_HANDLE;
/**
* Array that stores the "HookID" to be later unhooked on player disconnect.
@ -125,7 +126,7 @@ RestrictDefaultRestrictions()
decl String:restrict[8];
KvGetString(kvWeapons, "restrict", restrict, sizeof(restrict), "no");
if (ZRConfigSettingToBool(restrict))
if (ConfigSettingToBool(restrict))
{
new WpnRestrictQuery:output = RestrictRestrict(weapon, display);
RestrictPrintRestrictOutput(0, output, display, true);

View File

@ -27,18 +27,19 @@
*/
enum WeaponsType
{
Type_Invalid = -1,
Type_Primary = 0,
Type_Secondary = 1,
Type_Melee = 2,
Type_Projectile = 3,
Type_Explosive = 4,
Type_Invalid = -1, /** Invalid weapon (slot). */
Type_Primary = 0, /** Primary weapon slot. */
Type_Secondary = 1, /** Secondary weapon slot. */
Type_Melee = 2, /** Melee (knife) weapon slot. */
Type_Projectile = 3, /** Projectile (grenades, flashbangs, etc) weapon slot. */
Type_Explosive = 4, /** Explosive (c4) weapon slot. */
}
/**
* Array to store keyvalue data.
* Keyvalue handle to store weapon data.
*
* @redir config.inc
*/
new Handle:kvWeapons = INVALID_HANDLE;
#include "zr/weapons/restrict"
#include "zr/weapons/markethandler"
@ -263,7 +264,7 @@ bool:WeaponsIsWeaponMenu(const String:weapon[])
KvGetString(kvWeapons, "menu", menu, sizeof(menu), "yes");
// Return weapon's setting.
return ZRConfigSettingToBool(menu);
return ConfigSettingToBool(menu);
}
} while (KvGotoNextKey(kvWeapons));
}

View File

@ -24,45 +24,6 @@ new dxLevel[MAXPLAYERS + 1];
*/
new bool:g_bZombieSpawned;
/**
* Converts string of "yes" or "no" to a boolean value.
*
* @param option "yes" or "no" string to be converted.
* @return True if string is "yes", false otherwise.
*/
bool:ZRConfigSettingToBool(const String:option[])
{
// If option is equal to "yes," then return true.
if (StrEqual(option, "yes", false))
{
return true;
}
// Option isn't "yes."
return false;
}
/**
* Converts boolean value to "yes" or "no".
*
* @param bOption True/false value to be converted to "yes"/"no", respectively.
* @param option Variable to store "yes" or "no" in.
* @param maxlen Max length of return string, (can't be more than 4)
*/
ZRBoolToConfigSetting(bool:bOption, String:option[], maxlen)
{
// If option is true, then copy "yes" to return string.
if (bOption)
{
strcopy(option, maxlen, "yes");
}
// If option is false, then copy "no" to return string.
else
{
strcopy(option, maxlen, "no");
}
}
/**
* Create an array populated with eligible clients to be zombie.
*