diff --git a/cstrike/addons/sourcemod/configs/zr/hitgroups.txt b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt new file mode 100644 index 0000000..075b4cc --- /dev/null +++ b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt @@ -0,0 +1,70 @@ +// Hitgroups +// +// Format +// +// "hitgroup index" // Index of the hitgroup (listed below) +// { +// "name" "name of hitgroup" // Redundant as of now, used for readability. +// "knockback" "1.0" (default) // The knockback multiplier for the hitgroup +// } +// +// Notes: +// +// A missing config setting will be assumed to be its default value (documented above). + +"hitgroups" // Counter-Strike: Source hitgroups +{ + "0" + { + "name" "Generic" + "knockback" "1.0" + } + + "1" + { + "name" "Head" + "knockback" "2.0" + } + + "2" + { + "name" "Chest" + "knockback" "1.3" + } + + "3" + { + "name" "Stomach" + "knockback" "1.2" + } + + "4" + { + "name" "Left Arm" + "knockback" "1.0" + } + + "5" + { + "name" "Right Arm" + "knockback" "1.0" + } + + "6" + { + "name" "Left Leg" + "knockback" "0.9" + } + + "7" + { + "name" "Right Leg" + "knockback" "0.9" + } + + "10" + { + "name" "Gear" + "knockback" "1.0" + } +} diff --git a/src/include/zr.inc b/src/include/zr.inc index c85d222..ebd4426 100644 --- a/src/include/zr.inc +++ b/src/include/zr.inc @@ -1,3 +1,3 @@ -// =============================== -// Zombie:Reloaded External API +// =============================== +// Zombie:Reloaded External API // =============================== \ No newline at end of file diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index f312008..c5bd428 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -36,6 +36,9 @@ // Weapons #include "zr/weapons/weapons" +// Hitgroups +#include "zr/hitgroups" + // Knockback #include "zr/knockback" @@ -126,7 +129,8 @@ public OnMapStart() // Forward event to modules. ClassLoad(); - WeaponsOnMapStart(); + WeaponsLoad(); + HitgroupsLoad(); Anticamp_Startup(); } diff --git a/src/zr/event.inc b/src/zr/event.inc index f66ae22..be9ed29 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -240,13 +240,15 @@ public Action:PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) new index = GetClientOfUserId(GetEventInt(event, "userid")); new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); + new hitgroup = GetEventInt(event, "hitgroup"); + new dmg_health = GetEventInt(event, "dmg_health"); decl String:weapon[32]; GetEventString(event, "weapon", weapon, sizeof(weapon)); // Forward event to modules. - KnockbackPlayerHurt(index, attacker, weapon, dmg_health); + KnockbackPlayerHurt(index, attacker, weapon, hitgroup, dmg_health); // Check if the attacker is a player. if (attacker != 0) diff --git a/src/zr/hitgroups.inc b/src/zr/hitgroups.inc new file mode 100644 index 0000000..d35df50 --- /dev/null +++ b/src/zr/hitgroups.inc @@ -0,0 +1,104 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: hitgroup.inc + * Description: API for loading hitgroup specific settings. + * Author: Greyscale, Richard Helgeby + * + * ============================================================================ + */ + +/** + * Array to store keyvalue data. + */ +new Handle:kvHitgroups = INVALID_HANDLE; + +/** + * @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 + */ + +HitgroupsClearData() +{ + // Load hitgroup data + if (kvHitgroups != INVALID_HANDLE) + { + CloseHandle(kvHitgroups); + } + + kvHitgroups = CreateKeyValues("hitgroups"); +} + +HitgroupsLoad() +{ + // Clear hitgroup data + HitgroupsClearData(); + + decl String:path[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, path, sizeof(path), "configs/zr/hitgroups.txt"); + + // If file isn't found, stop plugin + if (!FileToKeyValues(kvHitgroups, path)) + { + if (LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_HITGROUPS)) + { + ZR_LogMessageFormatted(-1, "Hitgroups", "Config Validation", "Missing file hitgroups.txt, disabling hitgroup-based modules.", LOG_FORMAT_TYPE_FULL); + } + + return; + } + + // Validate hitgroups config + HitgroupsValidateConfig(); +} + +HitgroupsValidateConfig() +{ + // If log flag check fails, don't log + if (!LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_HITGROUPS)) + { + return; + } + + KvRewind(kvHitgroups); + if (!KvGotoFirstSubKey(kvHitgroups)) + { + ZR_LogMessageFormatted(-1, "Hitgroups", "Config Validation", "No hitgroups listed in hitgroups.txt, disabling hitgroup-based modules.", LOG_FORMAT_TYPE_FULL); + } +} + +Float:HitgroupsGetHitgroupKnockback(hitgroup) +{ + // Reset keyvalue's traversal stack. + KvRewind(kvHitgroups); + if (KvGotoFirstSubKey(kvHitgroups)) + { + decl String:sHitgroup[4]; + + do + { + KvGetSectionName(kvHitgroups, sHitgroup, sizeof(sHitgroup)); + + // If this is the right hitgroup, then return knockback for it. + if (hitgroup == StringToInt(sHitgroup)) + { + return KvGetFloat(kvHitgroups, "knockback", 1.0); + } + } while (KvGotoNextKey(kvHitgroups)); + } + + return 1.0; +} \ No newline at end of file diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index aebf089..c97ce33 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -5,30 +5,15 @@ * Author: Greyscale * ==================== */ - -/** - * @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 - */ /** Player hurt event * @param client The victim index. (zombie) * @param attacker The attacker index. (human) * @param weapon The weapon used. + * @param hitgroup Hitgroup attacker has damaged. * @param dmg_health Damage done. */ -KnockbackPlayerHurt(client, attacker, const String:weapon[], dmg_health) +KnockbackPlayerHurt(client, attacker, const String:weapon[], hitgroup, dmg_health) { // Check if the attacker is a player. if (attacker != 0) @@ -68,14 +53,15 @@ KnockbackPlayerHurt(client, attacker, const String:weapon[], dmg_health) TR_GetEndPosition(clientloc); } - // Apply damage knockback multiplier - knockback *= float(dmg_health); - // Retrieve weapon knockback boost. new Float:boostWeapon = WeaponGetWeaponKnockback(weapon); - // Apply weapon knockback multiplier. - knockback *= boostWeapon; + // Retrieve hitgroup knockback boost. + new Float:boostHitgroup = HitgroupsGetHitgroupKnockback(hitgroup); + + // Apply all knockback multipliers + PrintToChatAll("Multipliers %f * %f * %f * %f", knockback, float(dmg_health), boostWeapon, boostHitgroup); + knockback *= float(dmg_health) * boostWeapon * boostHitgroup; // Apply knockback. KnockbackSetVelocity(client, attackerloc, clientloc, knockback); diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index 2304120..7121888 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -126,14 +126,16 @@ RestrictDefaultRestrictions() */ RestrictValidateWeaponGroups() { - // If log flag check fails, don't log + // If log flag check fails, don't log. if (!LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) { return; } + // Reset keygroup's traversal stack. KvRewind(kvWeaponGroups); + // Traverse into the keygroup. (weapon groups level) if (KvGotoFirstSubKey(kvWeaponGroups)) { decl String:weapongroup[WEAPONS_MAX_LENGTH]; @@ -143,12 +145,14 @@ RestrictValidateWeaponGroups() { KvGetSectionName(kvWeaponGroups, weapongroup, sizeof(weapongroup)); + // Traverse into the keygroup. (weapons level) if (KvGotoFirstSubKey(kvWeaponGroups)) { do { KvGetSectionName(kvWeaponGroups, groupweapon, sizeof(groupweapon)); + // If weapon is invalid, then log it. if (!WeaponsIsValidWeapon(groupweapon)) { ZR_LogMessageFormatted(-1, "Weapon Restrict", "Config Validation", "Invalid weapon \"%s\" in group \"%s\" configured in weapongroups.txt.", LOG_FORMAT_TYPE_ERROR, groupweapon, weapongroup); @@ -157,6 +161,7 @@ RestrictValidateWeaponGroups() KvGoBack(kvWeaponGroups); } + // If it couldn't traverse to the weapons, then log no weapons within group. else { ZR_LogMessageFormatted(-1, "Weapon Restrict", "Config Validation", "No weapons listed in weapon group \"%s\" in weapongroups.txt.", LOG_FORMAT_TYPE_ERROR, weapongroup); diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index 9bb1a9b..aa2b2aa 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -50,7 +50,7 @@ WeaponsClearData() /** * Loads weapon data from file. */ -WeaponsOnMapStart() +WeaponsLoad() { // Clear weapon data WeaponsClearData(); @@ -73,13 +73,13 @@ WeaponsOnMapStart() } // Validate weapons config - WeaponsValidateWeaponsConfig(); + WeaponsValidateConfig(); // Forward event to sub-module RestrictOnMapStart(); } -WeaponsValidateWeaponsConfig() +WeaponsValidateConfig() { // If log flag check fails, don't log if (!LogFlagCheck(LOG_CORE_EVENTS, LOG_MODULE_WEAPONS)) diff --git a/src/zr/zadmin.inc b/src/zr/zadmin.inc index 682aaf6..c68697e 100644 --- a/src/zr/zadmin.inc +++ b/src/zr/zadmin.inc @@ -11,10 +11,9 @@ new curMenuClass[MAXPLAYERS + 1]; bool:ZRAdminMenu(client) { - if (!GetAdminFlag(GetUserAdmin(client), Admin_Generic)) + if (!IsClientAdmin(client)) { ZR_PrintToChat(client, "Must be admin"); - return false; } @@ -520,6 +519,7 @@ ZRLogFlagsMenu(client) decl String:z_log_module_teleport[64]; decl String:z_log_module_classes[64]; decl String:z_log_module_weapons[64]; + decl String:z_log_module_hitgroups[64]; decl String:z_log_module_commands[64]; decl String:z_log_module_anticamp[64]; decl String:z_log_module_damagecontrol[64]; @@ -542,6 +542,7 @@ ZRLogFlagsMenu(client) Format(z_log_module_teleport, sizeof(z_log_module_teleport), "Teleporter (%d)", LogHasFlag(LOG_MODULE_TELEPORT)); Format(z_log_module_classes, sizeof(z_log_module_classes), "Classes (%d)", LogHasFlag(LOG_MODULE_CLASSES)); Format(z_log_module_weapons, sizeof(z_log_module_weapons), "Weapons (%d)", LogHasFlag(LOG_MODULE_WEAPONS)); + Format(z_log_module_hitgroups, sizeof(z_log_module_hitgroups), "Hitgroups (%d)", LogHasFlag(LOG_MODULE_HITGROUPS)); Format(z_log_module_commands, sizeof(z_log_module_commands), "Admin commands (%d)", LogHasFlag(LOG_MODULE_COMMANDS)); Format(z_log_module_anticamp, sizeof(z_log_module_anticamp), "Anticamp (%d)", LogHasFlag(LOG_MODULE_ANTICAMP)); Format(z_log_module_damagecontrol, sizeof(z_log_module_damagecontrol), "Damage control (suicides) (%d)", LogHasFlag(LOG_MODULE_DAMAGECONTROL)); @@ -573,7 +574,7 @@ ZRLogFlagsMenu(client) DisplayMenu(menu_log_flags, client, MENU_TIME_FOREVER); } -public ZRLogFlagsMenuHandle(Handle:menu_log_flags , MenuAction:action, client, slot) +public ZRLogFlagsMenuHandle(Handle:menu_log_flags, MenuAction:action, client, slot) { if (action == MenuAction_Select) { @@ -666,20 +667,25 @@ public ZRLogFlagsMenuHandle(Handle:menu_log_flags , MenuAction:action, client, s } case 17: { - ToggleLogFlag(LOG_MODULE_COMMANDS); + ToggleLogFlag(LOG_MODULE_HITGROUPS); ZRLogFlagsMenu(client); } case 18: { - ToggleLogFlag(LOG_MODULE_ANTICAMP); + ToggleLogFlag(LOG_MODULE_COMMANDS); ZRLogFlagsMenu(client); } case 19: { - ToggleLogFlag(LOG_MODULE_DAMAGECONTROL); + ToggleLogFlag(LOG_MODULE_ANTICAMP); ZRLogFlagsMenu(client); } case 20: + { + ToggleLogFlag(LOG_MODULE_DAMAGECONTROL); + ZRLogFlagsMenu(client); + } + case 21: { ToggleLogFlag(LOG_MODULE_OFFSETS); ZRLogFlagsMenu(client); @@ -695,7 +701,7 @@ public ZRLogFlagsMenuHandle(Handle:menu_log_flags , MenuAction:action, client, s } if (action == MenuAction_End) { - CloseHandle(menu_log_flags ); + CloseHandle(menu_log_flags); } } diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index e01e91c..0ccbfa2 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -55,9 +55,10 @@ enum ZTeam #define LOG_MODULE_OVERLAYS 65536 /** overlays.inc */ #define LOG_MODULE_TELEPORT 131072 /** teleport.inc */ #define LOG_MODULE_WEAPONS 262144 /** Weapons module - weapons/ *.inc */ -#define LOG_MODULE_ANTICAMP 524288 /** anticamp.inc */ -#define LOG_MODULE_DAMAGECONTROL 1048576 /** damagecontrol.inc */ -#define LOG_MODULE_OFFSETS 2097152 /** offsets.inc */ +#define LOG_MODULE_HITGROUPS 524288 /** hitgroups.inc */ +#define LOG_MODULE_ANTICAMP 1048576 /** anticamp.inc */ +#define LOG_MODULE_DAMAGECONTROL 2097152 /** damagecontrol.inc */ +#define LOG_MODULE_OFFSETS 4194304 /** offsets.inc */ /* * @endsection */ @@ -248,3 +249,21 @@ bool:IsClientPlayer(client) return false; } } + +/** + * Returns whether a player is a generic admin or not. + * + * @param client The client index. + * @return True if generic admin, false otherwise. + */ +bool:IsClientAdmin(client) +{ + if (GetAdminFlag(GetUserAdmin(client), Admin_Generic)) + { + return true; + } + else + { + return false; + } +}