From 0f8206596a709d10964191fdd664550bb7c44451 Mon Sep 17 00:00:00 2001 From: Greyscale Date: Thu, 28 May 2009 23:43:15 -0700 Subject: [PATCH] Recoded weapon restrictions, and made new way of storing data. (Arrays) * Removed ZMarket as an external plugin (to be integrated next commit) * Updated weapon configs, removed weapongroups.txt and moved weapons.txt to root zr config folder. * Moved offset finding to respective module, made new forward *OnOffsetsFound. * Updated weapons&hitgroups config file format to match playerclass.txt * Updated translations. * Recoded weapon restrict menu, commented out all zadmin options that don't quite work. * Added weaponammo module (not finished but existent) * Started zmarket module. --- .../addons/sourcemod/configs/zr/hitgroups.txt | 118 +- .../addons/sourcemod/configs/zr/weapons.txt | 713 +++++++++++ .../configs/zr/weapons/weapongroups.txt | 69 - .../sourcemod/configs/zr/weapons/weapons.txt | 225 ---- .../translations/zombiereloaded.phrases.txt | 133 +- .../zombiereloaded/zombiereloaded.base.cfg | 2 +- src/zombiereloaded.sp | 36 +- src/zr/account.inc | 18 + src/zr/antistick.inc | 20 +- src/zr/config.inc | 572 ++++++--- src/zr/cvars.inc | 12 +- src/zr/damage.inc | 13 +- src/zr/downloads.inc | 51 +- src/zr/hitgroups.inc | 254 ++-- src/zr/infect.inc | 8 +- src/zr/knockback.inc | 20 +- src/zr/menu.inc | 4 +- src/zr/models.inc | 47 +- src/zr/playerclasses/apply.inc | 4 +- src/zr/playerclasses/classmenus.inc | 8 - src/zr/playerclasses/clientoverlays.inc | 2 +- src/zr/playerclasses/playerclasses.inc | 20 +- src/zr/roundend.inc | 2 +- src/zr/sayhooks.inc | 2 - src/zr/tools.inc | 37 +- src/zr/translation.inc | 25 +- src/zr/weapons/markethandler.inc | 165 --- src/zr/weapons/menu_weapons.inc | 392 +++--- src/zr/weapons/restrict.inc | 1136 ++++++----------- src/zr/weapons/weaponalpha.inc | 2 +- src/zr/weapons/weaponammo.inc | 81 ++ src/zr/weapons/weapons.inc | 485 ++++--- src/zr/weapons/zmarket.inc | 47 + src/zr/zadmin.inc | 515 +------- 34 files changed, 2565 insertions(+), 2673 deletions(-) create mode 100644 cstrike/addons/sourcemod/configs/zr/weapons.txt delete mode 100644 cstrike/addons/sourcemod/configs/zr/weapons/weapongroups.txt delete mode 100644 cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt delete mode 100644 src/zr/weapons/markethandler.inc create mode 100644 src/zr/weapons/weaponammo.inc create mode 100644 src/zr/weapons/zmarket.inc diff --git a/cstrike/addons/sourcemod/configs/zr/hitgroups.txt b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt index 9edefc2..cb627fe 100644 --- a/cstrike/addons/sourcemod/configs/zr/hitgroups.txt +++ b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt @@ -4,7 +4,7 @@ // // "hitgroup index" // Index of the hitgroup (listed below) // { -// "name" "name of hitgroup" // Redundant as of now, used for readability. +// "index" "name of hitgroup" // Redundant as of now, used for readability. // "knockback" "1.0" (default) // The knockback multiplier for the hitgroup. // "damage" "yes" (default // Toggle damage on and off for this hitgroup. // } @@ -13,68 +13,130 @@ // // A missing config setting will be assumed to be its default value (documented above). +// ============================================================================ +// +// ZOMBIE:RELOADED +// Hitgroup configurations +// +// Check the hitgroup configuration section in the manual for detailed info. +// +// ============================================================================ +// +// SHORT DESCRIPTIONS +// +// Attribute: Values: Description: +// ---------------------------------------------------------------------------- +// index number The hitgroup index +// damage yes/no Allow damage to be done on this hitgroup for zombies. +// knockback decimal The knockback multiplier for this hitgroup. + "hitgroups" // Counter-Strike: Source hitgroups { - "0" + "Generic" { - "name" "Generic" - "knockback" "1.0" + // General + "index" "0" + + // Damage "damage" "yes" + + // Knockback + "knockback" "1.0" } - "1" + "Head" { - "name" "Head" + // General + "index" "1" + + // Damage + "damage" "yes" + + // Knockback "knockback" "2.0" - "damage" "yes" } - "2" + "Chest" { - "name" "Chest" + // General + "index" "2" + + // Damage + "damage" "yes" + + // Knockback "knockback" "1.3" - "damage" "yes" } - "3" + "Stomach" { - "name" "Stomach" + // General + "index" "3" + + // Damage + "damage" "yes" + + // Knockback "knockback" "1.2" - "damage" "yes" } - "4" + "Left Arm" { - "name" "Left Arm" + // General + "index" "4" + + // Damage + "damage" "yes" + + // Knockback "knockback" "1.0" - "damage" "yes" } - "5" + "Right Arm" { - "name" "Right Arm" + // General + "index" "5" + + // Damage + "damage" "yes" + + // Knockback "knockback" "1.0" - "damage" "yes" } - "6" + "Left Leg" { - "name" "Left Leg" + // General + "index" "6" + + // Damage + "damage" "yes" + + // Knockback "knockback" "0.9" - "damage" "yes" } - "7" + "Right Leg" { - "name" "Right Leg" + // General + "index" "7" + + // Damage + "damage" "yes" + + // Knockback "knockback" "0.9" - "damage" "yes" } - "10" + "Gear" { - "name" "Gear" - "knockback" "1.0" + // General + "index" "8" + + // Damage "damage" "yes" + + // Knockback + "knockback" "1.0" } } diff --git a/cstrike/addons/sourcemod/configs/zr/weapons.txt b/cstrike/addons/sourcemod/configs/zr/weapons.txt new file mode 100644 index 0000000..b9b0bad --- /dev/null +++ b/cstrike/addons/sourcemod/configs/zr/weapons.txt @@ -0,0 +1,713 @@ +// ============================================================================ +// +// ZOMBIE:RELOADED +// Weapon configurations +// +// Check the weapon configuration section in the manual for detailed info. +// +// ============================================================================ +// +// SHORT DESCRIPTIONS +// +// Attribute: Values: Description: +// ---------------------------------------------------------------------------- +// weapontype text The type of weapon it is. (List types, separate by ", " +// restrictdefault yes/no The default restricted status of the weapon on map start. +// toggleable yes/no Enable weapon to have restrictions toggled mid-game. +// ammotype text Ammo entity that belongs to weapons. (Don't change this) +// ammoprice number Price of ammo for this weapon. +// knockback decimal The knockback multiplier for the weapon. ['0.5' = half knockback | 2.0 = double] +// zmarketprice number The price of the weapon in ZMarket. (Defaulted to CS:S buymenu price) + +"weapons" // Counter-Strike: Source weapons +{ + "Glock" + { + // General + + "weapontype" "All, Pistol" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_9mm" + "ammoprice" "100" + + // Knockback (module) + + "knockback" "0.8" + + // ZMarket (module) + + "zmarketprice" "400" + } + + "USP" + { + // General + + "weapontype" "All, Pistol" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_45acp" + "ammoprice" "100" + + // Knockback (module) + + "knockback" "0.8" + + // ZMarket (module) + + "zmarketprice" "500" + } + + "P228" + { + // General + + "weapontype" "All, Pistol" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_357sig" + "ammoprice" "100" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "600" + + } + + "Deagle" + { + // General + + "weapontype" "All, Pistol" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_50ae" + "ammoprice" "100" + + // Knockback (module) + + "knockback" "1.2" + + // ZMarket (module) + + "zmarketprice" "650" + + } + + "Elite" + { + // General + + "weapontype" "All, Pistol" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_9mm" + "ammoprice" "100" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "800" + + } + + "Fiveseven" + { + // General + + "weapontype" "All, Pistol" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_57mm" + "ammoprice" "100" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "750" + + } + + "M3" + { + // General + + "weapontype" "All, Shotgun" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_buckshot" + "ammoprice" "300" + + // Knockback (module) + + "knockback" "0.9" // Remember that there are 8 pellets in 1 shot. + + // ZMarket (module) + + "zmarketprice" "1700" + + } + + "XM1014" + { + // General + + "weapontype" "All, Shotgun" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_buckshot" + "ammoprice" "300" + + // Knockback (module) + + "knockback" "0.8" // See above comment. + + // ZMarket (module) + + "zmarketprice" "3000" + + } + + "Mac10" + { + // General + + "weapontype" "All, SMG" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_45acp" + "ammoprice" "300" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "1400" + } + + "TMP" + { + // General + + "weapontype" "All, SMG" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_9mm" + "ammoprice" "300" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "1250" + } + + "MP5Navy" + { + // General + + "weapontype" "All, SMG" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_9mm" + "ammoprice" "300" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "1500" + } + + "UMP45" + { + // General + + "weapontype" "All, SMG" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_45acp" + "ammoprice" "300" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "1700" + } + + "P90" + { + // General + + "weapontype" "All, SMG" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_57mm" + "ammoprice" "300" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "2350" + } + + "Galil" + { + // General + + "weapontype" "All, Rifle" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_556mm" + "ammoprice" "500" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "2000" + } + + "Famas" + { + // General + + "weapontype" "All, Rifle" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_556mm" + "ammoprice" "500" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "2250" + } + + "AK47" + { + // General + + "weapontype" "All, Rifle" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_762mm" + "ammoprice" "500" + + // Knockback (module) + + "knockback" "1.2" + + // ZMarket (module) + + "zmarketprice" "2500" + } + + "M4A1" + { + // General + + "weapontype" "All, Rifle" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_556mm" + "ammoprice" "500" + + // Knockback (module) + + "knockback" "1.1" + + // ZMarket (module) + + "zmarketprice" "3100" + } + + "SG552" + { + // General + + "weapontype" "All, Rifle" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_556mm" + "ammoprice" "500" + + // Knockback (module) + + "knockback" "1.0" + + // ZMarket (module) + + "zmarketprice" "3500" + } + + "AUG" + { + // General + + "weapontype" "All, Rifle" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_762mm" + "ammoprice" "500" + + // Knockback (module) + + "knockback" "1.1" + + // ZMarket (module) + + "zmarketprice" "3500" + } + + "Scout" + { + // General + + "weapontype" "All, Sniper" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_762mm" + "ammoprice" "750" + + // Knockback (module) + + "knockback" "1.5" + + // ZMarket (module) + + "zmarketprice" "2750" + } + + "SG550" + { + // General + + "weapontype" "All, Sniper" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_556mm" + "ammoprice" "1000" + + // Knockback (module) + + "knockback" "1.3" + + // ZMarket (module) + + "zmarketprice" "4200" + } + + "G3SG1" + { + // General + + "weapontype" "All, Sniper" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_762mm" + "ammoprice" "1000" + + // Knockback (module) + + "knockback" "1.3" + + // ZMarket (module) + + "zmarketprice" "5000" + } + + "AWP" + { + // General + + "weapontype" "All, Sniper" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_338mag" + "ammoprice" "1000" + + // Knockback (module) + + "knockback" "1.8" + + // ZMarket (module) + + "zmarketprice" "4750" + } + + "M249" + { + // General + + "weapontype" "All, Machine Gun" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Weapon Ammo (core) + + "ammotype" "ammo_556mm_box" + "ammoprice" "1500" + + // Knockback (module) + + "knockback" "1.2" + + // ZMarket (module) + + "zmarketprice" "5750" + } + + "Knife" + { + // General + + "weapontype" "All, Melee" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "no" + + // Knockback (module) + + "knockback" "10.0" + } + + "HEGrenade" + { + // General + + "weapontype" "All, Projectile" + + // Restrict (core) + + "restrictdefault" "no" + "toggleable" "yes" + + // Knockback (module) + + "knockback" "6.0" + + // ZMarket (module) + + "zmarketprice" "300" + } + + "Flashbang" + { + // General + + "weapontype" "All, Projectile" + + // Restrict (core) + + "restrictdefault" "yes" + "toggleable" "yes" + + // ZMarket (module) + + "zmarketprice" "300" + } + + "Smokegrenade" + { + // General + + "weapontype" "All, Projectile" + + // Restrict (core) + + "restrictdefault" "yes" + "toggleable" "yes" + + // ZMarket (module) + + "zmarketprice" "300" + } + + "NVGs" + { + // General + + "weapontype" "All, Equipment" + + // Restrict (core) + + "restrictdefault" "yes" + "toggleable" "yes" + + // ZMarket (module) + + "zmarketprice" "1000" + } +} diff --git a/cstrike/addons/sourcemod/configs/zr/weapons/weapongroups.txt b/cstrike/addons/sourcemod/configs/zr/weapons/weapongroups.txt deleted file mode 100644 index 54e90c3..0000000 --- a/cstrike/addons/sourcemod/configs/zr/weapons/weapongroups.txt +++ /dev/null @@ -1,69 +0,0 @@ -// Weapon Groups -// (See list of weapons in weapons.txt) - -// Format -// -// -// "weapon group name" (how it appears in chat messages) -// { -// "weaponname" {} <-- To satisfy the standard format of a keyvalues file, -// without these brackets the weapon will be skipped. -// Invalid weapons are logged and skipped. -// } -// -// Notes: -// -// Invalid weapons (not in weapons.txt) will be logged in the error logs and ignored in-game - -"weapongroups" -{ - "Pistols" - { - "Glock" {} - "USP" {} - "P228" {} - "Deagle" {} - "Elite" {} - "Fiveseven" {} - } - - "Shotguns" - { - "M3" {} - "XM1014" {} - } - - "SMGs" - { - "Mac10" {} - "TMP" {} - "MP5Navy" {} - "UMP45" {} - "P90" {} - } - - "Rifles" - { - "Galil" {} - "Famas" {} - "AK47" {} - "M4A1" {} - "SG552" {} - "AUG" {} - } - - "Snipers" - { - "Scout" {} - "SG550" {} - "G3SG1" {} - "AWP" {} - } - - "Grenades" - { - "hegrenade" {} - "flashbang" {} - "smokegrenade" {} - } -} diff --git a/cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt b/cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt deleted file mode 100644 index 52219f0..0000000 --- a/cstrike/addons/sourcemod/configs/zr/weapons/weapons.txt +++ /dev/null @@ -1,225 +0,0 @@ -// Weapons -// -// Format -// -// "weaponname" // Name of the weapon (without weapon_ prefix) -// { -// "restrict" "no" (default) // Restricts the weapon on each map start -// "menu" "yes" (default) // Allows admins to toggle restriction with the menu -// "knockback" "1.0" (default) // The knockback multiplier for the weapon -// } -// -// Notes: -// -// This is a list of valid weapons for your server, unlisted weapons will -// be seen as invalid by the weapon restrict module. -// -// A config setting set to something other than "yes" or "no" will be assumed as "no." -// -// A missing config setting will be assumed to be its default value (documented above). -// -// Duplicate weapon entries will show up separately in restrict menu, but -// only the first one's options are used. - -"weapons" // Counter-Strike: Source weapons -{ - "Glock" - { - "restrict" "no" - "menu" "yes" - "knockback" "0.8" - } - - "USP" - { - "restrict" "no" - "menu" "yes" - "knockback" "0.8" - } - - "P228" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "Deagle" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.2" - } - - "Elite" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "Fiveseven" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "M3" - { - "restrict" "no" - "menu" "yes" - "knockback" "0.8" // Remember that there are 8 pellets in 1 shot. - } - - "XM1014" - { - "restrict" "no" - "menu" "yes" - "knockback" "0.8" // See above comment. - } - - "Mac10" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "TMP" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "MP5Navy" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "UMP45" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "P90" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "Galil" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "Famas" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "AK47" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.2" - } - - "M4A1" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.1" - } - - "SG552" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.0" - } - - "AUG" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.1" - } - - "Scout" - { - "restrict" "no" - "menu" "yes" - "knockback" "1.5" - } - - "SG550" - { - "restrict" "yes" - "menu" "yes" - "knockback" "1.3" - } - - "G3SG1" - { - "restrict" "yes" - "menu" "yes" - "knockback" "1.3" - } - - "AWP" - { - "restrict" "yes" - "menu" "yes" - "knockback" "1.8" - } - - "M249" - { - "restrict" "yes" - "menu" "yes" - "knockback" "1.2" - } - - "hegrenade" - { - "restrict" "no" - "menu" "yes" - "knockback" "6.0" - } - - "flashbang" - { - "restrict" "yes" - "menu" "no" - } - - "smokegrenade" - { - "restrict" "yes" - "menu" "no" - } - - "Knife" - { - "restrict" "no" - "menu" "no" - "knockback" "15.0" - } - - "NVGs" - { - "restrict" "yes" - "menu" "no" - } -} diff --git a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt index 6c40b3c..3b72035 100644 --- a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt +++ b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt @@ -84,8 +84,8 @@ "Config command reload syntax" { - "#format" "{1:s},{2:s},{3:s},{4:s},{5:s},{6:s}" - "en" "Syntax: zr_reloadconfig - Reloads a config file.\n File Aliases:\n * \"{1}\"\n * \"{2}\"\n * \"{3}\"\n * \"{4}\"\n * \"{5}\"\n * \"{6}\"" + "#format" "{1:s},{2:s},{3:s},{4:s},{5:s}" + "en" "Syntax: zr_reloadconfig - Reloads a config file.\n File Aliases:\n * \"{1}\"\n * \"{2}\"\n * \"{3}\"\n * \"{4}\"\n * \"{5}\"" } "Config command reload invalid" @@ -289,46 +289,52 @@ "en" "Weapon @green\"{1}\" @defaulthas been unrestricted." } - "Restrict weapon failed" + "Restrict weapon stopped" { "#format" "{1:s}" "en" "Weapon @green\"{1}\" @defaultis already restricted." } - "Unrestrict weapon failed" + "Unrestrict weapon stopped" { "#format" "{1:s}" "en" "Weapon @green\"{1}\" @default has no restrictions set." } - "Restrict custom weapon group" + "Restrict weapon type" { - "#format" "{1:s},{2:s}" - "en" "Weapon group @green\"{1}\" ({2}) @defaulthas been restricted." + "#format" "{1:s}" + "en" "Weapons of type @green\"{1}\" @defaulthave been restricted." } - "Unrestrict custom weapon group" + "Unrestrict weapon type" { - "#format" "{1:s},{2:s}" - "en" "Weapon group @green\"{1}\" ({2}) @defaulthas been unrestricted." + "#format" "{1:s}" + "en" "Weapons of type @green\"{1}\" @defaulthave been unrestricted." } - "Restrict custom weapon group failed" + "Restrict weapon type stopped" { - "#format" "{1:s},{2:s}" - "en" "Weapon group @green\"{1}\" ({2}) @defaultis already restricted." + "#format" "{1:s}" + "en" "Weapons of type @green\"{1}\" @defaultare all already restricted." } - "Unrestrict custom weapon group failed" + "Unrestrict weapon type stopped" { - "#format" "{1:s},{2:s}" - "en" "Weapon group @green\"{1}\" ({2}) @defaulthas no restrictions set." + "#format" "{1:s}" + "en" "Weapons of type @green\"{1}\" @defaulthave no restrictions set." + } + + "Restrict weapon untoggleable" + { + "#format" "{1:s}" + "en" "Weapon @green\"{1}\" @defaultmay not have its restrictions toggled." } "Weapon invalid" { "#format" "{1:s}" - "en" "Weapon @green\"{1}\" @defaultis an invalid weapon name." + "en" "Weapon @green\"{1}\" @defaultis an invalid weapon (type) name." } "Weapon is restricted" @@ -338,29 +344,28 @@ "ru" "Оружие @green{1} @default запрещено." } - // Market + // ZMarket "Market title" { - "en" "Available Weapons:" + "en" "" } "Market rebuy" { - "en" "Rebuy" - "ru" "Купить снова" + "en" "" } // Commands "Weapons command restrict syntax" { - "en" "Syntax: zr_restrict (\"weapon_\" prefix is ignored)" + "en" "Restricts a weapon or a weapon type. Usage: zr_restrict [weapon2|weapontype2] ..." } "Weapons command unrestrict syntax" { - "en" "Syntax: zr_unrestrict (\"weapon_\" prefix is ignored)" + "en" "Unrestricts a weapon or a weapon type. Usage: zr_unrestrict [weapon2|weapontype2] ..." } // Menu @@ -370,56 +375,48 @@ "en" "Weapons Management" } - "Weapons menu main toggle weapon restrict" + "Weapons menu main restrict" { - "en" "Toggle Weapon Restriction" + "en" "Weapon Restrictions" } - "Weapons menu main toggle weapon group restrict" + "Weapons menu main market" { - "en" "Toggle Weapon Group Restriction" + "en" "ZMarket" } - "Weapons menu main market" // Option disabled if ZMarket isn't installed + "Weapons menu types title" { - "en" "ZMarket Options" + "en" "Weapon Restrictions\nSelect Weapon Type:" } - "Weapons menu weapons weapon title" - { - "en" "Toggle Restrictions:\n * = restricted" - } - - "Weapons menu weapons group title" - { - "en" "Access Weapon Group:\n * = Partially restricted\n ** = Fully restricted" - } - - "Weapons menu weapon group title" + "Weapons menu types type title" { "#format" "{1:s}" - "en" "Modify Restrictions:\n Current Weapon Group: {1}\n * = restricted" + "en" "Weapon Restrictions\nWeapon Type: {1}\n[] = Restricted" } - "Weapons menu market title" - { - "en" "Toggle Market Settings:" - } - - "Weapons menu market toggle buyzone" + "Weapons menu types restrict all" { "#format" "{1:s}" - "en" "Buyzone Only (Current: {1})" + "en" "Restrict weapon type {1}" } - "Weapons menu weapon group restrict all" + "Weapons menu types unrestrict all" { - "en" "Restrict All Group Weapons" + "#format" "{1:s}" + "en" "Unrestrict weapon type {1}\n " } - "Weapons menu weapon group unrestrict all" + "Weapons menu zmarket title" { - "en" "Unrestrict All Group Weapons" + "en" "ZMarket\nSelect Setting:" + } + + "Weapons menu zmarket buyzone" + { + "#format" "{1:s}" + "en" "Buyzone Only - {1}" } // =========================== @@ -556,37 +553,7 @@ "!zadmin main title" { - "en" "ZAdmin Menu:" - } - - "!zadmin main knockbackm" - { - "en" "Modify Knockback Multiplier" - } - - "!zadmin main knockback" - { - "en" "Modify Class Knockback" - } - - "!zadmin main nvgs" - { - "en" "Modify Nightvision Options" - } - - "!zadmin main infect" - { - "en" "Infect a Player" - } - - "!zadmin main spawn" - { - "en" "Spawn All Players" - } - - "!zadmin main tele" - { - "en" "ZTele Commands" + "en" "ZAdmin\n Select Category:" } "!zadmin main weapons" diff --git a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.base.cfg b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.base.cfg index 8680c29..249e294 100644 --- a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.base.cfg +++ b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.base.cfg @@ -4,7 +4,7 @@ // * Zombie:Reloaded // * // * File: zombiereloaded.cfg -// * Type: Core +// * Type: Config // * Description: Plugin cvar configuration. // * // * ============================================================================ diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 5183cf5..f77f2d4 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -16,9 +16,6 @@ #include #include -#undef REQUIRE_PLUGIN -#include - #define VERSION "3.0-dev" // Core includes. @@ -103,35 +100,7 @@ public OnPluginStart() WeaponsInit(); SayHooksInit(); EventInit(); - MarketInit(); -} - -/** - * Library is being removed. - * - * @param name The name of the library. - */ -public OnLibraryRemoved(const String:name[]) -{ - // If market is being removed, then set variable to false. - if (StrEqual(name, "market", false)) - { - g_bMarket = false; - } -} - -/** - * Library is being added. - * - * @param name The name of the library. - */ -public OnLibraryAdded(const String:name[]) -{ - // If market is being added, then set variable to true. - if (StrEqual(name, "market", false)) - { - g_bMarket = true; - } + ZMarketInit(); } /** @@ -162,7 +131,7 @@ public OnMapEnd() */ public OnConfigsExecuted() { - // Forward event to modules. + // Forward event to modules. (OnConfigsExecuted) ConfigLoad(); ModelsLoad(); DownloadsLoad(); @@ -173,6 +142,7 @@ public OnConfigsExecuted() SEffectsLoad(); ClassLoad(); + // Forward event to modules. (OnModulesLoaded) ConfigOnModulesLoaded(); ClassOnModulesLoaded(); } diff --git a/src/zr/account.inc b/src/zr/account.inc index 188b87b..4ac421a 100644 --- a/src/zr/account.inc +++ b/src/zr/account.inc @@ -15,6 +15,24 @@ */ #define ACCOUNT_CASH_MAX 16000 +/** + * Variable to store account offset value. + */ +new g_iToolsAccount; + +/** + * Find account-specific offsets here. + */ +AccountOnOffsetsFound() +{ + // If offset "m_iAccount" can't be found, then stop the plugin. + g_iToolsAccount = FindSendPropInfo("CCSPlayer", "m_iAccount"); + if (g_iToolsAccount == -1) + { + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Account", "Offsets", "Offset \"CCSPlayer::m_iAccount\" was not found."); + } +} + /** * Client is spawning into the game. * diff --git a/src/zr/antistick.inc b/src/zr/antistick.inc index 5904395..8b441f6 100644 --- a/src/zr/antistick.inc +++ b/src/zr/antistick.inc @@ -29,11 +29,29 @@ * @endsection */ +/** + * Variable to store antistick offset value. + */ +new g_iToolsCollisionGroup; + /** * Handle to keep track of AntiStickTimer. */ new Handle:tAntiStick = INVALID_HANDLE; +/** + * Find antistick-specific offsets here. + */ +AntiStickOnOffsetsFound() +{ + // If offset "m_CollisionGroup" can't be found, then stop the plugin. + g_iToolsCollisionGroup = FindSendPropInfo("CBaseEntity", "m_CollisionGroup"); + if (g_iToolsCollisionGroup == -1) + { + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CBaseEntity::m_CollisionGroup\" was not found."); + } +} + /** * Map is starting. */ @@ -191,4 +209,4 @@ AntiStickClientCollisionGroup(client, bool:apply = true, collisiongroup = 0) } return GetEntData(client, g_iToolsCollisionGroup, 1); -} +} \ No newline at end of file diff --git a/src/zr/config.inc b/src/zr/config.inc index ef15d41..d425d85 100644 --- a/src/zr/config.inc +++ b/src/zr/config.inc @@ -22,23 +22,31 @@ #define CONFIG_FILE_ALIAS_DOWNLOADS "downloads" #define CONFIG_FILE_ALIAS_CLASSES "classes" #define CONFIG_FILE_ALIAS_WEAPONS "weapons" -#define CONFIG_FILE_ALIAS_WEAPONGROUPS "weapongroups" #define CONFIG_FILE_ALIAS_HITGROUPS "hitgroups" /** * @endsection */ +/** + * List of config formats used by the plugin. + */ +enum ConfigStructure +{ + Structure_List, /** Config is structured as a simple list of strings. */ + Structure_Keyvalue, /** Config is a keyvalue structure */ +} + /** * List of config files used by the plugin. */ enum ConfigFile { - ConfigInvalid = -1, /** Invalid config file. */ - ConfigModels, /** /configs/zr/models.txt (default) */ - ConfigDownloads, /** /configs/zr/downloads.txt (default) */ - ConfigClasses, /** /configs/zr/playerclasses.txt (default) */ - ConfigWeapons, /** /configs/zr/weapons/weapons.txt/weapongroups.txt (default) */ - ConfigHitgroups, /** /configs/zr/hitgroups.txt (default) */ + File_Invalid = -1, /** Invalid config file. */ + File_Models, /** /configs/zr/models.txt (default) */ + File_Downloads, /** /configs/zr/downloads.txt (default) */ + File_Classes, /** /configs/zr/playerclasses.txt (default) */ + File_Weapons, /** /configs/zr/weapons.txt (default) */ + File_Hitgroups, /** /configs/zr/hitgroups.txt (default) */ } /** @@ -46,11 +54,12 @@ enum ConfigFile */ enum ConfigData { - bool:ConfigLoaded, /** True if config is loaded, false if not. */ - Function:ConfigReloadFunc, /** Function to call to reload config. */ - Handle:ConfigHandle, /** Handle of the config file. */ - String:ConfigPath[PLATFORM_MAX_PATH], /** Full path to config file. */ - String:ConfigAlias[CONFIG_MAX_LENGTH], /** Config file alias, used for client interaction. */ + bool: Data_Loaded, /** True if config is loaded, false if not. */ + ConfigStructure: Data_Structure, /** Format of the config */ + Function: Data_ReloadFunc, /** Function to call to reload config. */ + Handle: Data_Handle, /** Handle of the config file. */ + String: Data_Path[PLATFORM_MAX_PATH], /** Full path to config file. */ + String: Data_Alias[CONFIG_MAX_LENGTH], /** Config file alias, used for client interaction. */ } /** @@ -61,24 +70,14 @@ new g_ConfigData[ConfigFile][ConfigData]; /** * Actions to use when working on key/values. */ -enum ConfigKeyvalueAction +enum ConfigKvAction { - ConfigKVCreate, /** Create a key. */ - ConfigKVDelete, /** Delete a key. */ - ConfigKVSet, /** Modify setting of a key. */ - ConfigKVGet, /** Get setting of a key. */ + KvAction_Create, /** Create a key. */ + KvAction_KVDelete, /** Delete a key. */ + KvAction_KVSet, /** Modify setting of a key. */ + KvAction_KVGet, /** Get setting of a key. */ } -/** - * @section Global data handle initializations. - */ -new Handle:arrayModelsList = INVALID_HANDLE; -new Handle:arrayDownloadsList = INVALID_HANDLE; -new Handle:kvClassData = INVALID_HANDLE; -new Handle:kvWeapons = INVALID_HANDLE; -new Handle:kvWeaponGroups = INVALID_HANDLE; -new Handle:kvHitgroups = INVALID_HANDLE; - /** * Create commands related to config here. */ @@ -157,20 +156,20 @@ ConfigOnModulesLoaded() /** * Used by modules that rely on configs to register their config file info. + * (Don't forget to set 'loaded' to 'true' (ConfigSetConfigLoaded) in config load function) * * @param file Config file entry to register. - * @param loaded True if the config should be loaded, false if not. - * @param path (Optional) Full path to config file. - * @param alias (Optional) Config file alias, used for client interaction. + * @param alias Config file alias, used for client interaction. */ -stock ConfigRegisterConfig(ConfigFile:file, bool:loaded, Function:reloadfunc, Handle:filehandle = INVALID_HANDLE, const String:path[] = "", const String:alias[] = "") +stock ConfigRegisterConfig(ConfigFile:file, ConfigStructure:structure, const String:alias[] = "") { // Copy file info to data container. - g_ConfigData[file][ConfigLoaded] = loaded; - g_ConfigData[file][ConfigHandle] = filehandle; - g_ConfigData[file][ConfigReloadFunc] = reloadfunc; - strcopy(g_ConfigData[file][ConfigPath], PLATFORM_MAX_PATH, path); - strcopy(g_ConfigData[file][ConfigAlias], CONFIG_MAX_LENGTH, alias); + g_ConfigData[file][Data_Loaded] = false; + g_ConfigData[file][Data_Structure] = structure; + g_ConfigData[file][Data_Handle] = INVALID_HANDLE; + g_ConfigData[file][Data_ReloadFunc] = INVALID_FUNCTION; + strcopy(g_ConfigData[file][Data_Path], PLATFORM_MAX_PATH, ""); + strcopy(g_ConfigData[file][Data_Alias], CONFIG_MAX_LENGTH, alias); } /** @@ -182,7 +181,19 @@ stock ConfigRegisterConfig(ConfigFile:file, bool:loaded, Function:reloadfunc, Ha stock ConfigSetConfigLoaded(ConfigFile:config, bool:loaded) { // Set load state. - g_ConfigData[config][ConfigLoaded] = loaded; + g_ConfigData[config][Data_Loaded] = loaded; +} + +/** + * Set the structure type of a config file entry. + * + * @param config Config file to set structure type of. + * @param structure Structure to set as. + */ +stock ConfigSetConfigStructure(ConfigFile:config, ConfigStructure:structure) +{ + // Set load state. + g_ConfigData[config][Data_Structure] = structure; } /** @@ -194,7 +205,7 @@ stock ConfigSetConfigLoaded(ConfigFile:config, bool:loaded) stock ConfigSetConfigReloadFunc(ConfigFile:config, Function:reloadfunc) { // Set reload function. - g_ConfigData[config][ConfigReloadFunc] = reloadfunc; + g_ConfigData[config][Data_ReloadFunc] = reloadfunc; } /** @@ -206,7 +217,7 @@ stock ConfigSetConfigReloadFunc(ConfigFile:config, Function:reloadfunc) stock ConfigSetConfigHandle(ConfigFile:config, Handle:file) { // Set file handle. - g_ConfigData[config][ConfigHandle] = file; + g_ConfigData[config][Data_Handle] = file; } /** @@ -218,7 +229,7 @@ stock ConfigSetConfigHandle(ConfigFile:config, Handle:file) stock ConfigSetConfigPath(ConfigFile:config, const String:path[]) { // Set config file path. - strcopy(g_ConfigData[config][ConfigPath], PLATFORM_MAX_PATH, path); + strcopy(g_ConfigData[config][Data_Path], PLATFORM_MAX_PATH, path); } /** @@ -230,7 +241,7 @@ stock ConfigSetConfigPath(ConfigFile:config, const String:path[]) stock ConfigSetConfigAlias(ConfigFile:config, const String:alias[]) { // Set config alias. - strcopy(g_ConfigData[config][ConfigAlias], CONFIG_MAX_LENGTH, alias); + strcopy(g_ConfigData[config][Data_Alias], CONFIG_MAX_LENGTH, alias); } /** @@ -242,7 +253,19 @@ stock ConfigSetConfigAlias(ConfigFile:config, const String:alias[]) stock bool:ConfigIsConfigLoaded(ConfigFile:config) { // Return load status. - return g_ConfigData[config][ConfigLoaded]; + return g_ConfigData[config][Data_Loaded]; +} + +/** + * Returns config's structure type. + * + * @param config Config file to get structure type of. + * @return Config structure type. + */ +stock ConfigStructure:ConfigGetConfigStructure(ConfigFile:config) +{ + // Return load status. + return g_ConfigData[config][Data_Structure]; } /** @@ -254,7 +277,7 @@ stock bool:ConfigIsConfigLoaded(ConfigFile:config) stock Function:ConfigGetConfigReloadFunc(ConfigFile:config) { // Return load status. - return g_ConfigData[config][ConfigReloadFunc]; + return g_ConfigData[config][Data_ReloadFunc]; } /** @@ -266,7 +289,7 @@ stock Function:ConfigGetConfigReloadFunc(ConfigFile:config) stock Handle:ConfigGetConfigHandle(ConfigFile:config) { // Return load status. - return g_ConfigData[config][ConfigHandle]; + return g_ConfigData[config][Data_Handle]; } /** @@ -277,7 +300,7 @@ stock Handle:ConfigGetConfigHandle(ConfigFile:config) stock ConfigGetConfigPath(ConfigFile:config, String:path[], maxlen) { // Copy path to return string. - strcopy(path, maxlen, g_ConfigData[config][ConfigPath]); + strcopy(path, maxlen, g_ConfigData[config][Data_Path]); } /** @@ -288,7 +311,133 @@ stock ConfigGetConfigPath(ConfigFile:config, String:path[], maxlen) stock ConfigGetConfigAlias(ConfigFile:config, String:alias[], maxlen) { // Copy alias to return string. - strcopy(alias, maxlen, g_ConfigData[config][ConfigAlias]); + strcopy(alias, maxlen, g_ConfigData[config][Data_Alias]); +} + +/** + * Loads a config file and sets up a nested array type data storage. + * + * @param config The config file to load. + * @param arrayConfig Handle of the main array containing file data. + * @return True if file was loaded successfuly, false otherwise. + */ +stock bool:ConfigLoadConfig(ConfigFile:config, &Handle:arrayConfig) +{ + // Get config's structure. + new ConfigStructure:structure = ConfigGetConfigStructure(config); + + // Get config's alias + decl String:configalias[CONFIG_MAX_LENGTH]; + ConfigGetConfigAlias(config, configalias, sizeof(configalias)); + + // Get config's file path. + decl String:configpath[PLATFORM_MAX_PATH]; + ConfigGetConfigPath(config, configpath, sizeof(configpath)); + + // If handle is still open, then close it before creating a new one. + if (arrayConfig != INVALID_HANDLE) + { + CloseHandle(arrayConfig); + } + + // Create array in handle. + arrayConfig = CreateArray(CONFIG_MAX_LENGTH); + + switch(structure) + { + case Structure_List: + { + // Open file. + new Handle:hFile; + new success = ConfigOpenConfigFile(config, hFile); + + // If config file failed to open, then stop. + if (!success) + { + return false; + } + + // Clear out array. + ClearArray(arrayConfig); + + decl String:line[PLATFORM_MAX_PATH]; + + 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(arrayConfig, line); + } + + // We're done this file, so now we can destory it from memory. + CloseHandle(hFile); + + return true; + } + case Structure_Keyvalue: + { + // Open file. + new Handle:hKeyvalue; + new success = ConfigOpenConfigFile(config, hKeyvalue); + + // If config file failed to open, then stop. + if (!success) + { + return false; + } + + // Destroy all old data. + ConfigClearKvArray(arrayConfig); + + if (KvGotoFirstSubKey(hKeyvalue)) + { + do + { + // Create new array to store information for config entry. + new Handle:arrayConfigEntry = CreateArray(CONFIG_MAX_LENGTH); + + // Push the key name into the config entry's array. + decl String:keyname[CONFIG_MAX_LENGTH]; + KvGetSectionName(hKeyvalue, keyname, sizeof(keyname)); + + PushArrayString(arrayConfigEntry, keyname); // Index: 0 + + // Store this handle in the main array. + PushArrayCell(arrayConfig, arrayConfigEntry); + } while(KvGotoNextKey(hKeyvalue)); + } + + // We're done this file for now, so now we can destory it from memory. + CloseHandle(hKeyvalue); + + return true; + } + } + + return false; } /** @@ -297,7 +446,7 @@ stock ConfigGetConfigAlias(ConfigFile:config, String:alias[], maxlen) * @param config The config file entry to reload. * @return True if the config is loaded, false if not. */ -stock bool:ConfigReloadFile(ConfigFile:config) +stock bool:ConfigReloadConfig(ConfigFile:config) { // If file isn't loaded, then stop. new bool:loaded = ConfigIsConfigLoaded(config); @@ -309,6 +458,7 @@ stock bool:ConfigReloadFile(ConfigFile:config) // Call reload function new Function:reloadfunc = ConfigGetConfigReloadFunc(config); + // This should never be true unless someone has tampered with the code. if (reloadfunc == INVALID_FUNCTION) { // Get config alias. @@ -323,12 +473,169 @@ stock bool:ConfigReloadFile(ConfigFile:config) // Call reload function. Call_StartFunction(GetMyHandle(), reloadfunc); - Call_PushCell(config); Call_Finish(); return true; } +/** + * Opens a config file with appropriate method. + * + * @param config The config file. + * @param structure The structure of the config file. + * @param hConfig The handle of the opened file. + */ +stock bool:ConfigOpenConfigFile(ConfigFile:config, &Handle:hConfig) +{ + // Get config's structure + new ConfigStructure:structure = ConfigGetConfigStructure(config); + + // Get config's file path. + decl String:configpath[PLATFORM_MAX_PATH]; + ConfigGetConfigPath(config, configpath, sizeof(configpath)); + + // Get config's alias + decl String:configalias[CONFIG_MAX_LENGTH]; + ConfigGetConfigAlias(config, configalias, sizeof(configalias)); + + switch(structure) + { + case Structure_List: + { + // Open file. + hConfig = OpenFile(configpath, "r"); + + // If file couldn't be opened, then stop. + if (hConfig == INVALID_HANDLE) + { + return false; + } + + return true; + } + case Structure_Keyvalue: + { + hConfig = CreateKeyValues(configalias); + return FileToKeyValues(hConfig, configpath); + } + } + + return false; +} + +/** + * 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 file to modify. + * @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 retrieved value. + * @return True if the change was made successfully, false otherwise. + */ +stock bool:ConfigKeyvalueTreeSetting(ConfigFile:config, ConfigKvAction:action = KvAction_Create, const String:keys[][], keysMax, const String:setting[] = "", String:value[] = "", maxlen = 0) +{ + // Get config file's structure. + new ConfigStructure:structure = ConfigGetConfigStructure(config); + + // If the config is any other structure beside keyvalue, then stop. + if (structure != Structure_Keyvalue) + { + return false; + } + + // Retrieve handle of the keyvalue tree. + new Handle:hConfig; + new bool:success = ConfigOpenConfigFile(config, hConfig); + + // If the file couldn't be opened, then stop. + if (!success) + { + 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 == KvAction_Create)); + + // If exists is false, then stop. + if (!exists) + { + // Key doesn't exist. + return false; + } + } + + switch(action) + { + case KvAction_Create: + { + if (!setting[0] || !value[0]) + { + // We created the key already, so return true. + return true; + } + + // Set new value. + KvSetString(hConfig, setting, value); + } + case KvAction_Delete: + { + // Return deletion result. + return KvDeleteKey(hConfig, setting); + } + case KvAction_Set: + { + // Set new value. + KvSetString(hConfig, setting, value); + } + case KvAction_Get: + { + // Get current value. + KvGetString(hConfig, setting, value, maxlen); + } + } + + // We successfully set or got the value. + return true; +} + +/** + * Destroy all array handles within an array, and clear main array. + * + * @param arrayKv The array converted from a keyvalue structure. + */ +ConfigClearKvArray(Handle:arrayKv) +{ + // x = array index + new size = GetArraySize(arrayKv); + for (new x = 0; x < size; x++) + { + // Destroy nested arrays. + new Handle:arrayKvKey = GetArrayCell(arrayKv, x); + CloseHandle(arrayKvKey); + } + + // Now that all data within has been destroyed, we can clear the main array. + ClearArray(arrayKv); +} + /** * Load config file. * @@ -374,94 +681,11 @@ stock ConfigFile:ConfigAliasToConfigFile(const String:alias[]) } // Invalid config file. - return ConfigInvalid; + return File_Invalid; } /** - * 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. - */ -stock bool:ConfigKeyvalueTreeSetting(config, ConfigKeyvalueAction:action = ConfigKVCreate, const String:keys[][], keysMax, const String:setting[] = "", String:value[] = "", maxlen = 0) -{ - // Retrieve handle of the keyvalue tree. - new Handle:hConfig = ConfigGetConfigHandle(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 ConfigKVCreate: - { - if (!setting[0] || !value[0]) - { - // We created the key already, so return true. - return true; - } - - // Set new value. - KvSetString(hConfig, setting, value); - } - case ConfigKVDelete: - { - // Return deletion result. - return KvDeleteKey(hConfig, setting); - } - case ConfigKVSet: - { - // Set new value. - KvSetString(hConfig, setting, value); - } - case ConfigKVGet: - { - // Get current value. - KvGetString(hConfig, setting, value, maxlen); - } - } - - // We successfully set or got the value. - return true; -} - -/** - * Command callback (zr_reloadconfig) + * Command callback (zr_config_reload) * Reloads a config file and forwards event to modules. * * @param client The client index. @@ -472,7 +696,7 @@ public Action:ConfigReloadCommand(client, argc) // If not enough arguments given, then stop. if (argc < 1) { - TranslationReplyToCommand(client, "Config command reload syntax", CONFIG_FILE_ALIAS_MODELS, CONFIG_FILE_ALIAS_DOWNLOADS, CONFIG_FILE_ALIAS_CLASSES, CONFIG_FILE_ALIAS_WEAPONS, CONFIG_FILE_ALIAS_WEAPONGROUPS, CONFIG_FILE_ALIAS_HITGROUPS); + TranslationReplyToCommand(client, "Config command reload syntax", CONFIG_FILE_ALIAS_MODELS, CONFIG_FILE_ALIAS_DOWNLOADS, CONFIG_FILE_ALIAS_CLASSES, CONFIG_FILE_ALIAS_WEAPONS, CONFIG_FILE_ALIAS_HITGROUPS); return Plugin_Handled; } @@ -482,14 +706,14 @@ public Action:ConfigReloadCommand(client, argc) // If alias is invalid, then stop. new ConfigFile:config = ConfigAliasToConfigFile(arg1); - if (config == ConfigInvalid) + if (config == File_Invalid) { TranslationReplyToCommand(client, "Config command reload invalid", arg1); return Plugin_Handled; } // Reload config file. - new bool:loaded = ConfigReloadFile(config); + new bool:loaded = ConfigReloadConfig(config); // Get config file path. decl String:path[PLATFORM_MAX_PATH]; @@ -506,7 +730,7 @@ public Action:ConfigReloadCommand(client, argc) } /** - * Command callback (zr_reloadconfigall) + * Command callback (zr_config_reloadall) * Reloads all config files and forwards event to all modules. * * @param client The client index. @@ -523,7 +747,7 @@ public Action:ConfigReloadAllCommand(client, argc) for (new x = 0; x < sizeof(g_ConfigData); x++) { // Reload config file. - new bool:successful = ConfigReloadFile(ConfigFile:x); + new bool:successful = ConfigReloadConfig(ConfigFile:x); // Get config's alias. ConfigGetConfigAlias(ConfigFile:x, configalias, sizeof(configalias)); @@ -539,71 +763,13 @@ public Action:ConfigReloadAllCommand(client, argc) } } -/** - * 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[]) +stock bool:ConfigSettingToBool(const String:option[]) { // If option is equal to "yes," then return true. if (StrEqual(option, "yes", false)) @@ -620,9 +786,9 @@ bool:ConfigSettingToBool(const String:option[]) * * @param bOption True/false value to be converted to "yes"/"no", respectively. * @param option Destination string buffer to store "yes" or "no" in. - * @param maxlen Length of destination string buffer (can't be more than 4). + * @param maxlen Length of destination string buffer (wont't be more than 4). */ -ConfigBoolToSetting(bool:bOption, String:option[], maxlen) +stock ConfigBoolToSetting(bool:bOption, String:option[], maxlen) { // If option is true, then copy "yes" to return string. if (bOption) @@ -635,3 +801,11 @@ ConfigBoolToSetting(bool:bOption, String:option[], maxlen) strcopy(option, maxlen, "no"); } } + +stock bool:ConfigKvGetStringBool(Handle:kv, const String:key[], const String:defaultvalue[] = "yes") +{ + decl String:value[CONFIG_MAX_LENGTH]; + KvGetString(kv, key, value, sizeof(value), defaultvalue); + + return ConfigSettingToBool(value); +} \ No newline at end of file diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index b2cd842..8731ec3 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -38,7 +38,6 @@ enum CvarsList Handle:CVAR_CONFIG_PATH_DOWNLOADS, Handle:CVAR_CONFIG_PATH_CLASSES, Handle:CVAR_CONFIG_PATH_WEAPONS, - Handle:CVAR_CONFIG_PATH_WEAPONGROUPS, Handle:CVAR_CONFIG_PATH_HITGROUPS, Handle:CVAR_CLASSES_SPAWN, Handle:CVAR_CLASSES_RANDOM, @@ -51,6 +50,7 @@ enum CvarsList Handle:CVAR_CLASSES_OVERLAY_DEFAULT, Handle:CVAR_WEAPONS, Handle:CVAR_WEAPONS_RESTRICT, + Handle:CVAR_WEAPONS_ZMARKET, Handle:CVAR_WEAPONS_ZMARKET_BUYZONE, Handle:CVAR_HITGROUPS, Handle:CVAR_DAMAGE_HITGROUPS, @@ -207,9 +207,8 @@ CvarsCreate() g_hCvarsList[CVAR_CONFIG_PATH_MODELS] = CreateConVar("zr_config_path_models", "configs/zr/models.txt", "Path, relative to root sourcemod directory, to models config file."); g_hCvarsList[CVAR_CONFIG_PATH_DOWNLOADS] = CreateConVar("zr_config_path_downloads", "configs/zr/downloads.txt", "Path, relative to root sourcemod directory, to downloads file."); - g_hCvarsList[CVAR_CONFIG_PATH_CLASSES] = CreateConVar("zr_config_path_playerclasses", "configs/zr/playerclasses.txt", "Path, relative to root sourcemod directory, to playerclasses config file."); - g_hCvarsList[CVAR_CONFIG_PATH_WEAPONS] = CreateConVar("zr_config_path_weapons", "configs/zr/weapons/weapons.txt", "Path, relative to root sourcemod directory, to weapons config file."); - g_hCvarsList[CVAR_CONFIG_PATH_WEAPONGROUPS] = CreateConVar("zr_config_path_weapongroups", "configs/zr/weapons/weapongroups.txt", "Path, relative to root sourcemod directory, to weapongroups config file."); + g_hCvarsList[CVAR_CONFIG_PATH_CLASSES] = CreateConVar("zr_config_path_playerclasses", "configs/zr/playerclasses.txt", "Path, relative to root sourcemod directory, to playerclasses config file."); + g_hCvarsList[CVAR_CONFIG_PATH_WEAPONS] = CreateConVar("zr_config_path_weapons", "configs/zr/weapons.txt", "Path, relative to root sourcemod directory, to weapons config file."); g_hCvarsList[CVAR_CONFIG_PATH_HITGROUPS] = CreateConVar("zr_config_path_hitgroups", "configs/zr/hitgroups.txt", "Path, relative to root sourcemod directory, to hitgroups config file."); // =========================== @@ -258,9 +257,10 @@ CvarsCreate() g_hCvarsList[CVAR_WEAPONS_RESTRICT] = CreateConVar("zr_weapons_restrict", "1", "Enable weapon restriction module, disabling this will disable weapon restriction commands."); - // Market Handler + // ZMarket - g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE] = CreateConVar("zr_weapons_zmarket_buyzone", "1", "Requires player to be inside a buyzone to use ZMarket."); + g_hCvarsList[CVAR_WEAPONS_ZMARKET] = CreateConVar("zr_weapons_zmarket", "1", "Allow player to buy from a list of weapons in the weapons config."); + g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE] = CreateConVar("zr_weapons_zmarket_buyzone", "1", "Requires player to be inside a buyzone to use ZMarket. [Dependency: zr_weapons_zmarket]"); // =========================== // Hitgroups (core) diff --git a/src/zr/damage.inc b/src/zr/damage.inc index 3ffdff7..eb60969 100644 --- a/src/zr/damage.inc +++ b/src/zr/damage.inc @@ -48,7 +48,7 @@ DamageOnCommandsHook() // Explode string into array indexes. new cmdcount = ExplodeString(suicidecmds, ", ", arrayCmds, DAMAGE_SUICIDE_MAX_CMDS, DAMAGE_SUICIDE_MAX_LENGTH); - // x = array index. + // x = Array index. // arrayCmds[x] = suicide command. for (new x = 0; x <= cmdcount - 1; x++) { @@ -147,7 +147,16 @@ public ZRTools_Action:DamageTraceAttack(client, inflictor, attacker, Float:damag } // If damage is disabled for this hitgroup, then stop. - new bool:candamage = HitgroupsCanDamageHitgroup(hitgroup); + new index = HitgroupToIndex(hitgroup); + + // If index can't be found, then allow damage. + if (index == -1) + { + // Allow damage. + return ZRTools_Continue; + } + + new bool:candamage = HitgroupsCanDamage(index); if (!candamage) { // Stop bullet from hurting client. diff --git a/src/zr/downloads.inc b/src/zr/downloads.inc index 615a4a3..58255f7 100644 --- a/src/zr/downloads.inc +++ b/src/zr/downloads.inc @@ -12,43 +12,38 @@ /** * Array that stores a list of downloadable files. - * - * @redir config.inc */ +new Handle:arrayDownloads = INVALID_HANDLE; /** * Prepare all model/download data. */ DownloadsLoad() { + // Register config file. + ConfigRegisterConfig(File_Downloads, Structure_List, CONFIG_FILE_ALIAS_DOWNLOADS); + // Get downloads file path. decl String:pathdownloads[PLATFORM_MAX_PATH]; new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_DOWNLOADS, pathdownloads); - // Register config info. - ConfigRegisterConfig(ConfigDownloads, false, GetFunctionByName(GetMyHandle(), "DownloadsOnConfigReload"), _, pathdownloads, CONFIG_FILE_ALIAS_DOWNLOADS); - - // If file doesn't exist, then log. + // If file doesn't exist, then log and stop. if (!exists) { - // Log error, then stop. - LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Downloads", "Config Validation", "Missing downloads file: \"%s\"", pathdownloads); - - return; + // Log failure and stop plugin. + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Downloads", "Config Validation", "Fatal Error: Missing downloads file: \"%s\"", pathdownloads); } - // If download array exists, then destroy it. - if (arrayDownloadsList != INVALID_HANDLE) - { - CloseHandle(arrayDownloadsList); - } + // Set the path to the config file. + ConfigSetConfigPath(File_Downloads, pathdownloads); - arrayDownloadsList = ConfigLinesToArray(pathdownloads); + // Load config from file and create array structure. + new bool:success = ConfigLoadConfig(File_Downloads, arrayDownloads); - // If array couldn't be created, then fail. - if (arrayDownloadsList == INVALID_HANDLE) + // Unexpected error, stop plugin. + if (!success) { - LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Downloads", "Config Validation", "Error parsing \"%s\"", pathdownloads); + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Downloads", "Config Validation", "Fatal Error: Unexpected error encountered loading: %s", pathdownloads); } new downloadcount; @@ -56,19 +51,19 @@ DownloadsLoad() decl String:downloadpath[PLATFORM_MAX_PATH]; - new downloads = downloadcount = GetArraySize(arrayDownloadsList); + new downloads = downloadcount = GetArraySize(arrayDownloads); // x = download array index. for (new x = 0; x < downloads; x++) { - // Get base model path (rawline in models.txt) - GetArrayString(arrayDownloadsList, x, downloadpath, sizeof(downloadpath)); + // Get download path + GetArrayString(arrayDownloads, x, downloadpath, sizeof(downloadpath)); // If file doesn't exist, then remove, log, and stop. if (!FileExists(downloadpath)) { // Remove client from array. - RemoveFromArray(arrayDownloadsList, x); + RemoveFromArray(arrayDownloads, x); // Subtract one from count. downloads--; @@ -91,8 +86,9 @@ DownloadsLoad() LogPrintToLog(LOG_FORMAT_TYPE_NORMAL, "Downloads", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", downloadcount, downloadvalidcount, downloadcount - downloadvalidcount); // Set config data. - ConfigSetConfigLoaded(ConfigDownloads, true); - ConfigSetConfigHandle(ConfigDownloads, arrayDownloadsList); + ConfigSetConfigLoaded(File_Downloads, true); + ConfigSetConfigReloadFunc(File_Downloads, GetFunctionByName(GetMyHandle(), "DownloadsOnConfigReload")); + ConfigSetConfigHandle(File_Downloads, arrayDownloads); } /** @@ -103,8 +99,5 @@ DownloadsLoad() public DownloadsOnConfigReload(ConfigFile:config) { // Reload download config. - if (config == ConfigDownloads) - { - DownloadsLoad(); - } + DownloadsLoad(); } \ No newline at end of file diff --git a/src/zr/hitgroups.inc b/src/zr/hitgroups.inc index d1f5ad6..2e555df 100644 --- a/src/zr/hitgroups.inc +++ b/src/zr/hitgroups.inc @@ -11,10 +11,9 @@ */ /** - * Keyvalue handle to store hitgroups data. - * - * @redir config.inc + * Maximum length for a hitgroup name */ +#define HITGROUPS_MAX_LENGTH 32 /** * @section Player hitgroup values. @@ -33,33 +32,28 @@ */ /** - * Clears hitgroup data. - */ -HitgroupsClearData() + * Hitgroup config data indexes. + */ +enum HitgroupsData { - // Load hitgroup data. - if (kvHitgroups != INVALID_HANDLE) - { - CloseHandle(kvHitgroups); - } - - kvHitgroups = CreateKeyValues("hitgroups"); + HITGROUPS_DATA_NAME = 0, + HITGROUPS_DATA_INDEX, + HITGROUPS_DATA_DAMAGE, + HITGROUPS_DATA_KNOCKBACK, } +/** + * Array handle to store hitgroups data. + */ +new Handle:arrayHitgroups = INVALID_HANDLE; + /** * Loads hitgroup data from file. */ HitgroupsLoad() { - // Clear hitgroup data - HitgroupsClearData(); - - // Get hitgroups config path. - decl String:pathhitgroups[PLATFORM_MAX_PATH]; - new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_HITGROUPS, pathhitgroups); - - // Register config info. - ConfigRegisterConfig(ConfigHitgroups, false, GetFunctionByName(GetMyHandle(), "HitgroupsOnConfigReload"), _, pathhitgroups, CONFIG_FILE_ALIAS_HITGROUPS); + // 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]); @@ -68,23 +62,101 @@ HitgroupsLoad() 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. LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Hitgroups", "Config Validation", "Missing hitgroups config file: %s", pathhitgroups); + return; } - // Put file data into memory. - FileToKeyValues(kvHitgroups, pathhitgroups); + // 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) + { + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Hitgroups", "Config Validation", "Unexpected error encountered loading: %s", pathhitgroups); + + return; + } // Validate hitgroups config. - HitgroupsValidateConfig(); + new size = GetArraySize(arrayHitgroups); + if (!size) + { + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Hitgroups", "Config Validation", "No usable data found in hitgroups config file: %s", pathhitgroups); + } + + // Now copy data to array structure. + HitgroupsCacheData(); // Set config data. - ConfigSetConfigLoaded(ConfigHitgroups, true); - ConfigSetConfigHandle(ConfigHitgroups, kvHitgroups); + 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) + { + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "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)) + { + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "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); } /** @@ -95,85 +167,91 @@ HitgroupsLoad() public HitgroupsOnConfigReload(ConfigFile:config) { // Reload hitgroups config. - if (config == ConfigHitgroups) - { - HitgroupsLoad(); - } + HitgroupsLoad(); } /** - * Validate hitgroup config file and settings. - */ -HitgroupsValidateConfig() -{ - KvRewind(kvHitgroups); - if (!KvGotoFirstSubKey(kvHitgroups)) - { - // Log that no data was loaded from hitgroup file. - LogPrintToLog(LOG_FORMAT_TYPE_NORMAL, "Hitgroups", "Config Validation", "No hitgroups listed in hitgroups.txt, disabling hitgroup-based modules."); - } -} - -/** - * Retrieve hitgroup knockback value. + * Find the array index at which the hitgroup index is at. * - * @param hitgroup The hitgroup index. - * @return The knockback multiplier of the hitgroup. + * @param hitgroup The hitgroup index to search for. + * @return The array index that contains the given hitgroup index. */ -Float:HitgroupsGetHitgroupKnockback(hitgroup) +stock HitgroupToIndex(hitgroup) { - // Reset keyvalue's traversal stack. - KvRewind(kvHitgroups); - if (KvGotoFirstSubKey(kvHitgroups)) + // x = Array index. + new size = GetArraySize(arrayHitgroups); + for (new x = 0; x < size; x++) { - decl String:sHitgroup[4]; + // Get hitgroup index at this array index. + new index = HitgroupsGetIndex(x); - do + // If hitgroup indexes match, then return array index. + if (hitgroup == index) { - 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 x; + } } - return 1.0; + // Hitgroup index doesn't exist. + return -1; +} + +/** + * Gets the name of a hitgroup at a given index. + * @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. + * + * @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); } /** * Retrieve hitgroup damage value. * - * @param hitgroup The hitgroup index. + * @param index The array index. * @return True if hitgroup can be damaged, false if not. */ -bool:HitgroupsCanDamageHitgroup(hitgroup) +stock bool:HitgroupsCanDamage(index) { - // Reset keyvalue's traversal stack. - KvRewind(kvHitgroups); - if (KvGotoFirstSubKey(kvHitgroups)) - { - decl String:sHitgroup[4]; - decl String:damage[8]; - - do - { - KvGetSectionName(kvHitgroups, sHitgroup, sizeof(sHitgroup)); - - // If this is the right hitgroup, then return knockback for it. - if (hitgroup == StringToInt(sHitgroup)) - { - // Get config setting string. - KvGetString(kvHitgroups, "damage", damage, sizeof(damage), "yes"); - - // Return hitgroup's damage setting. - return ConfigSettingToBool(damage); - } - } while (KvGotoNextKey(kvHitgroups)); - } + // Get array handle of hitgroup at given index. + new Handle:arrayHitgroup = GetArrayCell(arrayHitgroups, index); - // If hitgroup is missing, then default to "yes." - return true; + // Return true if hitgroup can be damaged, false if not. + return bool:GetArrayCell(arrayHitgroup, _:HITGROUPS_DATA_DAMAGE); +} + +/** + * Retrieve hitgroup knockback value. + * + * @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); } diff --git a/src/zr/infect.inc b/src/zr/infect.inc index 073cfc4..a51e1bd 100644 --- a/src/zr/infect.inc +++ b/src/zr/infect.inc @@ -390,7 +390,7 @@ public Action:InfectMotherZombie(Handle:timer) new client; // Prune list of immune clients. - // x = array index. + // x = Array index. // client = client index. for (new x = 0; x < eligibleclients; x++) { @@ -522,7 +522,7 @@ InfectClient(client, attacker = -1, bool:motherinfect = false) bZombie[client] = true; // Get a list of all client's weapon indexes. - new weapons[WeaponsType]; + new weapons[WeaponsSlot]; WeaponsGetClientWeapons(client, weapons); // Check if weapons drop is enabled. @@ -541,7 +541,7 @@ InfectClient(client, attacker = -1, bool:motherinfect = false) if (weaponsdrop) { // If this is the knife slot, then stop. - if (WeaponsType:x == Type_Melee) + if (WeaponsSlot:x == Slot_Melee) { continue; } @@ -557,7 +557,7 @@ InfectClient(client, attacker = -1, bool:motherinfect = false) } // If client has no knife, give them one. - if (GetPlayerWeaponSlot(client, _:Type_Melee) == -1) + if (GetPlayerWeaponSlot(client, _:Slot_Melee) == -1) { GivePlayerItem(client, "weapon_knife"); } diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index 43e7190..b714640 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -70,14 +70,22 @@ KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_hea TR_GetEndPosition(clientloc); } - // Retrieve weapon knockback boost. - new Float:boostWeapon = WeaponGetWeaponKnockback(weapon); + new weaponindex = WeaponsNameToIndex(weapon); + if (weaponindex != -1) + { + // Apply weapon knockback multiplier. + knockback *= WeaponsGetKnockback(weaponindex); + } - // Retrieve hitgroup knockback boost. - new Float:boostHitgroup = HitgroupsGetHitgroupKnockback(hitgroup); + new hitgroupindex = HitgroupToIndex(hitgroup); + if (hitgroupindex != -1) + { + // Apply hitgroup knockback multiplier. + knockback *= HitgroupsGetKnockback(hitgroupindex); + } - // Apply all knockback multipliers. - knockback *= float(dmg_health) * boostWeapon * boostHitgroup; + // Apply damage knockback multiplier. + knockback *= float(dmg_health); // Apply knockback. KnockbackSetVelocity(client, attackerloc, clientloc, knockback); diff --git a/src/zr/menu.inc b/src/zr/menu.inc index 21b952d..2cb474b 100644 --- a/src/zr/menu.inc +++ b/src/zr/menu.inc @@ -52,7 +52,7 @@ MenuMain(client) AddMenuItem(menu_main, "zspawn", zspawn); AddMenuItem(menu_main, "ztele", ztele); AddMenuItem(menu_main, "zhp", zhp); - AddMenuItem(menu_main, "zmarket", zmarket, MenuGetItemDraw(g_bMarket)); + AddMenuItem(menu_main, "zmarket", zmarket); // Display menu to client. DisplayMenu(menu_main, client, MENU_TIME_FOREVER); @@ -113,8 +113,6 @@ public MenuMainHandle(Handle:menu, MenuAction:action, client, slot) // Select zmarket. case 5: { - // Copy return to resend variable. - resend = !ZMarketMenu(client); } } diff --git a/src/zr/models.inc b/src/zr/models.inc index 3596b26..5fab9a7 100644 --- a/src/zr/models.inc +++ b/src/zr/models.inc @@ -22,22 +22,21 @@ /** * Array that stores a list of validated models. - * - * @redir config.inc */ +new Handle:arrayModels = INVALID_HANDLE; /** * Prepare all model/download data. */ ModelsLoad() { + // Register config file. + ConfigRegisterConfig(File_Models, Structure_List, CONFIG_FILE_ALIAS_MODELS); + // Get models file path. decl String:pathmodels[PLATFORM_MAX_PATH]; new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_MODELS, pathmodels); - // Register config info. - ConfigRegisterConfig(ConfigModels, false, GetFunctionByName(GetMyHandle(), "ModelsOnConfigReload"), _, pathmodels, CONFIG_FILE_ALIAS_MODELS); - // If file doesn't exist, then log and stop. if (!exists) { @@ -45,18 +44,16 @@ ModelsLoad() LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Models", "Config Validation", "Fatal Error: Missing models file: \"%s\"", pathmodels); } - // If model array exists, then destroy it. - if (arrayModelsList != INVALID_HANDLE) - { - CloseHandle(arrayModelsList); - } + // Set the path to the config file. + ConfigSetConfigPath(File_Models, pathmodels); - arrayModelsList = ConfigLinesToArray(pathmodels); + // Load config from file and create array structure. + new bool:success = ConfigLoadConfig(File_Models, arrayModels); - // If array couldn't be created, then fail. - if (arrayModelsList == INVALID_HANDLE) + // Unexpected error, stop plugin. + if (!success) { - LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Models", "Config Validation", "Fatal Error: Error parsing \"%s\"", pathmodels); + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Models", "Config Validation", "Fatal Error: Unexpected error encountered loading: %s", pathmodels); } new modelcount; @@ -74,13 +71,13 @@ ModelsLoad() new FileType:type; - new models = modelcount = GetArraySize(arrayModelsList); + new models = modelcount = GetArraySize(arrayModels); // x = model array index. for (new x = 0; x < models; x++) { // Get base model path (rawline in models.txt) - GetArrayString(arrayModelsList, x, modelbase, sizeof(modelbase)); + GetArrayString(arrayModels, x, modelbase, sizeof(modelbase)); // Explode path into pieces. (separated by "/") new strings = ExplodeString(modelbase, "/", baseexploded, MODELS_PATH_MAX_DEPTH, MODELS_PATH_DIR_MAX_LENGTH); @@ -137,7 +134,7 @@ ModelsLoad() else { // Remove client from array. - RemoveFromArray(arrayModelsList, x); + RemoveFromArray(arrayModels, x); // Subtract one from count. models--; @@ -160,20 +157,16 @@ ModelsLoad() } // Set config data. - ConfigSetConfigLoaded(ConfigModels, true); - ConfigSetConfigHandle(ConfigModels, arrayModelsList); + ConfigSetConfigLoaded(File_Models, true); + ConfigSetConfigReloadFunc(File_Models, GetFunctionByName(GetMyHandle(), "ModelsOnConfigReload")); + ConfigSetConfigHandle(File_Models, arrayModels); } /** - * Called when configs are being reloaded. - * - * @param config The config being reloaded. (only if 'all' is false) + * Called when config is being reloaded. */ public ModelsOnConfigReload(ConfigFile:config) { - // Reload model config. - if (config == ConfigModels) - { - ModelsLoad(); - } + // Reload models config. + ModelsLoad(); } \ No newline at end of file diff --git a/src/zr/playerclasses/apply.inc b/src/zr/playerclasses/apply.inc index 10386a7..7efb185 100644 --- a/src/zr/playerclasses/apply.inc +++ b/src/zr/playerclasses/apply.inc @@ -71,8 +71,8 @@ bool:ClassApplyModel(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER) if (strcmp(modelpath, "random", false) == 0) { // TODO: Make a function that gets a random model from the specified team. - new randmodel = GetRandomInt(0, GetArraySize(arrayModelsList) - 1); - GetArrayString(arrayModelsList, randmodel, modelpath, sizeof(modelpath)); + new randmodel = GetRandomInt(0, GetArraySize(arrayModels) - 1); + GetArrayString(arrayModels, randmodel, modelpath, sizeof(modelpath)); Format(modelpath, sizeof(modelpath), "%s.mdl", modelpath); } diff --git a/src/zr/playerclasses/classmenus.inc b/src/zr/playerclasses/classmenus.inc index 809296c..af5343c 100644 --- a/src/zr/playerclasses/classmenus.inc +++ b/src/zr/playerclasses/classmenus.inc @@ -209,14 +209,6 @@ ClassMenuSelect(client, teamid) AddMenuItem(menu, classname, menuitem); } } - else - { - // No classes found. Display message. The main class menu should - // prevent this from happening, but we print a message just in case. - // THIS TRANSLATION PHRASES IS NOT IN FILE. - Format(menuitem, sizeof(menuitem), "%t\n", "Classes menu not found"); - AddMenuItem(menu, classname, menuitem, ITEMDRAW_RAWLINE); - } SetMenuExitBackButton(menu, true); DisplayMenu(menu, client, MENU_TIME_FOREVER); diff --git a/src/zr/playerclasses/clientoverlays.inc b/src/zr/playerclasses/clientoverlays.inc index 30978b0..df9f726 100644 --- a/src/zr/playerclasses/clientoverlays.inc +++ b/src/zr/playerclasses/clientoverlays.inc @@ -54,7 +54,7 @@ ClassOverlayOnCommandsHook() // Explode string into array indexes. new cmdcount = ExplodeString(togglecmds, ", ", arrayCmds, CLASSOVERLAY_TOGGLE_MAX_CMDS, CLASSOVERLAY_TOGGLE_MAX_LENGTH); - // x = array index. + // x = Array index. // arrayCmds[x] = suicide command. for (new x = 0; x <= cmdcount - 1; x++) { diff --git a/src/zr/playerclasses/playerclasses.inc b/src/zr/playerclasses/playerclasses.inc index 15a52c8..81fde59 100644 --- a/src/zr/playerclasses/playerclasses.inc +++ b/src/zr/playerclasses/playerclasses.inc @@ -252,9 +252,8 @@ enum ClassDataTypes /** * Keyvalue handle to store class data. - * - * @redir config.inc */ +new Handle:kvClassData = INVALID_HANDLE; /** * The original class data. This array only changed when class data is loaded. @@ -322,20 +321,20 @@ new ClassPlayerNextAdminClass[MAXPLAYERS + 1]; */ ClassLoad() { + // Register config file. + ConfigRegisterConfig(File_Classes, Structure_Keyvalue, CONFIG_FILE_ALIAS_CLASSES); + // Make sure kvClassData is ready to use. if (kvClassData != INVALID_HANDLE) { CloseHandle(kvClassData); } - kvClassData = CreateKeyValues("classes"); + kvClassData = CreateKeyValues(CONFIG_FILE_ALIAS_CLASSES); // Get weapons config path. decl String:pathclasses[PLATFORM_MAX_PATH]; new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_CLASSES, pathclasses); - // Register config info. - ConfigRegisterConfig(ConfigClasses, false, GetFunctionByName(GetMyHandle(), "ClassOnConfigReload"), _, pathclasses, CONFIG_FILE_ALIAS_CLASSES); - // If file doesn't exist, then log and stop. if (!exists) { @@ -463,8 +462,10 @@ ClassLoad() LogPrintToLog(LOG_FORMAT_TYPE_NORMAL, "Classes", "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", ClassCount, ClassCount - failedcount, failedcount); // Set config data. - ConfigSetConfigLoaded(ConfigClasses, true); - ConfigSetConfigHandle(ConfigClasses, kvClassData); + ConfigSetConfigLoaded(File_Classes, true); + ConfigSetConfigReloadFunc(File_Classes, GetFunctionByName(GetMyHandle(), "ClassOnConfigReload")); + // ConfigSetConfigHandle(File_Classes, INVALID_HANDLE); + ConfigSetConfigPath(File_Classes, pathclasses); } /** @@ -475,9 +476,6 @@ ClassLoad() public ClassOnConfigReload(ConfigFile:config) { // Reload class config. - if (config == ConfigClasses) - { - } } /** diff --git a/src/zr/roundend.inc b/src/zr/roundend.inc index bb828e7..081b275 100644 --- a/src/zr/roundend.inc +++ b/src/zr/roundend.inc @@ -306,7 +306,7 @@ RoundEndBalanceTeams() // Move all clients to T - // x = array index. + // x = Array index. // client = client index. for (new x = 0; x < eligibleclients; x++) { diff --git a/src/zr/sayhooks.inc b/src/zr/sayhooks.inc index ce1e801..5c80170 100644 --- a/src/zr/sayhooks.inc +++ b/src/zr/sayhooks.inc @@ -121,8 +121,6 @@ public Action:SayHooksCmdSay(client, argc) // Client triggered ZMarket flag. case SAYHOOKS_KEYWORD_FLAG_ZMARKET: { - // Send market menu. - success = ZMarketMenu(client); } } diff --git a/src/zr/tools.inc b/src/zr/tools.inc index ca62df1..199ba17 100644 --- a/src/zr/tools.inc +++ b/src/zr/tools.inc @@ -18,11 +18,8 @@ new g_iToolsBaseVelocity; new g_iToolsLMV; new g_iToolsHasNightVision; new g_iToolsNightVisionOn; -new g_iToolsCollisionGroup; -new g_iToolsAccount; new g_iToolsDefaultFOV; -new g_iToolsInBuyZone; -new g_iToolsActiveWeapon; + /** * @endsection */ @@ -93,20 +90,6 @@ ToolsFindOffsets() LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CCSPlayer::m_bNightVisionOn\" was not found."); } - // If offset "m_CollisionGroup" can't be found, then stop the plugin. - g_iToolsCollisionGroup = FindSendPropInfo("CBaseEntity", "m_CollisionGroup"); - if (g_iToolsCollisionGroup == -1) - { - LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CBaseEntity::m_CollisionGroup\" was not found."); - } - - // If offset "m_iAccount" can't be found, then stop the plugin. - g_iToolsAccount = FindSendPropInfo("CCSPlayer", "m_iAccount"); - if (g_iToolsAccount == -1) - { - LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CCSPlayer::m_iAccount\" was not found."); - } - // If offset "m_iDefaultFOV" can't be found, then stop the plugin. g_iToolsDefaultFOV = FindSendPropInfo("CBasePlayer", "m_iDefaultFOV"); if (g_iToolsDefaultFOV == -1) @@ -114,19 +97,11 @@ ToolsFindOffsets() LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CBasePlayer::m_iDefaultFOV\" was not found."); } - // If offset "m_bInBuyZone" can't be found, then stop the plugin. - g_iToolsInBuyZone = FindSendPropInfo("CCSPlayer", "m_bInBuyZone"); - if (g_iToolsInBuyZone == -1) - { - LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CCSPlayer::m_bInBuyZone\" was not found."); - } - - // If offset "m_hActiveWeapon" can't be found, then stop the plugin. - g_iToolsActiveWeapon = FindSendPropInfo("CBasePlayer", "m_hActiveWeapon"); - if (g_iToolsActiveWeapon == -1) - { - LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CBasePlayer::m_hActiveWeapon\" was not found."); - } + // Forward event to modules. + WeaponsOnOffsetsFound(); + AccountOnOffsetsFound(); + AntiStickOnOffsetsFound(); + ZMarketOnOffsetsFound(); } /** diff --git a/src/zr/translation.inc b/src/zr/translation.inc index 9e15093..404af44 100644 --- a/src/zr/translation.inc +++ b/src/zr/translation.inc @@ -153,8 +153,8 @@ stock TranslationPrintToChatAll(bool:server, bool:admin, any:...) continue; } - // Set translation target - SetGlobalTransTarget(LANG_SERVER); + // Set translation target to client. + SetGlobalTransTarget(x); // Translate phrase. VFormat(translation, sizeof(translation), "%t", 3); @@ -327,9 +327,20 @@ stock TranslationReplyToCommand(client, any:...) decl String:translation[TRANSLATION_MAX_LENGTH_CHAT]; VFormat(translation, sizeof(translation), "%t", 2); - // Format string to create plugin style. - TranslationPluginFormatString(translation, sizeof(translation)); - - // Print translated phrase to client. - ReplyToCommand(client, translation); + if (ZRIsClientValid(client)) + { + // Format string to create plugin style. (color) + TranslationPluginFormatString(translation, sizeof(translation)); + + // Print translated phrase to client's chat/console. + PrintToChat(client, translation); + } + else + { + // Format string to create plugin style. (no color) + TranslationPluginFormatString(translation, sizeof(translation), false); + + // Print to server. + PrintToServer(translation); + } } \ No newline at end of file diff --git a/src/zr/weapons/markethandler.inc b/src/zr/weapons/markethandler.inc deleted file mode 100644 index e32e4d1..0000000 --- a/src/zr/weapons/markethandler.inc +++ /dev/null @@ -1,165 +0,0 @@ -/* - * ============================================================================ - * - * Zombie:Reloaded - * - * File: markethandler.inc - * Type: Core - * Description: Handles market (optional plugin) API, natives, and forwards. - * - * ============================================================================ - */ - -/** - * Global variable set to true if market plugin is installed - */ -new bool:g_bMarket; - -/** - * Set global market flag variable - */ -MarketInit() -{ - // Set market variable to true if market is installed. - g_bMarket = LibraryExists("market"); -} - -/** - * Sends market menu to client. - * - * @param client The client index. - */ -bool:ZMarketMenu(client) -{ - // If market is disabled, then stop. - if (!g_bMarket) - { - // Tell client market is disabled. - TranslationPrintToChat(client, "Feature is disabled"); - return false; - } - - // If player is dead, then stop. - if (!IsPlayerAlive(client)) - { - // Tell player they must be alive. - TranslationPrintToChat(client, "Must be alive"); - return false; - } - - // Check buyzone cvar to see if client has to be in a buyzone to use. - new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); - if (!ZMarketIsClientInBuyZone(client) && buyzone) - { - // Tell client they must be in a buyzone. - TranslationPrintCenterText(client, "Market out of buyzone"); - return false; - } - - // Set translate target to client. - SetGlobalTransTarget(client); - - // Format title and rebuy lines. - decl String:title[64]; - decl String:rebuy[64]; - - Format(title, sizeof(title), "%t\n ", "Market title"); - Format(rebuy, sizeof(rebuy), "%t\n ", "Market rebuy"); - - // Send market menu. - Market_Send(client, title, rebuy); - - // Successfully sent the market menu. - return true; -} - -/** - * Checks if a client is in a buyzone. - * - * @param client The client index. - */ -bool:ZMarketIsClientInBuyZone(client) -{ - // Return if client is in buyzone. - return bool:GetEntData(client, g_iToolsInBuyZone); -} - -/** - * (Market) Forward called when a client selects a weapon from the market. - * - * @param client The client index. - * @param weaponid The unique weapon ID used for market natives. - * @return True to allow market to take over, false to block purchase. - */ -public bool:Market_OnWeaponSelected(client, String:weaponid[]) -{ - // If player is dead or weaponid is invalid, then stop. - if (!weaponid[0] || !IsPlayerAlive(client)) - { - return false; - } - - // If player is a zombie, then stop. - if (InfectIsClientInfected(client)) - { - TranslationPrintToChat(client, "Zombie cant use weapon"); - - return false; - } - - // If player is using the rebuy option then allow. - if (StrEqual(weaponid, "rebuy")) - { - return true; - } - - decl String:display[64]; - decl String:weapon[WEAPONS_MAX_LENGTH]; - new price; - - // If the market plugin can't find info about the weapon, then stop. - if (!Market_GetWeaponIDInfo(weaponid, display, weapon, price)) - { - return false; - } - - // Strip "weapon_" from entity name. - ReplaceString(weapon, sizeof(weapon), "weapon_", ""); - - // If the weapon is restricted, then stop. - if (RestrictIsWeaponRestricted(weapon)) - { - TranslationPrintToChat(client, "Weapon is restricted", weapon); - - return false; - } - - // Check if buyzone cvar is enabled, and if the client is in a buyzone. - new bool:buyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); - if (!ZMarketIsClientInBuyZone(client) && buyzone) - { - TranslationPrintCenterText(client, "Market out of buyzone"); - - return false; - } - - return true; -} - -/** - * (Market) Forward called one frame after a client selects a weapon from the market. - * - * @param client The client index. - * @param allowed True when the weapon was purchased successfully, false otherwise. - */ -public Market_PostOnWeaponSelected(client, &bool:allowed) -{ - // If the purchase wasn't allowed, then stop. - if (!allowed) - { - return; - } - - // Resend market menu. - ZMarketMenu(client); -} diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index c4d728e..fa29242 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -11,28 +11,14 @@ */ /** - * Weapons Menus + * Array to store the client's current weapon type within menu. */ -enum WeaponsMenu -{ - Weapon, - WeaponGroup, -} - -/** - * Array to store the client's current weapon menu. - */ -new WeaponsMenu:curMenuWeapons[MAXPLAYERS + 1]; - -/** - * Array to store the client's current weapon group menu. - */ -new String:curMenuGroup[WEAPONS_MAX_LENGTH][MAXPLAYERS + 1]; +new g_iCurWeaponType[MAXPLAYERS + 1]; /** * Sends main weapon menu to client. * @param client The client index. - */ + */ WeaponsMenuMain(client) { // Create menu handle. @@ -42,17 +28,15 @@ WeaponsMenuMain(client) SetMenuTitle(menu_weapons_main, "%t\n ", "Weapons menu main title"); - decl String:toggleweaponrestriction[64]; - decl String:togglewgrouprestriction[64]; + decl String:restrict[64]; decl String:zmarket[64]; - Format(toggleweaponrestriction, sizeof(toggleweaponrestriction), "%t", "Weapons menu main toggle weapon restrict"); - Format(togglewgrouprestriction, sizeof(togglewgrouprestriction), "%t", "Weapons menu main toggle weapon group restrict"); + Format(restrict, sizeof(restrict), "%t", "Weapons menu main restrict"); Format(zmarket, sizeof(zmarket), "%t", "Weapons menu main market"); - AddMenuItem(menu_weapons_main, "toggleweaponrestriction", toggleweaponrestriction); - AddMenuItem(menu_weapons_main, "togglewgrouprestriction", togglewgrouprestriction); - AddMenuItem(menu_weapons_main, "zmarket", zmarket, MenuGetItemDraw(g_bMarket)); + // Draw items, make unselectable if module is disabled. + AddMenuItem(menu_weapons_main, "restrict", restrict, MenuGetItemDraw(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_RESTRICT]))); + AddMenuItem(menu_weapons_main, "zmarket", zmarket, MenuGetItemDraw(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET]))); // Create a "Back" button to the weapons main menu. SetMenuExitBackButton(menu_weapons_main, true); @@ -75,17 +59,15 @@ public WeaponsMenuMainHandle(Handle:menu_weapons_main, MenuAction:action, client { switch(slot) { + // Weapons. case 0: { - WeaponsMenuWeapons(client, Weapon); + WeaponsMenuTypes(client); } + // ZMarket. case 1: { - WeaponsMenuWeapons(client, WeaponGroup); - } - case 2: - { - WeaponsMenuMarket(client); + WeaponsMenuZMarket(client); } } } @@ -95,7 +77,7 @@ public WeaponsMenuMainHandle(Handle:menu_weapons_main, MenuAction:action, client // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { - ZRAdminMenu(client); + // Re-open admin menu. } } // Client hit "Exit" button. @@ -106,159 +88,63 @@ public WeaponsMenuMainHandle(Handle:menu_weapons_main, MenuAction:action, client } /** - * Sends weapon list menu to client. + * Sends weapon type list to client. * @param client The client index. - */ -WeaponsMenuWeapons(client, WeaponsMenu:type) + */ +WeaponsMenuTypes(client) { - // Set the current action client is performing on a weapon. (see enum WeaponsMenu) - curMenuWeapons[client] = type; - // Create menu handle. - new Handle:menu_weapons_weapons = CreateMenu(WeaponsMenuWeaponsHandle); + new Handle:menu_weapons_types = CreateMenu(WeaponsMenuTypesHandle); SetGlobalTransTarget(client); - // If client wants to perform an action on a single weapon, show weapon list. - switch(curMenuWeapons[client]) + SetMenuTitle(menu_weapons_types, "%t\n ", "Weapons menu types title"); + + decl String:typename[WEAPONS_MAX_LENGTH]; + + // x = Array index. + new size = GetArraySize(arrayWeaponTypes); + for (new x = 0; x < size; x++) { - case Weapon: - { - SetMenuTitle(menu_weapons_weapons, "%t\n ", "Weapons menu weapons weapon title"); - - decl String:weapon[WEAPONS_MAX_LENGTH]; - decl String:display[WEAPONS_MAX_LENGTH + 1]; - new Handle:arrayWeapons = INVALID_HANDLE; - new size = WeaponsCreateWeaponArray(arrayWeapons); - - // x = Array index. - for (new x = 0; x < size; x++) - { - GetArrayString(arrayWeapons, x, weapon, sizeof(weapon)); - - strcopy(display, sizeof(display), weapon); - - if (RestrictIsWeaponRestricted(weapon)) - { - Format(display, sizeof(display), "%s*", weapon); - } - - // If weapon restriction is blocked for the menu, disable option. - new bool:menu = WeaponsIsWeaponMenu(weapon); - - if (menu) - { - AddMenuItem(menu_weapons_weapons, weapon, display); - } - else - { - AddMenuItem(menu_weapons_weapons, weapon, display, ITEMDRAW_DISABLED); - } - } - - // If there are no weapons, add an "(Empty)" line. - if (size == 0) - { - decl String:empty[64]; - Format(empty, sizeof(empty), "%t", "Menu empty"); - - AddMenuItem(menu_weapons_weapons, "empty", empty, ITEMDRAW_DISABLED); - } - - // Kill the array handle. - CloseHandle(arrayWeapons); - } - // If client wants to perform an action on a weapon group, show custom group list. - case WeaponGroup: - { - SetMenuTitle(menu_weapons_weapons, "%t\n ", "Weapons menu weapons group title"); - - decl String:weapongroup[WEAPONS_MAX_LENGTH]; - decl String:display[WEAPONS_MAX_LENGTH + 2]; - new Handle:arrayWeaponGroups = INVALID_HANDLE; - new size = RestrictCreateGroupArray(arrayWeaponGroups); - - // x = Array index. - for (new x = 0; x < size; x++) - { - GetArrayString(arrayWeaponGroups, x, weapongroup, sizeof(weapongroup)); - - strcopy(display, sizeof(display), weapongroup); - - if (RestrictIsPartialRestricted(weapongroup)) - { - Format(display, sizeof(display), "%s*", weapongroup); - } - else if (RestrictIsGroupRestricted(weapongroup)) - { - Format(display, sizeof(display), "%s**", weapongroup); - } - - AddMenuItem(menu_weapons_weapons, weapongroup, display); - } - - // If there are no weapons, add an "(Empty)" line. - if (size == 0) - { - decl String:empty[64]; - Format(empty, sizeof(empty), "%t", "Menu empty"); - - AddMenuItem(menu_weapons_weapons, "empty", empty, ITEMDRAW_DISABLED); - } - - // Kill the array handle - CloseHandle(arrayWeaponGroups); - } + // Get name of type. + RestrictWeaponTypeGetName(x, typename, sizeof(typename)); + + // Add item to menu. + AddMenuItem(menu_weapons_types, typename, typename); } - SetMenuExitBackButton(menu_weapons_weapons, true); + // If there are no weapons, add an "(Empty)" line. + if (size == 0) + { + decl String:empty[64]; + Format(empty, sizeof(empty), "%t", "Menu empty"); - DisplayMenu(menu_weapons_weapons, client, MENU_TIME_FOREVER); + AddMenuItem(menu_weapons_types, "empty", empty, ITEMDRAW_DISABLED); + } + + // Set exit back button. + SetMenuExitBackButton(menu_weapons_types, true); + + DisplayMenu(menu_weapons_types, client, MENU_TIME_FOREVER); } /** * Called when client selects option in the weapons list menu, and handles it. - * @param menu_weapons_main Handle of the menu being used. + * @param menu_weapons_types 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 WeaponsMenuWeaponsHandle(Handle:menu_weapons_weapons, MenuAction:action, client, slot) +public WeaponsMenuTypesHandle(Handle:menu_weapons_types, MenuAction:action, client, slot) { // Client selected an option. if (action == MenuAction_Select) { - decl String:weapon[WEAPONS_MAX_LENGTH]; - GetMenuItem(menu_weapons_weapons, slot, weapon, sizeof(weapon)); + // Menu slot index is = weapon type index. + g_iCurWeaponType[client] = slot; - switch(curMenuWeapons[client]) - { - // Client is restricting a single weapon. - case Weapon: - { - new WpnRestrictQuery:output; - - if (!RestrictIsWeaponRestricted(weapon)) - { - output = RestrictRestrict(weapon); - RestrictPrintRestrictOutput(client, output, weapon, false); - } - else - { - output = RestrictUnrestrict(weapon); - RestrictPrintUnrestrictOutput(client, output, weapon, false); - } - - // Resend menu. - WeaponsMenuWeapons(client, curMenuWeapons[client]); - } - // Client is accessing a weapon group. - case WeaponGroup: - { - // Send weapon group menu. - WeaponsMenuWeaponGroup(client, weapon); - } - } + // Send weapons of the selected type in a menu to client. + WeaponsMenuTypeWeapons(client); } // Client closed the menu. if (action == MenuAction_Cancel) @@ -272,118 +158,141 @@ public WeaponsMenuWeaponsHandle(Handle:menu_weapons_weapons, MenuAction:action, // Client hit "Exit" button. else if (action == MenuAction_End) { - CloseHandle(menu_weapons_weapons); + CloseHandle(menu_weapons_types); } } -WeaponsMenuWeaponGroup(client, const String:weapongroup[]) +/** + * Sends a list of weapons of a certain type in a menu to the client. + * @param client The client index. + */ +WeaponsMenuTypeWeapons(client) { - strcopy(curMenuGroup[client], WEAPONS_MAX_LENGTH, weapongroup); - // Create menu handle. - new Handle:menu_weapons_groupweapon = CreateMenu(WeaponsMenuWeaponGroupHandle); + new Handle:menu_weapons_typeweapons = CreateMenu(WeaponsMenuTypeWeaponsHandle); - SetMenuTitle(menu_weapons_groupweapon, "%t\n ", "Weapons menu weapon group title", weapongroup); + decl String:typename[WEAPONS_MAX_LENGTH]; + RestrictWeaponTypeGetName(g_iCurWeaponType[client], typename, sizeof(typename)); + + SetMenuTitle(menu_weapons_typeweapons, "%t\n ", "Weapons menu types type title", typename); decl String:restrictall[64]; decl String:unrestrictall[64]; - Format(restrictall, sizeof(restrictall), "%t", "Weapons menu weapon group restrict all"); - Format(unrestrictall, sizeof(unrestrictall), "%t", "Weapons menu weapon group unrestrict all"); + Format(restrictall, sizeof(restrictall), "%t", "Weapons menu types restrict all", typename); + Format(unrestrictall, sizeof(unrestrictall), "%t", "Weapons menu types unrestrict all", typename); - if (RestrictIsGroupRestricted(weapongroup)) - { - AddMenuItem(menu_weapons_groupweapon, "restrictall", restrictall, ITEMDRAW_DISABLED); - } - else - { - AddMenuItem(menu_weapons_groupweapon, "restrictall", restrictall); - } + // Draw items as selectable only if not all weapons within the type are restricted or unrestricted. + AddMenuItem(menu_weapons_typeweapons, "restrictall", restrictall, MenuGetItemDraw(!RestrictIsTypeUniform(true, g_iCurWeaponType[client]))); + AddMenuItem(menu_weapons_typeweapons, "unrestrictall", unrestrictall, MenuGetItemDraw(!RestrictIsTypeUniform(false, g_iCurWeaponType[client]))); - if (RestrictIsGroupUnrestricted(weapongroup)) - { - AddMenuItem(menu_weapons_groupweapon, "unrestrictall", unrestrictall, ITEMDRAW_DISABLED); - } - else - { - AddMenuItem(menu_weapons_groupweapon, "unrestrictall", unrestrictall); - } + decl String:typeweapon[WEAPONS_MAX_LENGTH]; + decl String:display[WEAPONS_MAX_LENGTH]; - decl String:groupweapon[WEAPONS_MAX_LENGTH]; - decl String:display[WEAPONS_MAX_LENGTH + 1]; - new Handle:arrayGroupWeapons = INVALID_HANDLE; - new size = RestrictCreateGroupWeaponsArray(arrayGroupWeapons, weapongroup); + // Get an array populated with all weapons of the given type. + new Handle:arrayTypeWeapons; + new count = RestrictGetTypeWeapons(g_iCurWeaponType[client], arrayTypeWeapons); // x = Array index. - for (new x = 0; x < size; x++) + for (new x = 0; x < count; x++) { - GetArrayString(arrayGroupWeapons, x, groupweapon, sizeof(groupweapon)); + // Get weapon index to check restricted status of. + new weaponindex = GetArrayCell(arrayTypeWeapons, x); - strcopy(display, sizeof(display), groupweapon); + // Get name of weapon. + WeaponsGetName(weaponindex, typeweapon, sizeof(typeweapon)); + strcopy(display, sizeof(display), typeweapon); - if (RestrictIsWeaponRestricted(groupweapon)) + if (RestrictIsWeaponRestricted(weaponindex)) { - Format(display, sizeof(display), "%s*", groupweapon); + Format(display, sizeof(display), "[%s]", typeweapon); } - AddMenuItem(menu_weapons_groupweapon, groupweapon, display); + // Disable option if it isn't toggleable. + AddMenuItem(menu_weapons_typeweapons, typeweapon, display, MenuGetItemDraw(WeaponsGetToggleable(weaponindex))); } - // Kill the array handle. - CloseHandle(arrayGroupWeapons); + // Destroy the array handle. + CloseHandle(arrayTypeWeapons); - SetMenuExitBackButton(menu_weapons_groupweapon, true); - - DisplayMenu(menu_weapons_groupweapon, client, MENU_TIME_FOREVER); + // Set menu back button. + SetMenuExitBackButton(menu_weapons_typeweapons, true); + + // Display menu to client. + DisplayMenu(menu_weapons_typeweapons, client, MENU_TIME_FOREVER); } /** * Called when client selects option in the weapon group menu, and handles it. - * @param menu_weapons_main 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). + * @param menu_weapons_typeweapons 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 WeaponsMenuWeaponGroupHandle(Handle:menu_weapons_groupweapon, MenuAction:action, client, slot) +public WeaponsMenuTypeWeaponsHandle(Handle:menu_weapons_typeweapons, MenuAction:action, client, slot) { // Client selected an option. if (action == MenuAction_Select) { + // Get name of current weapon type. + decl String:typename[WEAPONS_MAX_LENGTH]; + RestrictWeaponTypeGetName(g_iCurWeaponType[client], typename, sizeof(typename)); + + new RestrictQuery:query; + new bool:single; + new bool:restrict; + decl String:returntarget[WEAPONS_MAX_LENGTH]; + switch(slot) { case 0: { - new WpnRestrictQuery:output = RestrictRestrict(curMenuGroup[client]); - RestrictPrintRestrictOutput(client, output, curMenuGroup[client], false); + // Restrict all weapons of this type. + restrict = true; + query = RestrictWeapon(true, typename, single, returntarget, sizeof(returntarget)); } case 1: { - new WpnRestrictQuery:output = RestrictUnrestrict(curMenuGroup[client]); - RestrictPrintUnrestrictOutput(client, output, curMenuGroup[client], false); + // Unrestrict all weapons of this type. + restrict = false; + query = RestrictWeapon(false, typename, single, returntarget, sizeof(returntarget)); } - default: { - new WpnRestrictQuery:output; + // Get weappon name. + decl String:typeweapon[WEAPONS_MAX_LENGTH]; + GetMenuItem(menu_weapons_typeweapons, slot, typeweapon, sizeof(typeweapon)); - decl String:groupweapon[WEAPONS_MAX_LENGTH]; - GetMenuItem(menu_weapons_groupweapon, slot, groupweapon, sizeof(groupweapon)); + // Get weapon index. + new weaponindex = WeaponsNameToIndex(typeweapon); - if (!RestrictIsWeaponRestricted(groupweapon)) + // If weapon index is -1, then something went very wrong. + if (weaponindex == -1) { - output = RestrictRestrict(groupweapon); - RestrictPrintRestrictOutput(client, output, groupweapon, false); + CloseHandle(menu_weapons_typeweapons); + } + + // If weapon isn't restricted, then restrict it. + if (!RestrictIsWeaponRestricted(weaponindex)) + { + // Restrict this weapon. + restrict = true; + query = RestrictWeapon(true, typeweapon, single, returntarget, sizeof(returntarget)); } else { - output = RestrictUnrestrict(groupweapon); - RestrictPrintUnrestrictOutput(client, output, groupweapon, false); + // Unrestrict this weapon. + restrict = false; + query = RestrictWeapon(false, typeweapon, single, returntarget, sizeof(returntarget)); } } } + // Print query response. + RestrictPrintQueryResponse(client, query, single, restrict, returntarget); + // Resend menu. - WeaponsMenuWeaponGroup(client, curMenuGroup[client]); + WeaponsMenuTypeWeapons(client); } // Client closed the menu. if (action == MenuAction_Cancel) @@ -391,37 +300,38 @@ public WeaponsMenuWeaponGroupHandle(Handle:menu_weapons_groupweapon, MenuAction: // Client hit "Back" button. if (slot == MenuCancel_ExitBack) { - WeaponsMenuWeapons(client, curMenuWeapons[client]); + WeaponsMenuTypes(client); } } // Client hit "Exit" button. else if (action == MenuAction_End) { - CloseHandle(menu_weapons_groupweapon); + CloseHandle(menu_weapons_typeweapons); } } /** - * Sends market options menu to client. + * Sends ZMarket options menu to client. * @param client The client index. - */ -WeaponsMenuMarket(client) + */ +WeaponsMenuZMarket(client) { // Create menu handle. - new Handle:menu_weapons_market = CreateMenu(WeaponsMenuMarketHandle); + new Handle:menu_weapons_market = CreateMenu(WeaponsMenuZMarketHandle); SetGlobalTransTarget(client); - SetMenuTitle(menu_weapons_market, "%t\n ", "Weapons menu market title"); + SetMenuTitle(menu_weapons_market, "%t\n ", "Weapons menu zmarket title"); - decl String:togglebuyzone[64]; + decl String:buyzone[64]; + decl String:buyzonesetting[8]; - decl String:curSetting[8]; - ConfigBoolToSetting(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]), curSetting, sizeof(curSetting)); + // Get "yes" or "no" settings from respective cvar. + ConfigBoolToSetting(GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]), buyzonesetting, sizeof(buyzonesetting)); - Format(togglebuyzone, sizeof(togglebuyzone), "%t", "Weapons menu market toggle buyzone", curSetting); - - AddMenuItem(menu_weapons_market, "togglebuyzone", togglebuyzone); + // Add options to menu. + Format(buyzone, sizeof(buyzone), "%t", "Weapons menu zmarket buyzone", buyzonesetting); + AddMenuItem(menu_weapons_market, "buyzone", buyzone); // Create a "Back" button to the weapons main menu. SetMenuExitBackButton(menu_weapons_market, true); @@ -432,33 +342,29 @@ WeaponsMenuMarket(client) /** * Called when client selects option in the weapons main menu, and handles it. - * @param menu_weapons_main Handle of the menu being used. + * @param menu_weapons_market 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 WeaponsMenuMarketHandle(Handle:menu_weapons_market, MenuAction:action, client, slot) +public WeaponsMenuZMarketHandle(Handle:menu_weapons_market, MenuAction:action, client, slot) { // Client selected an option. if (action == MenuAction_Select) { switch(slot) { + // Buyzone. case 0: { - if (GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE])) - { - SetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE], false); - } - else - { - SetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE], true); - } + // Toggle cvar. + new bool:zmarketbuyzone = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE]); + SetConVarBool(g_hCvarsList[CVAR_WEAPONS_ZMARKET_BUYZONE], !zmarketbuyzone); } } // Resend menu. - WeaponsMenuMarket(client); + WeaponsMenuZMarket(client); } // Client closed the menu. if (action == MenuAction_Cancel) diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index ad1570d..81cd94d 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -11,31 +11,37 @@ */ /** - * Array to store restricted weapon names. + * Maximum types allowed for a single weapon. */ -new Handle:gRestrictedWeapons = INVALID_HANDLE; +#define WEAPONS_RESTRICT_MAX_TYPES 8 /** - * Keyvalue handle to store weapon groups data. - * - * @redir config.inc + * Restrict config data indexes. */ +enum RestrictData +{ + RESTRICT_DATA_NAME = 0, +} /** * Array that stores the "HookID" to be later unhooked on player disconnect. */ new g_iCanUseHookID[MAXPLAYERS + 1] = {-1, ...}; +/** + * Array to store a list of different weapon groups + */ +new Handle:arrayWeaponTypes = INVALID_HANDLE; + /** * Query results returned when (un)restricting a weapon. */ -enum WpnRestrictQuery +enum RestrictQuery { - Successful_Weapon, /** Weapon (un)restrict query was successful. */ - Successful_Group, /** Group (un)restrict query was successful. */ - Failed_Weapon, /** Weapon (un)restrict was unsuccessful */ - Failed_Group, /** Group (un)restrict was unsuccessful */ - WeaponInvalid, /** Weapon/Group invalid */ + Query_Successful, /** (Un)restrict was successful. */ + Query_Stopped, /** (Un)restrict was stopped because action was redundant. */ + Query_Locked, /** (Un)restrict was stopped because the weapon is marked "untoggleable." */ + Query_Invalid, /** (Un)restrict failed because invalid info was given. */ } /** @@ -43,163 +49,65 @@ enum WpnRestrictQuery */ RestrictInit() { - // Initialize weapon restrict array. - gRestrictedWeapons = CreateArray(WEAPONS_MAX_LENGTH, 0); - // Hook buy command. RegConsoleCmd("buy", RestrictBuyCommand); RegConsoleCmd("autobuy", RestrictBuyCommand); RegConsoleCmd("rebuy", RestrictBuyCommand); } +/** + * Auto-create a list of types loaded by weapons module. + */ +RestrictLoad() +{ + // If array exists, then destroy it. + if (arrayWeaponTypes != INVALID_HANDLE) + { + CloseHandle(arrayWeaponTypes); + } + + // Initialize array. + arrayWeaponTypes = CreateArray(WEAPONS_MAX_LENGTH); + + decl String:weapontype[WEAPONS_MAX_LENGTH]; + new String:weapontypes[WEAPONS_RESTRICT_MAX_TYPES][WEAPONS_MAX_LENGTH]; + + // x = array index + new size = GetArraySize(arrayWeapons); + for (new x = 0; x < size; x++) + { + WeaponsGetType(x, weapontype, sizeof(weapontype)); + + ExplodeString(weapontype, ",", weapontypes, WEAPONS_RESTRICT_MAX_TYPES, WEAPONS_MAX_LENGTH); + for (new y = 0; y < WEAPONS_RESTRICT_MAX_TYPES; y++) + { + // Cut off whitespace. + TrimString(weapontypes[y]); + + // If we've reached the end of the weapon's types, then stop. + if (!weapontypes[y][0]) + { + break; + } + + // If the weapon type isn't in the main array, then push it in. + if (FindStringInArray(arrayWeaponTypes, weapontypes[y]) == -1) + { + // Push weapon type name into weapon type array. + PushArrayString(arrayWeaponTypes, weapontypes[y]); + } + } + } +} + /** * Hook commands related to restrict here. */ RestrictOnCommandsCreate() { // Create weapon admin commands. - RegAdminCmd("zr_restrict", RestrictRestrictCommand, ADMFLAG_GENERIC, "Restrict a weapon. Usage: zr_restrict "); - RegAdminCmd("zr_unrestrict", RestrictUnrestrictCommand, ADMFLAG_GENERIC, "Unrestrict a weapon. Usage: zr_unrestrict "); -} - -/** - * Clears weapon restrict data. - */ -RestrictClearData() -{ - // Clear restricted weapons. - RestrictWeaponUnrestrictAll(); - - // Load weapon group data. - if (kvWeaponGroups != INVALID_HANDLE) - { - CloseHandle(kvWeaponGroups); - } - - kvWeaponGroups = CreateKeyValues("weapongroups"); -} - -/** - * Loads weapon data from file. - */ -RestrictLoad() -{ - // Clear weapon restrict data. - RestrictClearData(); - - // If module is disabled, then stop. - new bool:restrict = GetConVarBool(g_hCvarsList[CVAR_WEAPONS_RESTRICT]); - if (!restrict) - { - return; - } - - // Restrict default restrictions. (set in weapons.txt) - RestrictDefaultRestrictions(); - - // Get weapon groups config path. - decl String:pathweapongroups[PLATFORM_MAX_PATH]; - new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_WEAPONGROUPS, pathweapongroups); - - // If file doesn't exist, then log and stop. - if (!exists) - { - // Log failure. - LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapon Restrict", "Config Validation", "Missing weapon groups config file: %s", pathweapongroups); - - return; - } - - // Put file data into memory. - FileToKeyValues(kvWeaponGroups, pathweapongroups); - - // Validate weapon groups config. - RestrictValidateWeaponGroups(); -} - -/** - * Restrict default restrictions. (set in weapons.txt) - */ -RestrictDefaultRestrictions() -{ - KvRewind(kvWeapons); - - if (KvGotoFirstSubKey(kvWeapons)) - { - decl String:weapon[WEAPONS_MAX_LENGTH]; - decl String:display[WEAPONS_MAX_LENGTH]; - - do - { - KvGetSectionName(kvWeapons, weapon, sizeof(weapon)); - - // If weapon is defaulted to restricted, then restrict weapon. - decl String:restrict[8]; - KvGetString(kvWeapons, "restrict", restrict, sizeof(restrict), "no"); - - if (ConfigSettingToBool(restrict)) - { - new WpnRestrictQuery:output = RestrictRestrict(weapon, display); - RestrictPrintRestrictOutput(0, output, display, true); - - // Function calls above screwed with the keyvalue stack, so we have to set it back - // to where it was before those calls. - KvRewind(kvWeapons); - KvJumpToKey(kvWeapons, weapon); - } - } while (KvGotoNextKey(kvWeapons)); - } -} - -/** - * Validate weapon group options - */ -RestrictValidateWeaponGroups() -{ - // Reset keygroup's traversal stack. - KvRewind(kvWeaponGroups); - - // Traverse into the keygroup. (weapon groups level) - if (KvGotoFirstSubKey(kvWeaponGroups)) - { - decl String:weapongroup[WEAPONS_MAX_LENGTH]; - decl String:groupweapon[WEAPONS_MAX_LENGTH]; - - do - { - 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)) - { - LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapon Restrict", "Config Validation", "Invalid weapon \"%s\" in group \"%s\" configured in weapongroups.txt.", groupweapon, weapongroup); - } - } while (KvGotoNextKey(kvWeaponGroups)); - - KvGoBack(kvWeaponGroups); - } - // If it couldn't traverse to the weapons, then log no weapons within group. - else - { - LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapon Restrict", "Config Validation", "No weapons listed in weapon group \"%s\" in weapongroups.txt.", weapongroup); - } - } while (KvGotoNextKey(kvWeaponGroups)); - } -} - -/** - * Clears restricted weapon array. - */ -RestrictWeaponUnrestrictAll() -{ - ClearArray(gRestrictedWeapons); + RegAdminCmd("zr_restrict", RestrictCommand, ADMFLAG_GENERIC, "Restricts a weapon or a weapon type. Usage: zr_restrict [weapon2|weapontype2] ..."); + RegAdminCmd("zr_unrestrict", UnrestrictCommand, ADMFLAG_GENERIC, "Unrestricts a weapon or a weapon type. Usage: zr_unrestrict [weapon2|weapontype2] ..."); } /** @@ -263,8 +171,18 @@ public Action:RestrictBuyCommand(client, argc) ReplaceString(weapon, sizeof(weapon), "weapon_", ""); - // Check if the weapon is restricted, if so then block command. - if (RestrictIsWeaponRestricted(weapon)) + // If the weapon is restricted, then prevent pickup. + new index = WeaponsNameToIndex(weapon); + + // If weapon isn't configged, then allow pickup. + if (index == -1) + { + // Allow pickup. + return Plugin_Continue; + } + + // If weapon is restricted, then stop. + if (RestrictIsWeaponRestricted(index)) { TranslationPrintToChat(client, "Weapon is restricted", weapon); @@ -277,574 +195,320 @@ public Action:RestrictBuyCommand(client, argc) } /** - * Restricts a weapon. + * Restricts (or unrestricts) a given weapon or weapon type. * - * @param weapon The weapon/group name. - * @param display String set to the name set in weapons.txt - * Set to the value of 'weapon' if invalid - * @return Successful_Weapon: The call successfully restricted a weapon. - * Successful_Group: The call successfully restricted a weapon group. - * Failed_Weapon: The call failed to restrict a weapon. - * Failed_Group: The call failed to restrict a weapon group. - * WeaponInvalid: The call was unsuccessful due to invalid weapon. + * @param restrict True to restrict, false to unrestrict. + * @param target Weapon or weapon type to restrict/unrestrict. + * @param single True if a single weapon is being restricted, false if weapon type. + * @param returntarget The proper targetname. (same as param 'target' if invalid) + * @param maxlen The maximum length of param 'returntarget.' + * @return Query result. (See enum RestrictQuery) */ -WpnRestrictQuery:RestrictRestrict(const String:weapon[], String:display[] = "") +RestrictQuery:RestrictWeapon(bool:restrict, const String:target[], &bool:single = true, String:returntarget[], maxlen) { - // Check if weapon is a custom group name. - if (RestrictIsWeaponGroup(weapon)) + // Strip "weapon_" from target. + ReplaceString(target, WEAPONS_MAX_LENGTH, "weapon_", ""); + + // Copy 'target' to 'returntarget' to be possibly changed later. + strcopy(returntarget, maxlen, target); + + // Find index of the given weapon type. + new typeindex = RestrictTypeToIndex(target); + + // Single weapon. + if (typeindex == -1) { - // Return restrict failed if group is already restricted. - if (RestrictIsGroupRestricted(weapon)) + single = true; + + new weaponindex = WeaponsNameToIndex(target); + + // If weapon index is invalid, then return invalid. + if (weaponindex == -1) { - return Failed_Group; + return Query_Invalid; } - // Jump to weapon group key. - KvRewind(kvWeaponGroups); - KvJumpToKey(kvWeaponGroups, weapon); + // Return proper weapon name. + WeaponsGetName(weaponindex, returntarget, maxlen); - // Get display name of the weapon group. - KvGetSectionName(kvWeaponGroups, display, WEAPONS_MAX_LENGTH); - - // Traverse into the group's weapons. - if (KvGotoFirstSubKey(kvWeaponGroups)) + // If weapon is untoggleable, then return locked. + if (!WeaponsGetToggleable(weaponindex)) { - decl String:groupweapon[WEAPONS_MAX_LENGTH]; + return Query_Locked; + } + + // If weapon restriction is redundant then return stopped. + if (RestrictIsWeaponRestricted(weaponindex) == restrict) + { + return Query_Stopped; + } + + // Set weapon's restricted state. + RestrictSetWeaponRestricted(weaponindex, false, restrict); + + // Successfully restricted weapon. + return Query_Successful; + } + // Weapon type. + else + { + single = false; + + // Get all weapons in the given type. + new Handle:arrayTypeWeapons; + new count = RestrictGetTypeWeapons(typeindex, arrayTypeWeapons); + + // Return proper weapon name. + RestrictWeaponTypeGetName(typeindex, returntarget, maxlen); + + // If weapon restriction is redundant then return stopped. + if (RestrictIsTypeUniform(restrict, typeindex)) + { + return Query_Stopped; + } + + for (new x = 0; x < count; x++) + { + // Get weapon index. + new weaponindex = GetArrayCell(arrayTypeWeapons, x); - do - { - KvGetSectionName(kvWeaponGroups, groupweapon, sizeof(groupweapon)); - - // If weapon is invalid, then skip. - if (!WeaponsIsValidWeapon(groupweapon)) - { - continue; - } - - // Add to restricted weapon array if not already restricted. - if (!RestrictIsWeaponRestricted(groupweapon)) - { - PushArrayString(gRestrictedWeapons, groupweapon); - } - } while (KvGotoNextKey(kvWeaponGroups)); - } - - // Successfully restricted a group - return Successful_Group; - } - - // If weapon name is invalid then set display to invalid weapon name. - if (!WeaponsIsValidWeapon(weapon)) - { - strcopy(display, WEAPONS_MAX_LENGTH, weapon); - - // Weapon name was invalid. - return WeaponInvalid; - } - - // Get display name of the weapon. - WeaponsGetDisplayName(weapon, display); - - // Return restrict failed if weapon is already restricted. - if (RestrictIsWeaponRestricted(weapon)) - { - return Failed_Weapon; - } - - // Add to restricted weapon array. - PushArrayString(gRestrictedWeapons, display); - - return Successful_Weapon; -} - -/** - * Unrestricts a weapon. - * - * @param weapon The weapon/group name. - * @param display String set to the name set in weapons.txt. - * Set to the value of 'weapon' if invalid. - * @return Successful_Weapon: The call successfully restricted a weapon. - * Successful_Group: The call successfully restricted a weapon group. - * Failed_Weapon: The call failed to restrict a weapon. - * Failed_Group: The call failed to restrict a weapon group. - * WeaponInvalid: The call was unsuccessful due to invalid weapon. - */ -WpnRestrictQuery:RestrictUnrestrict(const String:weapon[], String:display[] = "") -{ - // Check if weapon is a custom group name. - if (RestrictIsWeaponGroup(weapon)) - { - // Jump to weapon group key. - KvRewind(kvWeaponGroups); - KvJumpToKey(kvWeaponGroups, weapon); - - // Get display name of the weapon group. - KvGetSectionName(kvWeaponGroups, display, WEAPONS_MAX_LENGTH); - - // Return restrict failed if group isn't restricted. - if (RestrictIsGroupUnrestricted(weapon)) - { - return Failed_Group; - } - - // Traverse into the group's weapons. - if (KvGotoFirstSubKey(kvWeaponGroups)) - { - decl String:groupweapon[WEAPONS_MAX_LENGTH]; - - do - { - KvGetSectionName(kvWeaponGroups, groupweapon, sizeof(groupweapon)); - - // If weapon is invalid, then skip - if (!WeaponsIsValidWeapon(groupweapon)) - { - continue; - } - - // Remove from restricted weapon array if currently restricted. - if (RestrictIsWeaponRestricted(groupweapon)) - { - // Verify weapon is in the array. - new weaponindex = RestrictGetIndex(groupweapon); - if (weaponindex > -1) - { - RemoveFromArray(gRestrictedWeapons, weaponindex); - } - } - } while (KvGotoNextKey(kvWeaponGroups)); - } - - // Successfully unrestricted a group - return Successful_Group; - } - - // If weapon name is invalid then set display to invalid weapon name. - if (!WeaponsIsValidWeapon(weapon)) - { - strcopy(display, WEAPONS_MAX_LENGTH, weapon); - - return WeaponInvalid; - } - - // Get display name of the weapon. - WeaponsGetDisplayName(weapon, display); - - // Return unrestrict failed if weapon isn't restricted. - if (!RestrictIsWeaponRestricted(weapon)) - { - return Failed_Weapon; - } - - // Verify weapon is in the array. - new weaponindex = RestrictGetIndex(display); - if (weaponindex > -1) - { - // Remove from restricted weapon array. - RemoveFromArray(gRestrictedWeapons, weaponindex); - } - - return Successful_Weapon; -} - -/** - * Prints text to server or client based off the output it RestrictRestrict(). - * @param client The client index. - * @param output The output of RestrictRestrict(). - * @param weapon The weapon client is trying to restrict. - * @param cmd True if printing output in reply to a client command. - */ -RestrictPrintRestrictOutput(client, WpnRestrictQuery:output, const String:weapon[], bool:reply) -{ - switch(output) - { - // Weapon was successfully restricted. - case Successful_Weapon: - { - TranslationPrintToChatAll(true, false, "Restrict weapon", weapon); - LogPrintToLog(LOG_FORMAT_TYPE_NORMAL, "Weapon Restrict", "Restrict", "\"%L\" restricted weapon: \"%s\".", client, weapon); - } - // Weapon group was successfully restricted. - case Successful_Group: - { - decl String:weaponlist[128]; - RestrictGetGroupWeapons(weapon, weaponlist, sizeof(weaponlist), ", "); - - TranslationPrintToChatAll(true, false, "Restrict custom weapon group", weapon, weaponlist); - LogPrintToLog(LOG_FORMAT_TYPE_NORMAL, "Weapon Restrict", "Restrict", "\"%L\" restricted weapon group: \"%s\".", client, weapon); - } - // Weapon was already restricted. - case Failed_Weapon: - { - if (reply) - { - TranslationReplyToCommand(client, "Restrict weapon failed", weapon); - } - else - { - TranslationPrintToChat(client, "Restrict weapon failed", weapon); - } - } - // Weapon group was already restricted. - case Failed_Group: - { - decl String:weaponlist[128]; - RestrictGetGroupWeapons(weapon, weaponlist, sizeof(weaponlist), ", "); - - if (reply) - { - TranslationReplyToCommand(client, "Restrict custom weapon group failed", weapon, weaponlist); - } - else - { - TranslationPrintToChat(client, "Restrict custom weapon group failed", weapon, weaponlist); - } - } - // Weapon name was invalid. - case WeaponInvalid: - { - if (reply) - { - TranslationReplyToCommand(client, "Weapon invalid", weapon); - } - else - { - TranslationPrintToChat(client, "Weapon invalid", weapon); - } - } - } -} - -/** - * Prints text to server or client based off the output it RestrictUnrestrict(). - * @param client The client index. - * @param output The output of RestrictUnrestrict(). - * @param weapon The weapon client is trying to unrestrict. - * @param cmd True if printing output in reply to a client command. - */ -RestrictPrintUnrestrictOutput(client, WpnRestrictQuery:output, const String:weapon[], bool:reply) -{ - switch(output) - { - // Weapon was successfully unrestricted. - case Successful_Weapon: - { - TranslationPrintToChatAll(true, false, "Unrestrict weapon", weapon); - LogPrintToLog(LOG_FORMAT_TYPE_NORMAL, "Weapon Restrict", "Unrestrict", "\"%L\" unrestricted weapon: \"%s\".", client, weapon); - - } - // Weapon group was successfully unrestricted. - case Successful_Group: - { - decl String:weaponlist[128]; - RestrictGetGroupWeapons(weapon, weaponlist, sizeof(weaponlist), ", "); - - TranslationPrintToChatAll(true, false, "Unrestrict custom weapon group", weapon, weaponlist); - LogPrintToLog(LOG_FORMAT_TYPE_NORMAL, "Weapon Restrict", "Unrestrict", "\"%L\" unrestricted weapon group: \"%s\".", client, weapon); - } - // Weapon wasn't restricted. - case Failed_Weapon: - { - if (reply) - { - TranslationReplyToCommand(client, "Unrestrict weapon failed", weapon); - } - else - { - TranslationPrintToChat(client, "Unrestrict weapon failed", weapon); - } - } - // Weapon group wasn't restricted. - case Failed_Group: - { - decl String:weaponlist[128]; - RestrictGetGroupWeapons(weapon, weaponlist, sizeof(weaponlist), ", "); - - if (reply) - { - TranslationReplyToCommand(client, "Unrestrict custom weapon group failed", weapon, weaponlist); - } - else - { - TranslationPrintToChat(client, "Unrestrict custom weapon group failed", weapon, weaponlist); - } - } - // Weapon name was invalid. - case WeaponInvalid: - { - if (reply) - { - TranslationReplyToCommand(client, "Weapon invalid", weapon); - } - else - { - TranslationPrintToChat(client, "Weapon invalid", weapon); - } - } - } -} - -/** - * Checks if a weapon is restricted. - * - * @param weapon The weapon name. - * @return True if weapon is restricted, false if not. - */ -bool:RestrictIsWeaponRestricted(const String:weapon[]) -{ - decl String:restrictedweapon[WEAPONS_MAX_LENGTH]; - - new size = GetArraySize(gRestrictedWeapons); - - // x = restricted weapon index. - for (new x = 0; x < size; x++) - { - GetArrayString(gRestrictedWeapons, x, restrictedweapon, sizeof(restrictedweapon)); - - // Check if weapon matches any weapon names in the restricted weapon array. - if (StrEqual(weapon, restrictedweapon, false)) - { - // Weapon is restricted. - return true; - } - } - - // Weapon is not restricted. - return false; -} - -/** - * Checks if a weapon group is completely restricted. - * - * @param weapongroup The weapon group name. - */ -bool:RestrictIsGroupRestricted(const String:weapongroup[]) -{ - // Reset keygroup's traversal stack. - KvRewind(kvWeaponGroups); - - // Traverse in to the group names. - if (KvJumpToKey(kvWeaponGroups, weapongroup)) - { - decl String:groupweapon[WEAPONS_MAX_LENGTH]; - - // Traverse into the group's weapons. - if (KvGotoFirstSubKey(kvWeaponGroups)) - { - do - { - KvGetSectionName(kvWeaponGroups, groupweapon, WEAPONS_MAX_LENGTH); - - // Return false is a weapon isn't restricted, but only if the weapon is valid (we ignore invalid ones) - if (WeaponsIsValidWeapon(groupweapon) && !RestrictIsWeaponRestricted(groupweapon)) - { - return false; - } - } while (KvGotoNextKey(kvWeaponGroups)); - - return true; - } - } - - return false; -} - -/** - * Checks if a weapon group is completely unrestricted. - * - * @param weapongroup The weapon group name. - */ -bool:RestrictIsGroupUnrestricted(const String:weapongroup[]) -{ - // Reset keygroup's traversal stack. - KvRewind(kvWeaponGroups); - - // Traverse in to the group names. - if (KvJumpToKey(kvWeaponGroups, weapongroup)) - { - decl String:groupweapon[WEAPONS_MAX_LENGTH]; - - // Traverse into the group's weapons. - if (KvGotoFirstSubKey(kvWeaponGroups)) - { - do - { - KvGetSectionName(kvWeaponGroups, groupweapon, WEAPONS_MAX_LENGTH); - - // Return false if a weapon is restricted - if (RestrictIsWeaponRestricted(groupweapon)) - { - return false; - } - } while (KvGotoNextKey(kvWeaponGroups)); - - return true; - } - } - - return false; -} - -/** - * Checks if a weapon group is partially restricted. - * - * @param weapongroup The weapon group name. - */ -bool:RestrictIsPartialRestricted(const String:weapongroup[]) -{ - return (!RestrictIsGroupRestricted(weapongroup) && !RestrictIsGroupUnrestricted(weapongroup)); -} - -/** - * Returns the array index of the restricted weapon. - * - * @param weapon The weapon name. - */ -RestrictGetIndex(const String:weapon[]) -{ - decl String:restrictedweapon[WEAPONS_MAX_LENGTH]; - - new size = GetArraySize(gRestrictedWeapons); - - // x = restricted weapon index. - for (new x = 0; x < size; x++) - { - GetArrayString(gRestrictedWeapons, x, restrictedweapon, sizeof(restrictedweapon)); - - // Check if weapon matches weapon in restricted weapons array. - if (StrEqual(weapon, restrictedweapon, false)) - { - // Return restricted weapon's index. - return x; - } - } - - // Weapon isn't restricted. - return -1; -} - -/** - * Checks if the provided name is a custom group. - * - * @param groupname Name of the group to check. - * @return True if it's a group, false if not. - */ -bool:RestrictIsWeaponGroup(const String:groupname[]) -{ - // Reset keygroup's traversal stack. - KvRewind(kvWeaponGroups); - - // Returns true if groupname is listed in the custom groups file. - return KvJumpToKey(kvWeaponGroups, groupname); -} - -/** - * Creates an array of all listed weapon groups in weapongroups.txt. - * @param arrayWeaponGroups The handle of the array, don't forget to call CloseHandle - * on it when finished! - * @return The size of the array. - */ -RestrictCreateGroupArray(&Handle:arrayWeaponGroups, maxlen = WEAPONS_MAX_LENGTH) -{ - arrayWeaponGroups = CreateArray(maxlen); - new count = 0; - - KvRewind(kvWeaponGroups); - if (KvGotoFirstSubKey(kvWeaponGroups)) - { - decl String:weapongroup[maxlen]; - - do - { - KvGetSectionName(kvWeaponGroups, weapongroup, maxlen); - - PushArrayString(arrayWeaponGroups, weapongroup); - count++; - } while (KvGotoNextKey(kvWeaponGroups)); - } - - return count; -} - -/** - * Creates an array of all weapons listed in a custom weapon group. - * @param arrayWeaponGroups The handle of the array, don't forget to call CloseHandle - * on it when finished! - * @return The size of the array. - */ -RestrictCreateGroupWeaponsArray(&Handle:arrayGroupWeapons, const String:weapongroup[], maxlen = WEAPONS_MAX_LENGTH) -{ - arrayGroupWeapons = CreateArray(maxlen); - new count = 0; - - KvRewind(kvWeaponGroups); - if (KvJumpToKey(kvWeaponGroups, weapongroup)) - { - decl String:groupweapon[maxlen]; - - if (KvGotoFirstSubKey(kvWeaponGroups)) - { - do - { - KvGetSectionName(kvWeaponGroups, groupweapon, maxlen); - - // If the weapon is invalid, then stop. - if (!WeaponsIsValidWeapon(groupweapon)) - { - continue; - } - - PushArrayString(arrayGroupWeapons, groupweapon); - count++; - } while (KvGotoNextKey(kvWeaponGroups)); - } - } - - return count; -} - -/** - * Returns a string of all weapons in a custom weapon group separated - * by the provided character. - * - * @param groupname Name of the group to get weapon list from. - * @param weaponlist Variable to store weapon list string in. - * @param maxlen Maximum length of the weapon list, the rest is truncated. - * @param separator Separator character between weapon names. - */ -RestrictGetGroupWeapons(const String:groupname[], String:weaponlist[], maxlen, const String:separator[]) -{ - KvRewind(kvWeaponGroups); - KvJumpToKey(kvWeaponGroups, groupname); - - if (KvGotoFirstSubKey(kvWeaponGroups)) - { - decl String:groupweapon[WEAPONS_MAX_LENGTH]; - - strcopy(weaponlist, maxlen, ""); - - do - { - KvGetSectionName(kvWeaponGroups, groupweapon, sizeof(groupweapon)); - - // If weapon is invalid, then skip. - if (!WeaponsIsValidWeapon(groupweapon)) + // If weapon is untoggleable, then stop. + if (!WeaponsGetToggleable(weaponindex)) { continue; } - if (!weaponlist[0]) + // Set weapon's restricted state. + RestrictSetWeaponRestricted(weaponindex, false, restrict); + } + + // Successfully restricted weapon type. + return Query_Successful; + } +} + +/** Print weapon (un)restriction query result to client(s). + * + * @param client The client to print response to. (0 for all clients) + * @param query The query result. + * @param single True if a single weapon is being restricted. + * @param restrict True if the query was to restrict/unrestrict a weapon. + * @param target The target to be restricted/unrestricted. + */ +RestrictPrintQueryResponse(client, RestrictQuery:query, bool:single, bool:restrict, const String:target[]) +{ + switch(query) + { + // Query was successful. + case Query_Successful: + { + if (single) { - strcopy(weaponlist, maxlen, groupweapon); + if (restrict) + { + TranslationPrintToChatAll(true, false, "Restrict weapon", target); + } + else + { + TranslationPrintToChatAll(true, false, "Unrestrict weapon", target); + } } else { - Format(weaponlist, maxlen, "%s%s%s", weaponlist, separator, groupweapon); + if (restrict) + { + TranslationPrintToChatAll(true, false, "Restrict weapon type", target); + } + else + { + TranslationPrintToChatAll(true, false, "Unrestrict weapon type", target); + } } - } while (KvGotoNextKey(kvWeaponGroups)); + } + // Query was redundant. + case Query_Stopped: + { + if (single) + { + if (restrict) + { + TranslationReplyToCommand(client, "Restrict weapon stopped", target); + } + else + { + TranslationReplyToCommand(client, "Unrestrict weapon stopped", target); + } + } + else + { + if (restrict) + { + TranslationReplyToCommand(client, "Restrict weapon type stopped", target); + } + else + { + TranslationReplyToCommand(client, "Unrestrict weapon type stopped", target); + } + } + } + // Weapon is untoggleable. + case Query_Locked: + { + TranslationReplyToCommand(client, "Restrict weapon untoggleable", target); + } + // Weapon was invalid. + case Query_Invalid: + { + TranslationReplyToCommand(client, "Weapon invalid", target); + } } } +stock RestrictTypeToIndex(const String:type[]) +{ + decl String:typename[WEAPONS_MAX_LENGTH]; + + // x = Array index. + new size = GetArraySize(arrayWeaponTypes); + for (new x = 0; x < size; x++) + { + RestrictWeaponTypeGetName(x, typename, sizeof(typename)); + + // If types match, then return index. + if (StrEqual(type, typename, false)) + { + return x; + } + } + + // Type doesn't exist. + return -1; +} + +/** + * Gets the name of a weapon type at a given index. + * @param index The weapon type index. + * @param weapon The string to return name in. + * @param maxlen The max length of the string. + */ +stock RestrictWeaponTypeGetName(index, String:weapontype[], maxlen) +{ + // Get weapon type name at given index. + GetArrayString(arrayWeaponTypes, index, weapontype, maxlen); +} + +/** + * Returns an array containing all weapon indexes matching the given type. + * + * @param index The weapon type index. + * @param arrayTypeWeapons A handle to store array containing matching weapons. + * Don't forget to close this! + */ +stock RestrictGetTypeWeapons(index, &Handle:arrayTypeWeapons) +{ + // Create array to hold weapons of the given type. + arrayTypeWeapons = CreateArray(); + + // Get name of the weapon type at given index. + decl String:typename[WEAPONS_MAX_LENGTH]; + RestrictWeaponTypeGetName(index, typename, sizeof(typename)); + + new count; + decl String:weapontype[WEAPONS_MAX_LENGTH]; + new String:weapontypes[WEAPONS_RESTRICT_MAX_TYPES][WEAPONS_MAX_LENGTH]; + + // x = Array index. + new size = GetArraySize(arrayWeapons); + for (new x = 0; x < size; x++) + { + WeaponsGetType(x, weapontype, sizeof(weapontype)); + + ExplodeString(weapontype, ",", weapontypes, WEAPONS_RESTRICT_MAX_TYPES, WEAPONS_MAX_LENGTH); + for (new y = 0; y < WEAPONS_RESTRICT_MAX_TYPES; y++) + { + // Cut off whitespace. + TrimString(weapontypes[y]); + + // If we've reached the end of the weapon's types, then stop. + if (!weapontypes[y][0]) + { + break; + } + + // If types match, then add weapon to array. + if (StrEqual(typename, weapontypes[y], false)) + { + PushArrayCell(arrayTypeWeapons, x); + count++; + } + } + } + + // Return number of weapons of the given type. + return count; +} + +/** + * Gets the restricted status on a weapon. + * + * @param index The weapon index. + * @param toggle If true, the value is toggled, otherwise 'restrict' param is used. + * @param restrict (Only if 'toggle' is 'false') Restricted status of the weapon. + */ +stock RestrictSetWeaponRestricted(index, bool:toggle, bool:restrict = false) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Set restricted status. + new bool:value = toggle ? !RestrictIsWeaponRestricted(index) : restrict; + SetArrayCell(arrayWeapon, _:WEAPONS_DATA_RESTRICTED, value); +} + +/** + * Gets the restricted status on a weapon. + * + * @param index The weapon index. + * @return True if weapon is restricted, false if not. + */ +stock bool:RestrictIsWeaponRestricted(index) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Return restricted status. + return bool:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_RESTRICTED); +} + +/** + * Used to check if all weapons of a type are restricted. + * + * @param restricted True to check if all weapons of given type are restricted. + * @param index The weapon type index. + * @return True if all weapons of the given type are restricted or not, false if not. + */ +stock bool:RestrictIsTypeUniform(bool:restricted, index) +{ + new Handle:arrayTypeWeapons; + new count = RestrictGetTypeWeapons(index, arrayTypeWeapons); + + // x = array index + for (new x = 0; x < count; x++) + { + // Get weapon index to check restricted status of. + new weaponindex = GetArrayCell(arrayTypeWeapons, x); + + // If weapon is toggleable and it's not uniform with the given status, then return false. + if (WeaponsGetToggleable(weaponindex) && RestrictIsWeaponRestricted(weaponindex) != restricted) + { + return false; + } + } + + // All weapons are restricted, so return true. + return true; +} + /** * Hook callback, called when a player is trying to pick up a weapon. * @param client The client index. @@ -867,7 +531,17 @@ public ZRTools_Action:RestrictCanUse(client, weapon) } // If the weapon is restricted, then prevent pickup. - if (RestrictIsWeaponRestricted(weaponname)) + new index = WeaponsNameToIndex(weaponname); + + // If weapon isn't configged, then allow pickup. + if (index == -1) + { + // Allow pickup. + return ZRTools_Continue; + } + + // If weapon is restricted, then stop. + if (RestrictIsWeaponRestricted(index)) { return ZRTools_Handled; } @@ -896,7 +570,7 @@ public ZRTools_Action:RestrictCanUse(client, weapon) * @param client The client index. * @param argc Argument count. */ -public Action:RestrictRestrictCommand(client, argc) +public Action:RestrictCommand(client, argc) { // If not enough arguments given, then stop. if (argc < 1) @@ -924,16 +598,22 @@ public Action:RestrictRestrictCommand(client, argc) } // arg1 = weapon being restricted - decl String:arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); + decl String:target[WEAPONS_MAX_LENGTH]; - // Strip "weapon_" from entity name - ReplaceString(arg1, sizeof(arg1), "weapon_", ""); - - decl String:display[WEAPONS_MAX_LENGTH]; - - new WpnRestrictQuery:output = RestrictRestrict(arg1, display); - RestrictPrintRestrictOutput(client, output, display, true); + new args = GetCmdArgs(); + for (new x = 1; x <= args; x++) + { + // Get target to restrict. + GetCmdArg(x, target, sizeof(target)); + + // Query restrict on this target, and get a result back. + new bool:single; + decl String:returntarget[WEAPONS_MAX_LENGTH]; + new RestrictQuery:query = RestrictWeapon(true, target, single, returntarget, sizeof(returntarget)); + + // Print response to client(s). + RestrictPrintQueryResponse(client, query, single, true, returntarget); + } return Plugin_Handled; } @@ -945,7 +625,7 @@ public Action:RestrictRestrictCommand(client, argc) * @param client The client index. * @param argc Argument count. */ -public Action:RestrictUnrestrictCommand(client, argc) +public Action:UnrestrictCommand(client, argc) { // If not enough arguments given, then stop. if (argc < 1) @@ -973,16 +653,22 @@ public Action:RestrictUnrestrictCommand(client, argc) } // arg1 = weapon being restricted - decl String:arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); + decl String:target[WEAPONS_MAX_LENGTH]; - // Strip "weapon_" from entity name - ReplaceString(arg1, sizeof(arg1), "weapon_", ""); - - decl String:display[WEAPONS_MAX_LENGTH]; - - new WpnRestrictQuery:output = RestrictUnrestrict(arg1, display); - RestrictPrintUnrestrictOutput(client, output, display, true); + new args = GetCmdArgs(); + for (new x = 1; x <= args; x++) + { + // Get target to restrict. + GetCmdArg(x, target, sizeof(target)); + + // Query unrestrict on this target, and get a result back. + new bool:single; + decl String:returntarget[WEAPONS_MAX_LENGTH]; + new RestrictQuery:query = RestrictWeapon(false, target, single, returntarget, sizeof(returntarget)); + + // Print response to client(s). + RestrictPrintQueryResponse(client, query, single, false, returntarget); + } return Plugin_Handled; } \ No newline at end of file diff --git a/src/zr/weapons/weaponalpha.inc b/src/zr/weapons/weaponalpha.inc index 5eee26e..0856f0a 100644 --- a/src/zr/weapons/weaponalpha.inc +++ b/src/zr/weapons/weaponalpha.inc @@ -150,7 +150,7 @@ WeaponAlphaApplyWeaponAlpha(entity, alpha) } // Get client's list of weapons. - new weapons[WeaponsType]; + new weapons[WeaponsSlot]; WeaponsGetClientWeapons(entity, weapons); // Loop through array slots and set alpha. diff --git a/src/zr/weapons/weaponammo.inc b/src/zr/weapons/weaponammo.inc new file mode 100644 index 0000000..536af2b --- /dev/null +++ b/src/zr/weapons/weaponammo.inc @@ -0,0 +1,81 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: weaponammo.inc + * Type: Core + * Description: API for all weaponammo-related functions. + * + * ============================================================================ + */ + +/** + * @section Variables to store ammo offset values. + */ +new g_iToolsClip1; +new g_iToolsClip2; +/** + * @endsection + */ + +/** + * Find ammo-reserve-specific offsets here. + */ +WeaponAmmoOnOffsetsFound() +{ + // If offset "m_iClip1" can't be found, then stop the plugin. + g_iToolsClip1 = FindSendPropInfo("CBaseCombatWeapon", "m_iClip1"); + if (g_iToolsClip1 == -1) + { + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CBaseCombatWeapon::m_iClip1\" was not found."); + } + + // If offset "m_iClip2" can't be found, then stop the plugin. + g_iToolsClip2 = FindSendPropInfo("CBaseCombatWeapon", "m_iClip2"); + if (g_iToolsClip2 == -1) + { + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CBaseCombatWeapon::m_iClip2\" was not found."); + } +} + +/** + * Set clip/reserve ammo on a weapon. + * + * @param weapon The weapon index. + * @param clip True sets clip ammo, false sets reserve. + * @param value The amount of ammo to set to. + * @param add (Optional) If true, the value is added to the weapon's current ammo count. + */ +stock WeaponAmmoSetClientAmmo(weapon, bool:clip, value, bool:add = false) +{ + // Set variable to offset we are changing. + new ammooffset = clip ? g_iToolsClip1 : g_iToolsClip2; + + // Initialize variable (value is 0) + new ammovalue; + + // If we are adding, then update variable with current ammo value. + if (add) + { + ammovalue = WeaponAmmoGetClientAmmo(weapon, clip); + } + + // Return ammo offset value. + SetEntData(weapon, ammooffset, ammovalue + value, _, true); +} + +/** + * Get clip/reserve ammo on a weapon. + * + * @param weapon The weapon index. + * @param clip True gets clip ammo, false gets reserve. + */ +stock WeaponAmmoGetClientAmmo(weapon, bool:clip) +{ + // Set variable to offset we are changing. + new ammooffset = clip ? g_iToolsClip1 : g_iToolsClip2; + + // Return ammo offset value. + return GetEntData(weapon, ammooffset); +} \ No newline at end of file diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index f6ccf04..076caa7 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -14,9 +14,6 @@ * Maximum length of a weapon name string */ #define WEAPONS_MAX_LENGTH 32 -/** - * @endsection - */ /** * Number of weapon slots (For CS:S) @@ -24,27 +21,52 @@ #define WEAPONS_SLOTS_MAX 5 /** - * Weapon types. + * Weapon config data indexes. */ -enum WeaponsType +enum WeaponsData { - 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. */ + WEAPONS_DATA_NAME = 0, + WEAPONS_DATA_TYPE, + WEAPONS_DATA_RESTRICTDEFAULT, + WEAPONS_DATA_TOGGLEABLE, + WEAPONS_DATA_AMMOTYPE, + WEAPONS_DATA_AMMOPRICE, + WEAPONS_DATA_KNOCKBACK, + WEAPONS_DATA_ZMARKETPRICE, + WEAPONS_DATA_RESTRICTED, } /** - * Keyvalue handle to store weapon data. - * - * @redir config.inc + * @endsection */ +/** + * Variable to store active weapon offset value. + */ +new g_iToolsActiveWeapon; + +/** + * Weapon slots. + */ +enum WeaponsSlot +{ + Slot_Invalid = -1, /** Invalid weapon (slot). */ + Slot_Primary = 0, /** Primary weapon slot. */ + Slot_Secondary = 1, /** Secondary weapon slot. */ + Slot_Melee = 2, /** Melee (knife) weapon slot. */ + Slot_Projectile = 3, /** Projectile (grenades, flashbangs, etc) weapon slot. */ + Slot_Explosive = 4, /** Explosive (c4) weapon slot. */ +} + +/** + * Array handle to store weapon config data. + */ +new Handle:arrayWeapons = INVALID_HANDLE; + #include "zr/weapons/restrict" +#include "zr/weapons/weaponammo" #include "zr/weapons/weaponalpha" -#include "zr/weapons/markethandler" +#include "zr/weapons/zmarket" #include "zr/weapons/menu_weapons" /** @@ -52,10 +74,26 @@ enum WeaponsType */ WeaponsInit() { - // Forward event to sub-module + // Forward event to sub-modules. RestrictInit(); } +/** + * Find active weapon-specific offsets here. + */ +WeaponsOnOffsetsFound() +{ + // If offset "m_hActiveWeapon" can't be found, then stop the plugin. + g_iToolsActiveWeapon = FindSendPropInfo("CBasePlayer", "m_hActiveWeapon"); + if (g_iToolsActiveWeapon == -1) + { + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CBasePlayer::m_hActiveWeapon\" was not found."); + } + + // Forward event to sub-modules + WeaponAmmoOnOffsetsFound(); +} + /** * Create commands related to weapons here. */ @@ -65,34 +103,13 @@ WeaponsOnCommandsCreate() RestrictOnCommandsCreate(); } -/** - * Clears weapon data. - */ -WeaponsClearData() -{ - // Load weapon data - if (kvWeapons != INVALID_HANDLE) - { - CloseHandle(kvWeapons); - } - - kvWeapons = CreateKeyValues("weapons"); -} - /** * Loads weapon data from file. */ WeaponsLoad() { - // Clear weapon data. - WeaponsClearData(); - - // Get weapons config path. - decl String:pathweapons[PLATFORM_MAX_PATH]; - new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_WEAPONS, pathweapons); - - // Register config info. - ConfigRegisterConfig(ConfigWeapons, false, GetFunctionByName(GetMyHandle(), "WeaponsOnConfigReload"), _, pathweapons, CONFIG_FILE_ALIAS_WEAPONS); + // Register config file. + ConfigRegisterConfig(File_Weapons, Structure_Keyvalue, CONFIG_FILE_ALIAS_WEAPONS); // If module is disabled, then stop. new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); @@ -101,6 +118,10 @@ WeaponsLoad() return; } + // Get weapons config path. + decl String:pathweapons[PLATFORM_MAX_PATH]; + new bool:exists = ConfigGetCvarFilePath(CVAR_CONFIG_PATH_WEAPONS, pathweapons); + // If file doesn't exist, then log and stop. if (!exists) { @@ -110,46 +131,121 @@ WeaponsLoad() return; } - // Put file data into memory. - FileToKeyValues(kvWeapons, pathweapons); + // Set the path to the config file. + ConfigSetConfigPath(File_Weapons, pathweapons); + + // Load config from file and create array structure. + new bool:success = ConfigLoadConfig(File_Weapons, arrayWeapons); + + // Unexpected error, stop plugin. + if (!success) + { + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapons", "Config Validation", "Unexpected error encountered loading: %s", pathweapons); + + return; + } // Validate weapons config. - WeaponsValidateConfig(); + new size = GetArraySize(arrayWeapons); + if (!size) + { + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapons", "Config Validation", "No usable data found in weapons config file: %s", pathweapons); + } + + // Now copy data to array structure. + WeaponsCacheData(); // Set config data. - ConfigSetConfigLoaded(ConfigWeapons, true); - ConfigSetConfigHandle(ConfigWeapons, kvWeapons); + ConfigSetConfigLoaded(File_Weapons, true); + ConfigSetConfigReloadFunc(File_Weapons, GetFunctionByName(GetMyHandle(), "WeaponsOnConfigReload")); + ConfigSetConfigHandle(File_Weapons, arrayWeapons); - // Forward event to sub-module. + // Forward event to sub-modules RestrictLoad(); } /** - * Called when configs are being reloaded. - * - * @param config The config being reloaded. (only if 'all' is false) + * Caches weapon data from file into arrays. + * Make sure the file is loaded before (ConfigLoadConfig) to prep array structure. */ -public WeaponsOnConfigReload(ConfigFile:config) +WeaponsCacheData() { - // Reload weapons config. - if (config == ConfigWeapons) + // Get config's file path. + decl String:pathweapons[PLATFORM_MAX_PATH]; + ConfigGetConfigPath(File_Weapons, pathweapons, sizeof(pathweapons)); + + new Handle:kvWeapons; + new bool:success = ConfigOpenConfigFile(File_Weapons, kvWeapons); + + if (!success) { - WeaponsLoad(); + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapons", "Config Validation", "Unexpected error caching data from weapons config file: %s", pathweapons); } + + decl String:weaponname[WEAPONS_MAX_LENGTH]; + + // x = array index + new size = GetArraySize(arrayWeapons); + for (new x = 0; x < size; x++) + { + WeaponsGetName(x, weaponname, sizeof(weaponname)); + KvRewind(kvWeapons); + if (!KvJumpToKey(kvWeapons, weaponname)) + { + LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapons", "Config Validation", "Couldn't cache weapon data for: %s (check weapons config)", weaponname); + continue; + } + + // Get config data. + + decl String:weapontype[CONFIG_MAX_LENGTH]; + decl String:ammotype[CONFIG_MAX_LENGTH]; + + // General + KvGetString(kvWeapons, "weapontype", weapontype, sizeof(weapontype)); + + // Restrict (core) + new bool:restrictdefault = ConfigKvGetStringBool(kvWeapons, "restrictdefault", "no"); + new bool:toggleable = ConfigKvGetStringBool(kvWeapons, "toggleable", "yes"); + + // Weapon Ammo (core) + KvGetString(kvWeapons, "ammotype", ammotype, sizeof(ammotype)); + new ammoprice = KvGetNum(kvWeapons, "ammoprice"); + + // Knockback (module) + new Float:knockback = KvGetFloat(kvWeapons, "knockback", 1.0); + + // ZMarket (module) + new zmarketprice = KvGetNum(kvWeapons, "zmarketprice", -1); + + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, x); + + // Push data into array. + PushArrayString(arrayWeapon, weapontype); // Index: 1 + PushArrayCell(arrayWeapon, restrictdefault); // Index: 2 + PushArrayCell(arrayWeapon, toggleable); // Index: 3 + PushArrayString(arrayWeapon, ammotype); // Index: 4 + PushArrayCell(arrayWeapon, ammoprice); // Index: 5 + PushArrayCell(arrayWeapon, knockback); // Index: 6 + PushArrayCell(arrayWeapon, zmarketprice); // Index: 7 + + // Initialize other stored weapon info here. + PushArrayCell(arrayWeapon, restrictdefault); // Index: 8 + } + + // We're done with this file now, so we can close it. + CloseHandle(kvWeapons); } /** - * Validate weapon config file and settings. + * Called when config is being reloaded. */ -WeaponsValidateConfig() +public WeaponsOnConfigReload() { - KvRewind(kvWeapons); - if (!KvGotoFirstSubKey(kvWeapons)) - { - LogPrintToLog(LOG_FORMAT_TYPE_ERROR, "Weapons", "Config Validation", "No weapons listed in weapons.txt."); - } + // Reload weapons config. + WeaponsLoad(); } - + /** * Client is joining the server. * @@ -195,154 +291,173 @@ WeaponsOnRoundEnd() } /** - * Creates an array of all listed weapons in weapons.txt. - * @param arrayWeapons The handle of the array, don't forget to call CloseHandle - * on it when finished! - * @return The size of the array. + * Weapon data reading API. */ -stock WeaponsCreateWeaponArray(&Handle:arrayWeapons, maxlen = WEAPONS_MAX_LENGTH) + +/** + * Clear cache for a given weapon. + * + * @param index The weapon index. + */ +WeaponsClearCache(index) { - // Initialize array handle. - arrayWeapons = CreateArray(maxlen); - new count = 0; + // Get array handle of weapon at given index. + new Handle:hWeapon = GetArrayCell(arrayWeapons, index); - // Reset keyvalue's traveral stack. - KvRewind(kvWeapons); - if (KvGotoFirstSubKey(kvWeapons)) - { - decl String:weapon[maxlen]; - - do - { - KvGetSectionName(kvWeapons, weapon, maxlen); - - // Push weapon name into the array. - PushArrayString(arrayWeapons, weapon); - - // Increment count. - count++; - } while (KvGotoNextKey(kvWeapons)); - } - - // Return the count - return count; + // Clear array. + ClearArray(hWeapon); } /** - * Checks if a weapon is valid. (aka listed in weapons.txt) + * Find the index at which the weapon's name is at. + * + * @param weapon The weapon name. + * @return The array index containing the given weapon name. + */ +stock WeaponsNameToIndex(const String:weapon[]) +{ + decl String:weaponname[WEAPONS_MAX_LENGTH]; + + // x = Array index. + new size = GetArraySize(arrayWeapons); + for (new x = 0; x < size; x++) + { + WeaponsGetName(x, weaponname, sizeof(weaponname)); + + // If names match, then return index. + if (StrEqual(weapon, weaponname, false)) + { + return x; + } + } + + // Name doesn't exist. + return -1; +} + +/** + * Checks if a weapon is valid. (E.G. listed in weapons.txt) * @param weapon The weapon name. * @return Returns true if valid, false it not. */ -stock bool:WeaponsIsValidWeapon(const String:weapon[]) +stock bool:WeaponsIsWeaponValid(const String:weapon[]) { - // Reset keyvalue's traversal stack. - KvRewind(kvWeapons); - if (KvGotoFirstSubKey(kvWeapons)) - { - decl String:validweapon[WEAPONS_MAX_LENGTH]; - - do - { - KvGetSectionName(kvWeapons, validweapon, sizeof(validweapon)); - - // If weaponname matches a valid weapon, then return true. - if (StrEqual(validweapon, weapon, false)) - { - return true; - } - - } while (KvGotoNextKey(kvWeapons)); - } - - // Weapon is invalid. - return false; + return (WeaponsNameToIndex(weapon) != -1); } /** - * Looks up a weapon in weapons.txt and returns exact display name. - * @param weapon The weapon name. - * @param display Returns with the display name, is not changed if weapon is invalid. + * Gets the name of a weapon at a given index. + * @param index The weapon index. + * @param weapon The string to return name in. + * @param maxlen The max length of the string. */ -stock WeaponsGetDisplayName(const String:weapon[], String:display[]) +stock WeaponsGetName(index, String:weapon[], maxlen) { - // Reset keyvalue's traversal stack. - KvRewind(kvWeapons); - if (KvGotoFirstSubKey(kvWeapons)) - { - decl String:validweapon[WEAPONS_MAX_LENGTH]; - - do - { - KvGetSectionName(kvWeapons, validweapon, sizeof(validweapon)); - - // If weapon matches a valid weapon (case-insensitive), then return display name. - if (StrEqual(validweapon, weapon, false)) - { - strcopy(display, WEAPONS_MAX_LENGTH, validweapon); - } - - } while (KvGotoNextKey(kvWeapons)); - } + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Get weapon name. + GetArrayString(arrayWeapon, _:WEAPONS_DATA_NAME, weapon, maxlen); } /** - * Checks if a weapon restriction can be toggled by the admin menu. - * @param weapon The weapon name. - * @return Returns true if restricted, false it not. + * Gets the type of a weapon at a given index. + * @param index The weapon index. + * @param type The string to return type in. + * @param maxlen The max length of the string. */ -stock bool:WeaponsIsWeaponMenu(const String:weapon[]) +stock WeaponsGetType(index, String:type[], maxlen) { - // Reset keyvalue's traversal stack. - KvRewind(kvWeapons); - if (KvGotoFirstSubKey(kvWeapons)) - { - decl String:validweapon[WEAPONS_MAX_LENGTH]; - decl String:menu[8]; - - do - { - KvGetSectionName(kvWeapons, validweapon, sizeof(validweapon)); - - // If this is the right weapon, then return setting for it. - if (StrEqual(validweapon, weapon, false)) - { - KvGetString(kvWeapons, "menu", menu, sizeof(menu), "yes"); - - // Return weapon's setting. - return ConfigSettingToBool(menu); - } - } while (KvGotoNextKey(kvWeapons)); - } + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); - return false; + // Get weapon type. + GetArrayString(arrayWeapon, _:WEAPONS_DATA_TYPE, type, maxlen); } /** - * Returns knockback multiplier of the weapon. - * @param weapon The weapon name. - * @return The float value of the knockback multiplier, 1.0 if not found. + * Gets if a weapon is restricted by default. + * @param index The weapon index. + * @return True if the weapon is restricted by default, false if not. */ -stock Float:WeaponGetWeaponKnockback(const String:weapon[]) +stock bool:WeaponsGetRestrictDefault(index) { - // Reset keyvalue's traversal stack. - KvRewind(kvWeapons); - if (KvGotoFirstSubKey(kvWeapons)) - { - decl String:validweapon[WEAPONS_MAX_LENGTH]; - - do - { - KvGetSectionName(kvWeapons, validweapon, sizeof(validweapon)); - - // If this is the right weapon, then return setting for it. - if (StrEqual(validweapon, weapon, false)) - { - return KvGetFloat(kvWeapons, "knockback", 1.0); - } - } while (KvGotoNextKey(kvWeapons)); - } + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); - return 1.0; + // Return default restriction status. + return bool:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_RESTRICTDEFAULT); +} + +/** + * Gets if a weapon's restriction status is toggleable. + * @param index The weapon index. + * @return True if the weapon restriction can be toggled, false if not. + */ +stock bool:WeaponsGetToggleable(index) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Return if weapon is toggleable. + return bool:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_TOGGLEABLE); +} + +/** + * Gets the ammo type of a weapon at a given index. + * @param index The weapon index. + * @param ammotype The string to return ammotype in. + * @param maxlen The max length of the string. + */ +stock WeaponsGetAmmoType(index, String:ammotype[], maxlen) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Get ammo type of the weapon. + GetArrayString(arrayWeapon, _:WEAPONS_DATA_AMMOTYPE, type, maxlen); +} + +/** + * Gets the price of ammo for the weapon. + * @param index The weapon index. + * @return The ammo price. + */ +stock WeaponsGetAmmoPrice(index) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Return ammo price of the weapon. + return GetArrayCell(arrayWeapon, _:WEAPONS_DATA_AMMOPRICE); +} + +/** + * Gets the knockback multiplier for the weapon. + * @param index The weapon index. + * @return The weapon knockback multiplier. + */ +stock Float:WeaponsGetKnockback(index) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Return knockback multiplier of the weapon. + return Float:GetArrayCell(arrayWeapon, _:WEAPONS_DATA_KNOCKBACK); +} + +/** + * Gets the ZMarket price for the weapon. + * @param index The weapon index. + * @return The ZMarket price. + */ +stock WeaponsGetZMarketPrice(index) +{ + // Get array handle of weapon at given index. + new Handle:arrayWeapon = GetArrayCell(arrayWeapons, index); + + // Return the ZMarket price of the weapon. + return GetArrayCell(arrayWeapon, _:WEAPONS_DATA_ZMARKETPRICE); } /** @@ -356,7 +471,7 @@ stock Float:WeaponGetWeaponKnockback(const String:weapon[]) * @param weapons The weapon index array. * -1 if no weapon in slot. */ -stock WeaponsGetClientWeapons(client, weapons[WeaponsType]) +stock WeaponsGetClientWeapons(client, weapons[WeaponsSlot]) { // x = weapon slot. for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) @@ -384,10 +499,10 @@ stock WeaponsGetDeployedWeaponIndex(client) * @param client The client index. * @return The slot number of deployed weapon. */ -stock WeaponsType:WeaponsGetDeployedWeaponSlot(client) +stock WeaponsSlot:WeaponsGetDeployedWeaponSlot(client) { // Get all client's weapon indexes. - new weapons[WeaponsType]; + new weapons[WeaponsSlot]; WeaponsGetClientWeapons(client, weapons); // Get client's deployed weapon. @@ -404,7 +519,7 @@ stock WeaponsType:WeaponsGetDeployedWeaponSlot(client) { if (weapons[x] == deployedweapon) { - return x; + return WeaponsSlot:x; } } diff --git a/src/zr/weapons/zmarket.inc b/src/zr/weapons/zmarket.inc new file mode 100644 index 0000000..1fc6c54 --- /dev/null +++ b/src/zr/weapons/zmarket.inc @@ -0,0 +1,47 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: + * Type: Module + * Description: + * + * ============================================================================ + */ + +/** + * Variable to store buyzone offset value. + */ +new g_iToolsInBuyZone; + +/** + * Initialize market data. + */ +ZMarketInit() +{ +} + +/** + * Find ZMarket-specific offsets here. + */ +ZMarketOnOffsetsFound() +{ + // If offset "m_bInBuyZone" can't be found, then stop the plugin. + g_iToolsInBuyZone = FindSendPropInfo("CCSPlayer", "m_bInBuyZone"); + if (g_iToolsInBuyZone == -1) + { + LogPrintToLog(LOG_FORMAT_TYPE_FATALERROR, "Tools", "Offsets", "Offset \"CCSPlayer::m_bInBuyZone\" was not found."); + } +} + +/** + * Checks if a client is in a buyzone. + * + * @param client The client index. + */ +stock bool:ZMarketIsClientInBuyZone(client) +{ + // Return if client is in buyzone. + return bool:GetEntData(client, g_iToolsInBuyZone); +} \ No newline at end of file diff --git a/src/zr/zadmin.inc b/src/zr/zadmin.inc index 287c551..bdc04ea 100644 --- a/src/zr/zadmin.inc +++ b/src/zr/zadmin.inc @@ -10,9 +10,6 @@ * ============================================================================ */ -#include "include/adminmenu.inc" -//new curMenuClass[MAXPLAYERS + 1]; - bool:ZRAdminMenu(client) { if (!ZRIsClientAdmin(client)) @@ -27,35 +24,37 @@ bool:ZRAdminMenu(client) SetMenuTitle(menu_zadmin, "%t\n ", "!zadmin main title"); - decl String:knockbackm[64]; - decl String:knockback[64]; - decl String:nvgs[64]; - decl String:infect[64]; - decl String:zspawn[64]; - decl String:ztele[64]; + //decl String:knockbackm[64]; + //decl String:knockback[64]; + //decl String:nvgs[64]; + //decl String:infect[64]; + //decl String:zspawn[64]; + //decl String:ztele[64]; decl String:weapons[64]; - decl String:logflags[64]; + //decl String:logflags[64]; - Format(knockbackm, sizeof(knockbackm), "%t", "!zadmin main knockbackm"); - Format(knockback, sizeof(knockback), "%t", "!zadmin main knockback"); - Format(nvgs, sizeof(nvgs), "%t", "!zadmin main nvgs"); - Format(infect, sizeof(infect), "%t", "!zadmin main infect"); - Format(zspawn, sizeof(zspawn), "%t", "!zadmin main spawn"); - Format(ztele, sizeof(ztele), "%t", "!zadmin main tele"); + //Format(knockbackm, sizeof(knockbackm), "%t", "!zadmin main knockbackm"); + //Format(knockback, sizeof(knockback), "%t", "!zadmin main knockback"); + //Format(nvgs, sizeof(nvgs), "%t", "!zadmin main nvgs"); + //Format(infect, sizeof(infect), "%t", "!zadmin main infect"); + //Format(zspawn, sizeof(zspawn), "%t", "!zadmin main spawn"); + //Format(ztele, sizeof(ztele), "%t", "!zadmin main tele"); Format(weapons, sizeof(weapons), "%t", "!zadmin main weapons"); - Format(logflags, sizeof(logflags), "%t", "!zadmin main logflags"); + //Format(logflags, sizeof(logflags), "%t", "!zadmin main logflags"); - AddMenuItem(menu_zadmin, "knockbackm", knockbackm, ITEMDRAW_DISABLED); - AddMenuItem(menu_zadmin, "knockback", knockback, ITEMDRAW_DISABLED); - AddMenuItem(menu_zadmin, "nvgs", nvgs, ITEMDRAW_DISABLED); - AddMenuItem(menu_zadmin, "infect", infect); - AddMenuItem(menu_zadmin, "zspawn", zspawn); - AddMenuItem(menu_zadmin, "ztele", ztele, ITEMDRAW_DISABLED); + //AddMenuItem(menu_zadmin, "knockbackm", knockbackm, ITEMDRAW_DISABLED); + //AddMenuItem(menu_zadmin, "knockback", knockback, ITEMDRAW_DISABLED); + //AddMenuItem(menu_zadmin, "nvgs", nvgs, ITEMDRAW_DISABLED); + //AddMenuItem(menu_zadmin, "infect", infect); + //AddMenuItem(menu_zadmin, "zspawn", zspawn); + //AddMenuItem(menu_zadmin, "ztele", ztele, ITEMDRAW_DISABLED); AddMenuItem(menu_zadmin, "weapons", weapons); - AddMenuItem(menu_zadmin, "logflags", logflags); + //AddMenuItem(menu_zadmin, "logflags", logflags); + // Set "Back" button. SetMenuExitBackButton(menu_zadmin, true); + // Send menu to client. DisplayMenu(menu_zadmin, client, MENU_TIME_FOREVER); return true; @@ -67,45 +66,21 @@ public ZRAdminMenuHandle(Handle:menu_admin, MenuAction:action, client, slot) { switch(slot) { + // Weapon management. case 0: - { - //ZRKnockbackMMenu(client); - } - case 1: - { - //ZRClassSelectMenu(client); - } - case 2: - { - //ZRNVGSMenu(client); - } - case 3: - { - ZRInfectMenu(client); - } - case 4: - { - ZRSpawnAll(client); - } - case 5: - { - ZRZTeleMenu(client); - } - case 6: { WeaponsMenuMain(client); } - case 7: - { - ZRLogFlagsMenu(client); - } } + + // TODO: Resend menu if feature is disabled or unopenable. } if (action == MenuAction_Cancel) { if (slot == MenuCancel_ExitBack) { + // Exit back to main menu. MenuMain(client); } } @@ -113,438 +88,4 @@ public ZRAdminMenuHandle(Handle:menu_admin, MenuAction:action, client, slot) { CloseHandle(menu_admin); } -} - -/** - * Needs to be recoded to support new modules. - */ -/*ZRKnockbackMMenu(client) -{ - new Handle:menu_knockbackm = CreateMenu(ZRKnockbackMHandle); - new Float:curknockback = GetConVarFloat(g_hCvarsList[CVAR_ZOMBIE_KNOCKBACK]); - - SetGlobalTransTarget(client); - - SetMenuTitle(menu_knockbackm, "%t\n ", "!zadmin knockbackm title", curknockback); - - decl String:knockbackmincrease1[64]; - decl String:knockbackmdecrease1[64]; - decl String:knockbackmincrease2[64]; - decl String:knockbackmdecrease2[64]; - - Format(knockbackmincrease1, sizeof(knockbackmincrease1), "%t", "!zadmin knockbackm increase", "0.1"); - Format(knockbackmdecrease1, sizeof(knockbackmdecrease1), "%t", "!zadmin knockbackm decrease", "0.1"); - Format(knockbackmincrease2, sizeof(knockbackmincrease2), "%t", "!zadmin knockbackm increase", "0.5"); - Format(knockbackmdecrease2, sizeof(knockbackmdecrease2), "%t", "!zadmin knockbackm decrease", "0.5"); - - AddMenuItem(menu_knockbackm, "knockbackmincrease1", knockbackmincrease1); - AddMenuItem(menu_knockbackm, "knockbackmdecrease1", knockbackmdecrease1); - AddMenuItem(menu_knockbackm, "knockbackmincrease2", knockbackmincrease2); - AddMenuItem(menu_knockbackm, "knockbackmdecrease2", knockbackmdecrease2); - - SetMenuExitBackButton(menu_knockbackm, true); - - DisplayMenu(menu_knockbackm, client, MENU_TIME_FOREVER); -} - -public ZRKnockbackMHandle(Handle:menu_knockbackm, MenuAction:action, client, slot) -{ - if (action == MenuAction_Select) - { - switch(slot) - { - case 0: - { - AddToKnockbackMultiplier(0.1); - ZRKnockbackMMenu(client); - } - case 1: - { - AddToKnockbackMultiplier(-0.1); - ZRKnockbackMMenu(client); - } - case 2: - { - AddToKnockbackMultiplier(0.5); - ZRKnockbackMMenu(client); - } - case 3: - { - AddToKnockbackMultiplier(-0.5); - ZRKnockbackMMenu(client); - } - } - } - if (action == MenuAction_Cancel) - { - if (slot == MenuCancel_ExitBack) - { - ZRAdminMenu(client); - } - } - if (action == MenuAction_End) - { - CloseHandle(menu_knockbackm); - } -} - -ZRClassSelectMenu(client) -{ - new Handle:menu_class = CreateMenu(ZRClassSelectHandle); - - SetGlobalTransTarget(client); - - SetMenuTitle(menu_class, "%t\n ", "!zadmin class title"); - - // x = index of class - for (new x = 0; x < classCount; x++) - { - AddMenuItem(menu_class, arrayClasses[x][data_name], arrayClasses[x][data_name]); - } - - SetMenuExitBackButton(menu_class, true); - DisplayMenu(menu_class, client, MENU_TIME_FOREVER); -} - -public ZRClassSelectHandle(Handle:menu_class, MenuAction:action, client, slot) -{ - if (action == MenuAction_Select) - { - curMenuClass[client] = slot; - ZRClassKnockbackMenu(client, slot); - } - if (action == MenuAction_Cancel) - { - if (slot == MenuCancel_ExitBack) - { - ZRAdminMenu(client); - } - } - if (action == MenuAction_End) - { - CloseHandle(menu_class); - } -} - -ZRClassKnockbackMenu(client, classindex) -{ - new Handle:menu_knockback = CreateMenu(ZRClassKnockbackHandle); - - new Float:curknockback = arrayClasses[classindex][data_knockback]; - - new String:classname[64]; - GetClassName(classindex, classname, sizeof(classname)); - - SetGlobalTransTarget(client); - - SetMenuTitle(menu_knockback, "%t\n ", "!zadmin knockback title", classname, curknockback); - - decl String:knockbackincrease1[64]; - decl String:knockbackdecrease1[64]; - decl String:knockbackincrease2[64]; - decl String:knockbackdecrease2[64]; - - Format(knockbackincrease1, sizeof(knockbackincrease1), "%t", "!zadmin knockback increase", "0.1"); - Format(knockbackdecrease1, sizeof(knockbackdecrease1), "%t", "!zadmin knockback decrease", "0.1"); - Format(knockbackincrease2, sizeof(knockbackincrease2), "%t", "!zadmin knockback increase", "0.5"); - Format(knockbackdecrease2, sizeof(knockbackdecrease2), "%t", "!zadmin knockback decrease", "0.5"); - - AddMenuItem(menu_knockback, "knockbackincrease1", knockbackincrease1); - AddMenuItem(menu_knockback, "knockbackdecrease1", knockbackdecrease1); - AddMenuItem(menu_knockback, "knockbackincrease2", knockbackincrease2); - AddMenuItem(menu_knockback, "knockbackdecrease2", knockbackdecrease2); - - SetMenuExitBackButton(menu_knockback, true); - - DisplayMenu(menu_knockback, client, MENU_TIME_FOREVER); -} - -public ZRClassKnockbackHandle(Handle:menu_knockback, MenuAction:action, client, slot) -{ - if (action == MenuAction_Select) - { - switch(slot) - { - case 0: - { - AddToClassKnockback(curMenuClass[client], 0.1); - } - case 1: - { - AddToClassKnockback(curMenuClass[client], -0.1); - } - case 2: - { - AddToClassKnockback(curMenuClass[client], 0.5); - } - case 3: - { - AddToClassKnockback(curMenuClass[client], -0.5); - } - } - - ZRClassKnockbackMenu(client, curMenuClass[client]); - } - if (action == MenuAction_Cancel) - { - if (slot == MenuCancel_ExitBack) - { - ZRClassSelectMenu(client); - } - } - if (action == MenuAction_End) - { - CloseHandle(menu_knockback); - } -} - -ZRNVGSMenu(client) -{ - new Handle:menu_nvgs = CreateMenu(ZRNVGSHandle); - new curnvgs = GetConVarInt(g_hCvarsList[CVAR_ZOMBIE_NVGS]); - - SetGlobalTransTarget(client); - - SetMenuTitle(menu_nvgs, "%t\n ", "!zadmin nvgs title", curnvgs); - - decl String:nooverride[64]; - decl String:disable[64]; - decl String:enable[64]; - - Format(nooverride, sizeof(nooverride), "%t", "!zadmin nvgs no override"); - Format(disable, sizeof(disable), "%t", "!zadmin nvgs disable"); - Format(enable, sizeof(enable), "%t", "!zadmin nvgs enable"); - - AddMenuItem(menu_nvgs, "nooverride", nooverride); - AddMenuItem(menu_nvgs, "disable", disable); - AddMenuItem(menu_nvgs, "enable", enable); - - SetMenuExitBackButton(menu_nvgs, true); - - DisplayMenu(menu_nvgs, client, MENU_TIME_FOREVER); -} - -public ZRNVGSHandle(Handle:menu_nvgs, MenuAction:action, client, slot) -{ - if (action == MenuAction_Select) - { - switch(slot) - { - case 0: - { - SetConVarInt(g_hCvarsList[CVAR_ZOMBIE_NVGS], -1); - ZRNVGSMenu(client); - } - case 1: - { - SetConVarInt(g_hCvarsList[CVAR_ZOMBIE_NVGS], 0); - ZRNVGSMenu(client); - } - case 2: - { - SetConVarInt(g_hCvarsList[CVAR_ZOMBIE_NVGS], 1); - ZRNVGSMenu(client); - } - } - } - if (action == MenuAction_Cancel) - { - if (slot == MenuCancel_ExitBack) - { - ZRAdminMenu(client); - } - } - if (action == MenuAction_End) - { - CloseHandle(menu_nvgs); - } -}*/ - -ZRInfectMenu(client) -{ - new Handle:menu_infect = CreateMenu(ZRInfectHandle); - - SetGlobalTransTarget(client); - - SetMenuTitle(menu_infect, "%t\n ", "!zadmin infect title"); - - AddTargetsToMenu(menu_infect, client, true, true); - - SetMenuExitBackButton(menu_infect, true); - - DisplayMenu(menu_infect, client, MENU_TIME_FOREVER); -} - -public ZRInfectHandle(Handle:menu_infect, MenuAction:action, client, slot) -{ - if (action == MenuAction_Select) - { - decl String:info[32]; - new userid, target; - - GetMenuItem(menu_infect, slot, info, sizeof(info)); - userid = StringToInt(info); - - if ((target = GetClientOfUserId(userid)) == 0) - { - ReplyToCommand(client, "[ZR] Player no longer available"); - } - else if (!CanUserTarget(client, target)) - { - ReplyToCommand(client, "[ZR] Unable to target player"); - } - else if (!IsPlayerAlive(target)) - { - ReplyToCommand(client, "[ZR] Player is dead"); - } - else - { - decl String:name[64]; - GetClientName(target, name, sizeof(name)); - InfectClient(target); - ShowActivity2(client, "[ZR] ", "Infected %s", name); - ZRInfectMenu(client); - } - } - if (action == MenuAction_Cancel) - { - if (slot == MenuCancel_ExitBack) - { - ZRAdminMenu(client); - } - } - if (action == MenuAction_End) - { - CloseHandle(menu_infect); - } -} - -ZRSpawnAll(client) -{ - // x = client index. - for (new x = 1; x < MaxClients; x++) - { - if (IsClientInGame(x)) - { - ZSpawnClient(x); - } - } - ZRAdminMenu(client); -} - -ZRZTeleMenu(client) -{ - new Handle:menu_ztele = CreateMenu(ZRTeleHandle); - - SetGlobalTransTarget(client); - - SetMenuTitle(menu_ztele, "%t\n ", "!zadmin ztele title"); - - decl String:ztele_spawntele[64]; - decl String:ztele_abort[64]; - decl String:ztele_save[64]; - decl String:ztele_tele[64]; - - Format(ztele_spawntele, sizeof(ztele_spawntele), "%t", "!zadmin ztele spawn tele"); - Format(ztele_abort, sizeof(ztele_abort), "%t", "!zadmin ztele abort"); - Format(ztele_save, sizeof(ztele_save), "%t", "!zadmin ztele save"); - Format(ztele_tele, sizeof(ztele_tele), "%t", "!zadmin ztele tele"); - - AddMenuItem(menu_ztele, "ztele_spawntele", ztele_spawntele); - AddMenuItem(menu_ztele, "ztele_abort", ztele_abort); - AddMenuItem(menu_ztele, "ztele_save", ztele_save); - AddMenuItem(menu_ztele, "ztele_tele", ztele_tele); - - SetMenuExitBackButton(menu_ztele, true); - DisplayMenu(menu_ztele, client, MENU_TIME_FOREVER); -} - -public ZRTeleHandle(Handle:menu_ztele , MenuAction:action, client, slot) -{ - if (action == MenuAction_Select) - { - switch(slot) - { - case 0: - { - // Teleport player. - } - case 1: - { - // Abort teleport. - } - case 2: - { - // Save location. - } - case 3: - { - // Teleport to location. - } - } - } - if (action == MenuAction_Cancel) - { - if (slot == MenuCancel_ExitBack) - { - ZRAdminMenu(client); - } - } - if (action == MenuAction_End) - { - CloseHandle(menu_ztele); - } -} - -ZRLogFlagsMenu(client) -{ - new Handle:menu_log_flags = CreateMenu(ZRLogFlagsMenuHandle); - - SetGlobalTransTarget(client); - - SetMenuTitle(menu_log_flags, "%t\n ", "!zadmin log flags title"); - - //new client_flags = GetUserFlagBits(client); - //new item_state = (client_flags & ADMFLAG_ROOT) ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED; - - //decl String:z_log_core[64]; - - //Format(z_log_core, sizeof(z_log_core), "Log core events (%d)", LogCheckFlag(LOG_CORE_EVENTS)); - - //AddMenuItem(menu_log_flags, z_log_core, z_log_core, item_state); - - SetMenuExitBackButton(menu_log_flags, true); - DisplayMenu(menu_log_flags, client, MENU_TIME_FOREVER); -} - -public ZRLogFlagsMenuHandle(Handle:menu_log_flags, MenuAction:action, client, slot) -{ - if (action == MenuAction_Select) - { - switch(slot) - { - } - } - if (action == MenuAction_Cancel) - { - if (slot == MenuCancel_ExitBack) - { - ZRAdminMenu(client); - } - } - if (action == MenuAction_End) - { - CloseHandle(menu_log_flags); - } -} - -AddToKnockbackMultiplier(Float:value) -{ - new Float:current_val = GetConVarFloat(g_hCvarsList[CVAR_ZOMBIE_KNOCKBACK]); - SetConVarFloat(g_hCvarsList[CVAR_ZOMBIE_KNOCKBACK], current_val + value); -} - -AddToClassKnockback(classindex, Float:value) -{ - arrayClasses[classindex][data_knockback] = arrayClasses[classindex][data_knockback] + value; -} +} \ No newline at end of file