sm-zombiereloaded-3/src/zr/hitgroups.inc
richard 3794251cc5 Updated all admin console commands to check if client is privileged (so group authentication works), instead of using RegAdminCmd. Minior fixes.
Changed admin teleport command to log target names.
Cached result of privilege check instead of calling function twice (zadmin menu).
Disabled old debug commands. Do not remove, we need them for testing later.
2009-10-26 23:17:22 +01:00

682 lines
21 KiB
SourcePawn

/*
* ============================================================================
*
* Zombie:Reloaded
*
* File: hitgroup.inc
* Type: Core
* Description: API for loading hitgroup specific settings.
*
* Copyright (C) 2009 Greyscale, Richard Helgeby
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* ============================================================================
*/
/**
* Maximum length for a hitgroup name
*/
#define HITGROUPS_MAX_LENGTH 32
/**
* @section Player hitgroup values.
*/
#define HITGROUP_GENERIC 0
#define HITGROUP_HEAD 1
#define HITGROUP_CHEST 2
#define HITGROUP_STOMACH 3
#define HITGROUP_LEFTARM 4
#define HITGROUP_RIGHTARM 5
#define HITGROUP_LEFTLEG 6
#define HITGROUP_RIGHTLEG 7
#define HITGROUP_GEAR 10
/**
* @endsection
*/
/**
* Hitgroup config data indexes.
*/
enum HitgroupsData
{
HITGROUPS_DATA_NAME = 0,
HITGROUPS_DATA_INDEX,
HITGROUPS_DATA_DAMAGE,
HITGROUPS_DATA_KNOCKBACK,
}
/**
* Array handle to store hitgroups data.
*/
new Handle:arrayHitgroups = INVALID_HANDLE;
/**
* Create commands related to config here.
*/
HitgroupsOnCommandsCreate()
{
// Create config admin commands.
RegConsoleCmd("zr_hitgroup", HitgroupsCommand, "Toggles or sets if a zombie's hitgroup can be damaged. Usage: zr_hitgroup <hitgroup name> [1/0]");
RegConsoleCmd("zr_hitgroup_enable_all", HitgroupsEnableAllCommand, "Enables all zombie hitgroups to be damaged. Usage: zr_hitgroup_enable_all");
RegConsoleCmd("zr_hitgroup_headshots_only", HitgroupsHeadshotsOnlyCommand, "Disables all zombie hitgroups but the head. Usage: zr_hitgroup_headshots_only");
}
/**
* Loads hitgroup data from file.
*/
HitgroupsLoad()
{
// Register config file.
ConfigRegisterConfig(File_Hitgroups, Structure_Keyvalue, CONFIG_FILE_ALIAS_HITGROUPS);
// If module is disabled, then stop.
new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]);
if (!hitgroups)
{
return;
}
// Get hitgroups config path.
decl String:pathhitgroups[PLATFORM_MAX_PATH];
new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_HITGROUPS, pathhitgroups);
// If file doesn't exist, then log and stop.
if (!exists)
{
// Log failure.
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Hitgroups, "Config Validation", "Missing hitgroups config file: %s", pathhitgroups);
return;
}
// Set the path to the config file.
ConfigSetConfigPath(File_Hitgroups, pathhitgroups);
// Load config from file and create array structure.
new bool:success = ConfigLoadConfig(File_Hitgroups, arrayHitgroups);
// Unexpected error, stop plugin.
if (!success)
{
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Hitgroups, "Config Validation", "Unexpected error encountered loading: %s", pathhitgroups);
return;
}
// Validate hitgroups config.
new size = GetArraySize(arrayHitgroups);
if (!size)
{
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Hitgroups, "Config Validation", "No usable data found in hitgroups config file: %s", pathhitgroups);
}
// Now copy data to array structure.
HitgroupsCacheData();
// Set config data.
ConfigSetConfigLoaded(File_Hitgroups, true);
ConfigSetConfigReloadFunc(File_Hitgroups, GetFunctionByName(GetMyHandle(), "HitgroupsOnConfigReload"));
ConfigSetConfigHandle(File_Hitgroups, arrayHitgroups);
}
/**
* Caches hitgroup data from file into arrays.
* Make sure the file is loaded before (ConfigLoadConfig) to prep array structure.
*/
HitgroupsCacheData()
{
// Get config's file path.
decl String:pathhitgroups[PLATFORM_MAX_PATH];
ConfigGetConfigPath(File_Hitgroups, pathhitgroups, sizeof(pathhitgroups));
new Handle:kvHitgroups;
new bool:success = ConfigOpenConfigFile(File_Hitgroups, kvHitgroups);
if (!success)
{
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Hitgroups, "Config Validation", "Unexpected error caching data from hitgroups config file: %s", pathhitgroups);
}
decl String:hitgroupname[HITGROUPS_MAX_LENGTH];
// x = array index
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
HitgroupsGetName(x, hitgroupname, sizeof(hitgroupname));
KvRewind(kvHitgroups);
if (!KvJumpToKey(kvHitgroups, hitgroupname))
{
LogEvent(false, LogType_Error, LOG_CORE_EVENTS, LogModule_Hitgroups, "Config Validation", "Couldn't cache hitgroup data for: %s (check hitgroup config)", hitgroupname);
continue;
}
// General
new index = KvGetNum(kvHitgroups, "index", -1);
// Damage
new bool:damage = ConfigKvGetStringBool(kvHitgroups, "damage", "yes");
// Knockback (module)
new Float:knockback = KvGetFloat(kvHitgroups, "knockback", 1.0);
new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, x);
// Push data into array.
PushArrayCell(arrayHitgroup, index); // Index: 1
PushArrayCell(arrayHitgroup, damage); // Index: 2
PushArrayCell(arrayHitgroup, knockback); // Index: 3
}
// We're done with this file now, so we can close it.
CloseHandle(kvHitgroups);
}
/**
* Called when configs are being reloaded.
*
* @param config The config being reloaded. (only if 'all' is false)
*/
public HitgroupsOnConfigReload(ConfigFile:config)
{
// Reload hitgroups config.
HitgroupsLoad();
}
/**
* Find the index at which the hitgroup's name is at.
*
* @param hitgroup The higroup name.
* @param maxlen (Only if 'overwritename' is true) The max length of the hitgroup name.
* @param overwritename (Optional) If true, the hitgroup given will be overwritten with the name from the config.
* @return The array index containing the given hitgroup name.
*/
stock HitgroupsNameToIndex(String:hitgroup[], maxlen = 0, bool:overwritename = false)
{
decl String:hitgroupname[HITGROUPS_MAX_LENGTH];
// x = Array index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
HitgroupsGetName(x, hitgroupname, sizeof(hitgroupname));
// If names match, then return index.
if (StrEqual(hitgroup, hitgroupname, false))
{
// If 'overwrite' name is true, then overwrite the old string with new.
if (overwritename)
{
// Copy config name to return string.
strcopy(hitgroup, maxlen, hitgroupname);
}
// Return this index.
return x;
}
}
// Name doesn't exist.
return -1;
}
/**
* Find the array index at which the hitgroup index is at.
*
* @param hitgroup The hitgroup index to search for.
* @return The array index that contains the given hitgroup index.
*/
stock HitgroupToIndex(hitgroup)
{
// x = Array index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
// Get hitgroup index at this array index.
new index = HitgroupsGetIndex(x);
// If hitgroup indexes match, then return array index.
if (hitgroup == index)
{
return x;
}
}
// Hitgroup index doesn't exist.
return -1;
}
/**
* Gets the name of a hitgroup at a given index. (static)
* @param index The hitgroup index.
* @param hitgroup The string to return name in.
* @param maxlen The max length of the string.
*/
stock HitgroupsGetName(index, String:hitgroup[], maxlen)
{
// Get array handle of hitgroup at given index.
new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, index);
// Get hitgroup name.
GetArrayString(arrayHitgroup, _:HITGROUPS_DATA_NAME, hitgroup, maxlen);
}
/**
* Retrieve hitgroup index. (static)
*
* @param index The array index.
* @return The hitgroup index.
*/
stock HitgroupsGetIndex(index)
{
// Get array handle of hitgroup at given index.
new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, index);
// Return hitgroup index of the hitgroup.
return GetArrayCell(arrayHitgroup, _:HITGROUPS_DATA_INDEX);
}
/**
* Set hitgroup damage value. (dynamic)
*
* @param index The array index.
* @param candamage True to allow damage to hitgroup, false to block damage.
*/
stock HitgroupsSetDamage(index, bool:candamage)
{
// Get array handle of hitgroup at given index.
new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, index);
// Return true if hitgroup can be damaged, false if not.
SetArrayCell(arrayHitgroup, _:HITGROUPS_DATA_DAMAGE, candamage);
}
/**
* Retrieve hitgroup damage value. (dynamic)
*
* @param index The array index.
* @return True if hitgroup can be damaged, false if not.
*/
stock bool:HitgroupsCanDamage(index)
{
// Get array handle of hitgroup at given index.
new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, index);
// Return true if hitgroup can be damaged, false if not.
return bool:GetArrayCell(arrayHitgroup, _:HITGROUPS_DATA_DAMAGE);
}
/**
* Set hitgroup knockback value. (dynamic)
*
* @param index The array index.
* @param knockback The knockback multiplier for the hitgroup.
*/
stock HitgroupsSetKnockback(index, Float:knockback)
{
// Get array handle of hitgroup at given index.
new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, index);
// Return the knockback multiplier for the hitgroup.
SetArrayCell(arrayHitgroup, _:HITGROUPS_DATA_KNOCKBACK, knockback);
}
/**
* Retrieve hitgroup knockback value. (dynamic)
*
* @param index The array index.
* @return The knockback multiplier of the hitgroup.
*/
stock Float:HitgroupsGetKnockback(index)
{
// Get array handle of hitgroup at given index.
new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, index);
// Return the knockback multiplier for the hitgroup.
return Float:GetArrayCell(arrayHitgroup, _:HITGROUPS_DATA_KNOCKBACK);
}
/**
* Sends list of hitgroups to client.
*
* @param client The client index.
* @return True if sent successfully, false if not.
*/
bool:HitgroupsMenuHitgroups(client)
{
// If hitgroups is disabled, then stop.
new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]);
if (!hitgroups)
{
return false;
}
// Create menu handle.
new Handle:menu_hitgroups = CreateMenu(HitgroupsMenuHitgroupsHandle);
// Set client as translation target.
SetGlobalTransTarget(client);
decl String:title[MENU_LINE_HUGE_LENGTH];
decl String:enableall[MENU_LINE_REG_LENGTH];
decl String:headshotsonly[MENU_LINE_REG_LENGTH];
// Format menu options.
Format(title, sizeof(title), "%t\n ", "Hitgroups menu hitgroups title");
Format(enableall, sizeof(enableall), "%t", "Hitgroups menu hitgroups enable all");
Format(headshotsonly, sizeof(headshotsonly), "%t\n ", "Hitgroups menu hitgroups headshots only");
// Add options to menu.
SetMenuTitle(menu_hitgroups, title);
AddMenuItem(menu_hitgroups, "Enable All", enableall);
AddMenuItem(menu_hitgroups, "Headshots Only", headshotsonly);
decl String:hitgroupoption[MENU_LINE_REG_LENGTH];
decl String:hitgroupcandamage[MENU_LINE_SMALL_LENGTH];
decl String:hitgroupid[4];
// x = Hitgroup index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
// Get hitgroup name.
HitgroupsGetName(x, hitgroupoption, sizeof(hitgroupoption));
IntToString(x, hitgroupid, sizeof(hitgroupid));
// Convert bool to "On/Off"
ConfigBoolToSetting(HitgroupsCanDamage(x), hitgroupcandamage, sizeof(hitgroupcandamage), false, client);
// Format "on/off" to the option.
Format(hitgroupoption, sizeof(hitgroupoption), "%s: %s", hitgroupoption, hitgroupcandamage);
// Add option to menu.
AddMenuItem(menu_hitgroups, hitgroupid, hitgroupoption);
}
// Create a "Back" button to the main admin menu.
SetMenuExitBackButton(menu_hitgroups, true);
// Send menu.
DisplayMenu(menu_hitgroups, client, MENU_TIME_FOREVER);
return true;
}
/**
* Called when client selects option in the infect clients menu, and handles it.
* @param menu_hitgroups Handle of the menu being used.
* @param action The action done on the menu (see menus.inc, enum MenuAction).
* @param client The client index.
* @param slot The slot index selected (starting from 0).
*/
public HitgroupsMenuHitgroupsHandle(Handle:menu_hitgroups, MenuAction:action, client, slot)
{
// Client selected an option.
if (action == MenuAction_Select)
{
switch(slot)
{
// Enable all hitgroups.
case 0:
{
// x = Hitgroup index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
// Enable hitgroup.
HitgroupsSetDamage(x, true);
}
// Tell the server that all hitgroups have been enabled.
TranslationPrintToChatAll(true, false, "Hitgroups command enable all successful");
}
// Headshots only.
case 1:
{
// x = Hitgroup index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
if (HitgroupsGetIndex(x) == HITGROUP_HEAD)
{
// Enable hitgroup.
HitgroupsSetDamage(x, true);
continue;
}
// Disable hitgroup.
HitgroupsSetDamage(x, false);
}
// Tell the server that headshots only been enabled.
TranslationPrintToChatAll(true, false, "Hitgroups command headshots only successful");
}
default:
{
// Get selected hitgroup index.
decl String:hitgroupid[4];
GetMenuItem(menu_hitgroups, slot, hitgroupid, sizeof(hitgroupid));
new hitgroup = StringToInt(hitgroupid);
// Toggle value.
new bool:hitgroupcandamage = HitgroupsCanDamage(hitgroup);
HitgroupsSetDamage(hitgroup, !hitgroupcandamage);
}
}
// Re-send menu.
HitgroupsMenuHitgroups(client);
}
// Client closed the menu.
if (action == MenuAction_Cancel)
{
// Client hit "Back" button.
if (slot == MenuCancel_ExitBack)
{
// Re-open admin menu.
ZAdminMenu(client);
}
}
// Client hit "Exit" button.
else if (action == MenuAction_End)
{
CloseHandle(menu_hitgroups);
}
}
/**
* Command callback (zr_hitgroup)
* Toggles or sets if a zombie's hitgroup can be damaged.
*
* @param client The client index.
* @param argc Argument count.
*/
public Action:HitgroupsCommand(client, argc)
{
// Check if privileged.
if (!ZRIsClientPrivileged(client, OperationType_Configuration))
{
TranslationReplyToCommand(client, "No access to command");
return Plugin_Handled;
}
// If module is disabled, then stop.
new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]);
if (!hitgroups)
{
TranslationReplyToCommand(client, "Feature is disabled");
return Plugin_Handled;
}
// If not enough arguments given, then stop.
if (argc < 1)
{
TranslationReplyToCommand(client, "Hitgroups command syntax");
TranslationReplyToCommand(client, "Hitgroups command related commands");
TranslationPrintToConsole(client, "Hitgroups command syntax names");
// Print all the hitgroup names in the client's console.
decl String:hitgroupname[HITGROUPS_MAX_LENGTH];
// x = Hitgroup index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
// Get the hitgroups name and print in console.
HitgroupsGetName(x, hitgroupname, sizeof(hitgroupname));
PrintToConsole(client, "* %s", hitgroupname);
}
return Plugin_Handled;
}
// Get hitgroup alias given.
decl String:target[HITGROUPS_MAX_LENGTH];
GetCmdArg(1, target, sizeof(target));
// If the hitgroup is invalid, then stop and tell client.
new hitgroup = HitgroupsNameToIndex(target, sizeof(target), true);
if (hitgroup == -1)
{
TranslationReplyToCommand(client, "Hitgroups command invalid hitgroup", target);
return Plugin_Handled;
}
new bool:hitgroupdamage;
// Check if value was given
decl String:value[4];
GetCmdArg(2, value, sizeof(value));
if (!value[0])
{
// Get the opposite value of the current hitgroup value.
hitgroupdamage = !HitgroupsCanDamage(hitgroup);
}
else
{
// Cast the given value to a bool.
hitgroupdamage = bool:StringToInt(value);
}
// Set new value in the hitgroup data cache.
HitgroupsSetDamage(hitgroup, hitgroupdamage);
// Tell client the new value of the hitgroup.
if (hitgroupdamage)
{
TranslationReplyToCommand(client, "Hitgroups command successful on", target);
}
else
{
TranslationReplyToCommand(client, "Hitgroups command successful off", target);
}
// Log action to game events.
LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_Hitgroups, "Headshots Toggle", "Admin \"%L\" toggled hitgroup \"%s\" to \"%d\". (zr_hitgroup)", client, target, hitgroupdamage);
return Plugin_Handled;
}
/**
* Command callback (zr_hitgroup_enable_all)
* Enables all zombie hitgroups to be damaged.
*
* @param client The client index.
* @param argc Argument count.
*/
public Action:HitgroupsEnableAllCommand(client, argc)
{
// Check if privileged.
if (!ZRIsClientPrivileged(client, OperationType_Configuration))
{
TranslationReplyToCommand(client, "No access to command");
return Plugin_Handled;
}
// If module is disabled, then stop.
new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]);
if (!hitgroups)
{
TranslationReplyToCommand(client, "Feature is disabled");
return Plugin_Handled;
}
// x = Hitgroup index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
// Set that hitgroup index to true for damage.
HitgroupsSetDamage(x, true);
}
// Tell the server that all hitgroups have been enabled.
TranslationPrintToChatAll(true, false, "Hitgroups command enable all successful");
// Log action to game events.
LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_Hitgroups, "Enable All", "Admin \"%L\" enabled all zombie hitgroups. (zr_hitgroup_enable_all)", client);
return Plugin_Handled;
}
/**
* Command callback (zr_hitgroup_enable_all)
* Disables all zombie hitgroups but the head.
*
* @param client The client index.
* @param argc Argument count.
*/
public Action:HitgroupsHeadshotsOnlyCommand(client, argc)
{
// Check if privileged.
if (!ZRIsClientPrivileged(client, OperationType_Configuration))
{
TranslationReplyToCommand(client, "No access to command");
return Plugin_Handled;
}
// If module is disabled, then stop.
new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]);
if (!hitgroups)
{
TranslationReplyToCommand(client, "Feature is disabled");
return Plugin_Handled;
}
// x = Hitgroup index.
new size = GetArraySize(arrayHitgroups);
for (new x = 0; x < size; x++)
{
// If this hitgroup is the head, then enable it and stop.
if (HitgroupsGetIndex(x) == HITGROUP_HEAD)
{
HitgroupsSetDamage(x, true);
continue;
}
// Set that hitgroup index to true for damage.
HitgroupsSetDamage(x, false);
}
// Tell the server that headshots only been enabled.
TranslationPrintToChatAll(true, false, "Hitgroups command headshots only successful");
// Log action to game events.
LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_Hitgroups, "Headshots Only", "Admin \"%L\" enabled headshots only. (zr_hitgroup_headshots_only)", client);
return Plugin_Handled;
}