diff --git a/cstrike/addons/sourcemod/configs/zr/downloads.txt b/cstrike/addons/sourcemod/configs/zr/downloads.txt index f11d6b8..f9cbaaa 100644 --- a/cstrike/addons/sourcemod/configs/zr/downloads.txt +++ b/cstrike/addons/sourcemod/configs/zr/downloads.txt @@ -10,6 +10,7 @@ // ---------------------------------------------------------------------------- // Defaults: // ---------------------------------------------------------------------------- + materials/models/player/zh/Zombie_Classic_sheet.vmt materials/models/player/zh/corpse1.vmt materials/models/player/zh/Charple1_sheet.vmt diff --git a/cstrike/addons/sourcemod/configs/zr/hitgroups.txt b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt index 5965fd9..b354dec 100644 --- a/cstrike/addons/sourcemod/configs/zr/hitgroups.txt +++ b/cstrike/addons/sourcemod/configs/zr/hitgroups.txt @@ -12,7 +12,7 @@ // Attribute: Values: Description: // ---------------------------------------------------------------------------- // index number The hitgroup index. -// damage yes/no Allow damage to be done on this hitgroup for zombies. +// damage on/off Allow damage to be done on this hitgroup for zombies. // knockback decimal The knockback multiplier for this hitgroup. "hitgroups" // Counter-Strike: Source hitgroups @@ -23,7 +23,7 @@ "index" "0" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "1.0" @@ -35,7 +35,7 @@ "index" "1" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "2.0" @@ -47,7 +47,7 @@ "index" "2" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "1.3" @@ -59,7 +59,7 @@ "index" "3" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "1.2" @@ -71,7 +71,7 @@ "index" "4" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "1.0" @@ -83,7 +83,7 @@ "index" "5" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "1.0" @@ -95,7 +95,7 @@ "index" "6" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "0.9" @@ -107,7 +107,7 @@ "index" "7" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "0.9" @@ -119,7 +119,7 @@ "index" "8" // Damage - "damage" "yes" + "damage" "on" // Knockback "knockback" "1.0" diff --git a/cstrike/addons/sourcemod/configs/zr/models.txt b/cstrike/addons/sourcemod/configs/zr/models.txt index 40b6402..461a903 100644 --- a/cstrike/addons/sourcemod/configs/zr/models.txt +++ b/cstrike/addons/sourcemod/configs/zr/models.txt @@ -6,12 +6,25 @@ // Check the weapon configuration section in the manual for detailed info. // // ============================================================================ +// Format: +// ---------------------------------------------------------------------------- +// the/path/to/the/model ;public/hidden/adminonly/etc +// * ;public - The model will be treated as a model that any client has access to. +// * ;hidden - The model can only be accessed through explicit use of a player class. +// E.g. If a class uses the "random" setting for model, then any non-public +// models will not be chosen. +// ============================================================================ // * Each uncommented line will be used as a model path for clients to download, // and classes to utilize. +// * If no ; is specified, the model will be assumed as public. // ---------------------------------------------------------------------------- // Defaults: // ---------------------------------------------------------------------------- -models/player/zh/zh_charple001 -models/player/zh/zh_zombie003 -models/player/zh/zh_corpse002 -models/player/ics/hellknight_red/t_guerilla + +models/player/zh/zh_charple001 ;public +models/player/zh/zh_zombie003 ;public +models/player/zh/zh_corpse002 ;public +models/player/ics/hellknight_red/t_guerilla ;public +// models/player/adminmodels/1337model ;adminonly // None of these models will be randomly chosen. +// models/player/donatormodels/donatormodel ;donator +// models/player/hiddenmodels/myhiddenmodel ;non-public \ No newline at end of file diff --git a/cstrike/addons/sourcemod/configs/zr/playerclasses.txt b/cstrike/addons/sourcemod/configs/zr/playerclasses.txt index e353721..d75545a 100644 --- a/cstrike/addons/sourcemod/configs/zr/playerclasses.txt +++ b/cstrike/addons/sourcemod/configs/zr/playerclasses.txt @@ -1,9 +1,8 @@ // ============================================================================ // -// ZOMBIE:RELOADED -// Class configuration +// Zombie:Reloaded Class configuration // -// Check the class configuration section in the manual for detailed info. +// See Class Configuration (3.7) in the manual for detailed info. // // ============================================================================ // @@ -52,7 +51,7 @@ // Zombie classes // // ------------------------------------------ - "classic" + "zombie_classic" { // General "enabled" "1" @@ -95,7 +94,7 @@ "jump_distance" "1.2" } - "fast" + "zombie_fast" { // General "enabled" "1" @@ -138,7 +137,7 @@ "jump_distance" "1.2" } - "mutated" + "zombie_mutated" { // General "enabled" "1" @@ -181,7 +180,7 @@ "jump_distance" "1.3" } - "heavy" + "zombie_heavy" { // General "enabled" "1" @@ -224,6 +223,92 @@ "jump_distance" "0.9" } + "mother_zombie" + { + // General + "enabled" "1" + "team" "0" + "team_default" "0" + "flags" "2" + + "name" "Mother zombie" + "description" "+HP regen | +Speed | +Jump | -Knockback" + + // Model + "model_path" "models/player/zh/zh_charple001.mdl" + "alpha_initial" "255" + "alpha_damaged" "255" + "alpha_damage" "0" + + // Hud + "overlay_path" "overlays/zr/zvision" + "nvgs" "0" + "fov" "110" + + // Effects + "has_napalm" "0" + "napalm_time" "5.0" + + // Player behaviour + "immunity_mode" "0" + "immunity_amount" "0.0" + "no_fall_damage" "1" + + "health" "2500" + "health_regen_interval" "0.25" + "health_regen_amount" "10" + "health_infect_gain" "700" + "kill_bonus" "1" + + "speed" "400" + "knockback" "2.8" + "jump_height" "1.2" + "jump_distance" "1.3" + } + + "mother_zombie_admin" + { + // General + "enabled" "1" + "team" "0" + "team_default" "0" + "flags" "3" + + "name" "Admin mother zombie" + "description" "+HP regen | +Speed | +Jump | -Knockback" + + // Model + "model_path" "models/player/zh/zh_charple001.mdl" + "alpha_initial" "255" + "alpha_damaged" "255" + "alpha_damage" "0" + + // Hud + "overlay_path" "overlays/zr/zvision" + "nvgs" "0" + "fov" "110" + + // Effects + "has_napalm" "0" + "napalm_time" "3.0" + + // Player behaviour + "immunity_mode" "0" + "immunity_amount" "0.0" + "no_fall_damage" "1" + + "health" "3500" + "health_regen_interval" "0.25" + "health_regen_amount" "10" + "health_infect_gain" "700" + "kill_bonus" "1" + + "speed" "425" + "knockback" "2.8" + "jump_height" "1.2" + "jump_distance" "1.3" + } + // ------------------------------------------ // // Human classes @@ -273,6 +358,92 @@ "jump_distance" "1.0" } + "human_vip" + { + // General + "enabled" "1" + "team" "1" + "team_default" "0" + "flags" "0" + + "name" "VIP Human" + "description" "Human class for important players" + + // Model + "model_path" "default" + "alpha_initial" "255" + "alpha_damaged" "255" + "alpha_damage" "0" + + // Hud + "overlay_path" "" + "nvgs" "0" + "fov" "90" + + // Effects + "has_napalm" "1" + "napalm_time" "0.0" + + // Player behaviour + "immunity_mode" "0" + "immunity_amount" "0.0" + "no_fall_damage" "0" + + "health" "200" + "health_regen_interval" "1.0" + "health_regen_amount" "10" + "health_infect_gain" "0" + "kill_bonus" "2" + + "speed" "320" + "knockback" "0" + "jump_height" "1.1" + "jump_distance" "1.1" + } + + "human_admin" + { + // General + "enabled" "1" + "team" "1" + "team_default" "0" + "flags" "1" + + "name" "Admin Human" + "description" "Human class for admins" + + // Model + "model_path" "default" + "alpha_initial" "255" + "alpha_damaged" "255" + "alpha_damage" "0" + + // Hud + "overlay_path" "" + "nvgs" "0" + "fov" "90" + + // Effects + "has_napalm" "1" + "napalm_time" "0.0" + + // Player behaviour + "immunity_mode" "0" + "immunity_amount" "0.0" + "no_fall_damage" "1" + + "health" "200" + "health_regen_interval" "1.0" + "health_regen_amount" "10" + "health_infect_gain" "0" + "kill_bonus" "2" + + "speed" "320" + "knockback" "0" + "jump_height" "1.1" + "jump_distance" "1.1" + } + "human_speedy" { // General diff --git a/cstrike/addons/sourcemod/configs/zr/weapons.txt b/cstrike/addons/sourcemod/configs/zr/weapons.txt index 0307ce2..3548374 100644 --- a/cstrike/addons/sourcemod/configs/zr/weapons.txt +++ b/cstrike/addons/sourcemod/configs/zr/weapons.txt @@ -736,6 +736,7 @@ // General "weapontype" "All, Equipment" + "weaponslot" "5" // Restrict (core) diff --git a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt index b3d42d5..1f39ba8 100644 --- a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt +++ b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt @@ -9,25 +9,36 @@ "Offsets" { - - "EyeAngles" - { - "windows" "206" - "linux" "207" - } - "TraceAttack" { "windows" "58" "linux" "59" } - + "OnTakeDamage" { "windows" "60" "linux" "61" } + "StartTouch" + { + "windows" "88" + "linux" "89" + } + + "Touch" + { + "windows" "89" + "linux" "90" + } + + "EndTouch" + { + "windows" "90" + "linux" "91" + } + "Weapon_CanUse" { "windows" "216" diff --git a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt index a94bc35..78cff2f 100644 --- a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt +++ b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt @@ -143,7 +143,7 @@ "Config command reload all stats begin" { - "en" "Reloading all Zombie:Reloaded config files...\n ------------------------------------------------" + "en" "Reloading all Zombie:Reloaded config files...\n------------------------------------------------" } "Config command reload all stats successful" @@ -432,37 +432,37 @@ "Menu main zclass" { "#format" "{1:s}" - "en" "ZClass - Configure your class settings. (Command: {1})" + "en" "ZClass - Configure class settings. (Command: {1})" } "Menu main zcookies" { "#format" "{1:s}" - "en" "ZCookies - Toggle your personal ZR settings here. (Command: {1})" + "en" "ZCookies - Toggle personal ZR settings here. (Command: {1})" } "Menu main zspawn" { "#format" "{1:s}" - "en" "ZSpawn - Join late? Use this to spawn. (Command: {1})" + "en" "ZSpawn - Join late? Spawn with this. (Command: {1})" } "Menu main ztele" { "#format" "{1:s}" - "en" "ZTele - Teleport back to your spawn location. (Command: {1})" + "en" "ZTele - Stuck? Teleport back to spawn. (Command: {1})" } "Menu main zhp" { "#format" "{1:s}" - "en" "ZHP - Toggle real HP display when infected. (Command: {1})" + "en" "ZHP - Shows real HP as zombie. (Command: {1})" } "Menu main zmarket" { "#format" "{1:s}" - "en" "ZMarket - Need a weapon? Buy them here. (Command: {1})" + "en" "ZMarket - Customize loadouts here. (Command: {1})" } // =========================== @@ -634,7 +634,7 @@ "Weapons menu restrict types unrestrict all" { "#format" "{1:s}" - "en" "Unrestrict weapon type {1}\n " + "en" "Unrestrict weapon type {1}" } "Weapons menu restrict zmarket title" @@ -683,7 +683,7 @@ "Weapons menu zmarket loadout title" { - "en" "ZMarket\nMy Current Loadout:\nRebuy refers to these weapons" + "en" "ZMarket\nMy Current Loadout:\nSelect weapon slot to clear.\nNote: Rebuy refers to these weapons." } "Weapons menu zmarket loadout primary" @@ -716,6 +716,12 @@ "en" "Explosive: {1}" } + "Weapons menu zmarket loadout nvgs" + { + "#format" "{1:s}" + "en" "NVGs: {1}" + } + "Weapons menu zmarket loadout empty" { "en" "(None)" @@ -747,6 +753,25 @@ // Hitgroups (core) // =========================== + // Menu + + "Hitgroups menu hitgroups title" + { + "en" "Hitgroup Management\nCommands: zr_hitgroup(_enable_all/_headshots_only)\nSelect a Hitgroup to Toggle:" + } + + "Hitgroups menu hitgroups enable all" + { + "en" "Enable All Hitgroups" + } + + "Hitgroups menu hitgroups headshots only" + { + "en" "Headshots Only" + } + + // Commands + "Hitgroups command syntax" { "en" "Toggles or sets if a zombie's hitgroup can be damaged. Usage: zr_hitgroup [1/0]" @@ -790,6 +815,85 @@ "en" "Zombies may now only be damaged by headshots." } + // =========================== + // ZAdmin (core) + // =========================== + + "ZAdmin main title" + { + "en" "ZAdmin\nSelect Category:" + } + + "ZAdmin main class multipliers" + { + "en" "Class Multipliers" + } + + "ZAdmin main weapons" + { + "en" "Weapon Management" + } + + "ZAdmin main hitgroups" + { + "en" "Hitgroup Management" + } + + "ZAdmin main zombie" + { + "en" "Zombie Management" + } + + "ZAdmin main force zspawn" + { + "en" "Force ZSpawn" + } + + "ZAdmin main force ztele" + { + "en" "Force ZTele" + } + + // =========================== + // AntiStick (module) + // =========================== + + // Commands + + "AntiStick command set width syntax" + { + "en" "Sets the width of a model's hull. (See zr_antistick_list_models) Usage: zr_antistick_set_width " + } + + "AntiStick command list models list" + { + "en" "Showing all players' model data...\n------------------------------------------------" + } + + "AntiStick command list models name" + { + "#format" "{1:s},{2:s},{3:f}" + "en" "Player Name: {1} | Model Name: {2} | Model Hull Width: {3}" + } + + "AntiStick command set width successful" + { + "#format" "{1:s},{2:f}" + "en" "Model hull width for model \"{1}\" has been changed to \"{2}.\"" + } + + "AntiStick command set width invalid model" + { + "#format" "{1:s}" + "en" "Invalid model/player specified: \"{1}\"" + } + + "AntiStick command set width invalid width" + { + "#format" "{1:f}" + "en" "Invalid model hull width specified: \"{1}\"" + } + // =========================== // Spawn Protect (module) // =========================== @@ -848,6 +952,8 @@ // ZSpawn (module) // =========================== + // General + "ZSpawn double spawn" { "en" "ZSpawn can only be used if you joined late during a round in progress." @@ -859,6 +965,33 @@ "en" "The timelimit ({1} seconds), to use ZSpawn, has already expired." } + // Menu + + "ZSpawn clients title" + { + "en" "Force ZSpawn (zr_zspawn_force)\nSelect a Player:" + } + + // Commands + + "ZSpawn command force syntax" + { + "en" "Force ZSpawn on a client. Usage: zr_zspawn_force ['0' = Spawn as human | '1' = Spawn as zombie]" + + } + + "ZSpawn command force successful" + { + "#format" "{1:s}" + "en" "Player {1} was successfully spawned." + } + + "ZSpawn command force unsuccessful" + { + "#format" "{1:s}" + "en" "Player {1} couldn't be spawned." + } + // =========================== // ZTele (module) // =========================== @@ -906,6 +1039,33 @@ "en" "Teleported back to spawn. (Count: {1}/{2})" } + // Menu + + "ZTele clients title" + { + "en" "Force ZTele (zr_ztele_force)\nSelect a Player:" + } + + // Commands + + "ZTele command force syntax" + { + "en" "Force ZTele on a client. Usage: zr_ztele_force " + + } + + "ZTele command force successful" + { + "#format" "{1:s}" + "en" "Player {1} was successfully teleported." + } + + "ZTele command force unsuccessful" + { + "#format" "{1:s}" + "en" "Player {1} couldn't be teleported." + } + // =========================== // ZHP (module) // =========================== @@ -946,28 +1106,4 @@ "#format" "{1:s},{2:d}" "en" "Player \"{1}\" has been slayed for camping in a restricted area (ID: {2})." } - - // =========================== - // ZAdmin Menu - // =========================== - - "ZAdmin main title" - { - "en" "ZAdmin\n Select Category:" - } - - "ZAdmin main class multipliers" - { - "en" "Class Multipliers" - } - - "ZAdmin main weapons" - { - "en" "Weapon Management" - } - - "ZAdmin main zombie" - { - "en" "Zombie Management" - } } \ No newline at end of file diff --git a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg index 94d1f2d..fd17a27 100644 --- a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg +++ b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg @@ -324,12 +324,16 @@ zr_damage_block_blast "1" // Suicide Intercept // Intercept suicide commands attempted by zombies. +// Default: "0" +zr_damage_suicide_zombie "0" + +// Intercept suicide commands attempted by mother zombies. // Default: "1" -zr_damage_suicide_zombie "1" +zr_damage_suicide_mzombie "1" // Intercept suicide commands attempted by humans. -// Default: "1" -zr_damage_suicide_human "1" +// Default: "0" +zr_damage_suicide_human "0" // List of client commands to intercept as suicide attempts. [Delimiter: ", "] // Default: "kill, spectate, jointeam" @@ -503,9 +507,13 @@ zr_ambientsounds_volume "0.8" // Default: "1" zr_antistick "1" -// Time between each check for stuck players. [Dependency: zr_antistick] -// Default: "0.5" -zr_antistick_interval "0.5" +// The default width of player models, don't touch if you don't know what you're doing. [Dependency: zr_antistick] +// Default: "32.0" +zr_antistick_default_width "32.0" + +// File to store antistick model hull data. [Dependency: zr_antistick] +// Default: "data/antistick.dat" +zr_antistick_file_path "data/antistick.dat" // ---------------------------------------------------------------------------- diff --git a/docs/zr_3.0_release_notes.txt b/docs/zr_3.0_release_notes.txt new file mode 100644 index 0000000..97771e5 --- /dev/null +++ b/docs/zr_3.0_release_notes.txt @@ -0,0 +1,236 @@ +=============================================================================== + + Zombie:Reloaded Release Notes + + Targets plugin version 3.0.0, (not released) + Written by Richard Helgeby + + Last modified: 2009.06.27 + +=============================================================================== + +Release Notes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is a major release and it do break compatibility with older configuration! +Clean install of configuration files and reconfiguring is recommended. + +A lot of work is put into this plugin. The entire plugin is completely recoded +with lots of improvements and fixes. + +Our code base have expanded at least five times compared to version 2.5.1 (now +with source files above 20 000 lines). Of course, made with optimizing in mind. +This is, as far as we know, the biggest SourceMod plugin ever made! + +We also hope Zombie:Reloaded will be a good learning resource for new or +existing coders to find out how certain things are done. The code is well +structured and documented with comments explaining almost what every line do. + +In addition we try to make this a quality release with a well tested release +and a full user manual. Read the user manual for details on how to use or +configure individual features. Better quality and less time spent on support +gives more time for us to what we really want to do. + + +Richard Helgeby & +Greyscale + + +OVERVIEW OF MAJOR CHANGES +--------------------------- + +* New configuration style. Configuration files and CVARs are also validated so + errors and invalid values are caught early. + +* Expanded class system with support for human classes and additional + attributes like setting transparency on player classes, effects or other + special behaviour. + +* New weapon configurations that support knock back multipliers per weapon and + custom weapon groups for easy restriction. + +* Market feature for pre configuring or buying equimpents and weapons from the + oposite team, also outside the buy zone if allowed in configuration. + +* Improved knock back with support for scaling based on different modules. Now + it's possible to fully customize knock back behaviour. + +* Volumetric features. Define areas in maps and do certain stuff to players in + those areas based on a selection of features like the anti-camp. + +* Improved teleport settings. Delays and limits separated per team. + +* Admin menu. Configure certain settings in-game, do generic commands like + infect, spawn and teleport. + +* Cookies. This plugin is using the cookie system of SourceMod so player + preferences can be saved until next time they connect. + +* New logging system that is fully customizable. Makes it possible to decide + what stuff to be logged by setting generic logging flags and applying module + filters. + + +CONFIGURATION CHANGES +----------------------- + +Configuration settings are validated when the plugin starts. The plugin will +stop, use defaults or disable features if there are invalid values. Also a +warning is logged in the SourceMod error logs. + +The validation prevents unexpected or invalid behaviour in the plugin. Dealing +with errors or warnings in error logs helps a lot troubleshooting eventual +eventual issues in the plugin caused by incorrect configurations. + +It's also possible to specify the path of configuration files. This can be used +in combination with map configs, so it's possible to have different +configuration sets per map. + +Support for post map configs is made. These are configs executed after the +plugin and its features are loaded. Some settings can only be changed or +overridden after loading. Those commands must be placed in post map configs. + + +IMPROVED CLASS SYSTEM +----------------------- + +There's a lot of new features in the class system. The major change is that +it's made for multiple teams (humans and zombies). Now human classes can be +made. It has support for extended team filtering where admin-only and mother +zombie classes can be made. + +In addition any attribute on one or more classes can be modified in-game, which +expands the possibilities in combination with map configs. This makes it easier +to improve the map balance by adjusting attributes like health, knock back and +running speed. + +One of the new features is transparency on players. There are also immunity +modes (but it's currently a incomplete feature) that could implement slow +infection that requires zombies to stab multiple times with its knife before +the humans get infected, or stab them to death (turning into a zombie). + + +IMPROVED WEAPON SYSTEM +------------------------ + +The new weapon system lets makes it possible to do more than just restricting +weapons. Now it's possible to set knock back multipliers per weapon. + +Hit groups can also be configured with knock back multipliers, or disable +damage on certain hit groups completely. + +There's also a new market feature which is a custom buy menu with all available +weapons, including from the oposite team. It's also possible to buy weapons +outside the buy zone if the server admins enable that setting. + +Weapon selections can be pre configured and even saved using cookies so they +can be quickly bought on next spawn or on next connect to the server. + + +CUSTOMIZING KNOCK BACK +------------------------ + +The knock back is based on three factors that are multiplied into the effective +knock back: + + - Class knock back. This is the main value. + + - Weapon knock back. Set knock back scale values per weapon. + + - Hit group knock back. Customize or completely disable knock back scale + per hit group. + +With these factors it's possible to fully customize knock back. + + +VOLUMETRIC FEATURES +--------------------- + +(Currently in development) + +This is a brand new useful feature where custom defined areas in maps can do +certain stuff on players. These are the available features: + + - Anti-camp: Slay or warn players that stay too long in a certain area. + Useful in unfair camping places, or to avoid glitches in maps. + + - Modify class attributes. + + - Restrict weapons. Takes away ammo, and gives back when leaving area. + + - Modify ammo modes. + + - Modify knock back set on players or knock back in hit groups. + + - Teleporter. + +Features that modify settings will be reverted when players leave volumes. +Example of usage is to only allow pistols in tubes, use the anti-camp to hurt +humans camping in a certain unfair place, or fine tune knock back for a area in +the map. + + +TELEPORTER +------------ + +The teleporter is improved with more settings like these: + + - Deciding when players can teleport per team, before or after mother + zombie. + + - Setting teleport delays per team. + + - Limiting number of teleports per team. + + - Abuse protection: Automatically aborting a teleport in progress if the + player moves a certain distance (configurable). + + +ADMIN MENU +------------ + +A menu for admins with basic commands to configure certain settings in-game +or do generic commands. That is: + + - Infecting players. + + - Spawning players. + + - Modifying weapon restrictions. + + - Modifying class data. + + - Configuring log messages. + + +LOGGING SYSTEM +---------------- + +The logging system is based on logging flags and filtering that gives full +control of what log types and events to be logged. + +There are a few generic log events and settings, like these: + + - Core events: Executing config files, error messages, etc. + + - Game events: Admin commands, suicide prevention, anticamp kills, etc. + + - Player commands: Commands executed by non-admins: zspawn, teleport, class + change, etc. + + - Debug messages, if any. Usually only developers use this one. + + - Debug messages with more detail. It may cause spam, but this can be + avoided in combination with module filtering. + + - Ignoring log events caused by server commands (console), like from map + configs. + + - Logging to admin chat: A copy of the message is also logged to admins. + +In addition a module filter can be enabled. Only log messages from modules +listed in the filter is logged, other are ignored. Except fatal errors, those +are logged anyways. + +The logging system is made this way so server admins can monitor activity in +Zombie:Reloaded whithout reading spammed log messages. diff --git a/docs/zr_dev_manual.txt b/docs/zr_dev_manual.txt new file mode 100644 index 0000000..2fcbec5 --- /dev/null +++ b/docs/zr_dev_manual.txt @@ -0,0 +1,164 @@ +=============================================================================== + + Zombie:Reloaded + Technical Manual For Developers + + Targets plugin version 3.0.0, (not released) + Written by Richard Helgeby + + Manual last modified: 2009.04.25 + +=============================================================================== + +INDEX +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1.0 . . Introduction +1.1 . . . About This Manual +1.2 . . . Briefing + +2.0 . . Plugin Core +2.1 . . . Startup +2.2 . . . Console Variables +2.3 . . . Translations +2.4 . . . Offsets +2.5 . . . Models +2.6 . . . Round End Handler +2.7 . . . Infection Handler +2.8 . . . Damage Handler + +(account) +(say hooks) +(menu) +(commands) +(events) + +3.0 . . Log Module +3.1 . . . Description +3.2 . . . Logging Flags And Filters +3.3 . . . Formatted Log Messages +3.4 . . . The Log Function + +4.0 . . Class Module + +5.0 . . Weapon Module + +6.0 . . Hit Groups Module + +7.0 . . Visual Effects Module + +8.0 . . Sound Effects Module + +9.0 . . Anti-Stick Module + +10.0 . Knockback Module + +11.0 . Respawn Module + +12.0 . Spawn Protect Module + +13.0 . Napalm Grenades Module + +14.0 . HP Display Module + +15.0 . Teleport Module + + +1.0 INTRODUCTION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1.1 ABOUT THIS MANUAL +------------------------ + +The point of this manual is to describe how the plugin technically works so +it's easier for other developers to make modifications or join the development. + + +1.2 BRIEFING +--------------- + +The entire plugin is based on events in the game. It has a lot of features and +each feature is separated in its own module. Events are then forwarded to those +modules. + +There are core modules and optional modules. Core modules is features and stuff +that cannot be disabled and is required for the plugin to function. Optional +modules like respawning, sound effects or weapon restrictions can be disabled. + +Each module takes care of its own task. But modules have dependency, and events +should be forwarded in correct order. Usually only core modules depends on other +core modules. Optional modules should be independent. + + +2.0 PLUGIN CORE +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +3.0 LOG MODULE +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +3.1 DESCRIPTION +------------------ + +A plugin with a lots of modules and events needs a good logging system. The +user should be able to decide what's logged with logging flags. + + +3.2 LOGGING FLAGS AND FILTERS +-------------------------------- + +The log system decides what to log based on some generic log flags. Those flags +are stored in a bid field (http://en.wikipedia.org/wiki/Bit_field). + +An optional module filter can be enabled to only allow log events from user +specified modules. + +For performance reasons there should be a single function that tells whether it +should log or not, based on the specified module and generic event. The logging +function itself should not do such check and always log a message when called. + +(incomplete) + +How to store module flags? Key/values? Reading those flags MUST be cheap, so +the overall plugin performance isn't affected. + + +3.3 FORMATTED LOG MESSAGES +----------------------------- + +Each log message should tell the module and what part of it that fired the +log event. Also it must be possible to supply additional info as parameters +(the "any:..." parameter) to be used in the log message. These are easily' +parsed with VFormat. + + +3.4 THE LOG FUNCTION +----------------------- + +Syntax: + +LogMessageFormatted(client, + const String:module[], + const String:block[], + const String:message[], + type = LOG_FORMAT_TYPE_FULL, + any:...) + + Parameter: Description: + --------------------------------------------------------------------------- + client Specifies what client that triggered the event. Use -1 for + core events. + module What module the event was triggered in. + block What function or block that triggered the event. + message The log message. Can be formatted. + type Optional. Specifies what log type to use. Defaults to full. + any:... Formatting parameters for the log message. + +Example usage with flag check: + +if (LogCheckFlag(LOG_CORE_EVENTS, LOG_MODULE_CLASSES)) +{ + LogMessageFormatted(-1, "Classes", "Load", "Warning: Maximum classes reached (%d). Skipping other classes.", _, ZR_CLASS_MAX + 1); +} + +The module check will be replaced with something other than defined constants. diff --git a/docs/zr_manual.txt b/docs/zr_manual.txt new file mode 100644 index 0000000..5401bb6 --- /dev/null +++ b/docs/zr_manual.txt @@ -0,0 +1,2120 @@ +=============================================================================== + + Zombie:Reloaded User Manual + + Targets plugin version 3.0.0, (not released) + Written by Richard Helgeby + + Manual last modified: 2009.07.04 + +=============================================================================== + +INDEX +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1.0 . . Introduction +1.1 . . . About The Plugin +1.2 . . . Game Objectives +1.3 . . . Credits + +2.0 . . Installation +2.1 . . . Requirements +2.2 . . . Plugin Installation +2.3 . . . Test Run + +3.0 . . Configuration +3.1 . . . Understanding Syntax +3.1.1 . . . Optional Parameters +3.1.2 . . . Required Parameters +3.1.3 . . . Multiple Options In The Same Parameter +3.1.4 . . . Text As Parameters +3.2 . . . Configuration Files +3.3 . . . Logging +3.3.1 . . . Log Flags +3.3.2 . . . List Of Modules +3.4 . . . Custom Map Configuration Files +3.4.1 . . . Types +3.5 . . . Model List +3.6 . . . Download List +3.7 . . . Class Configuration +3.7.1 . . . Class Types +3.7.2 . . . Class Attributes +3.7.3 . . . Class Requirements +3.7.4 . . . Class Console Variables +3.7.5 . . . Modifying Class Attributes +3.8 . . . Weapon Configuration +3.8.1 . . . Attributes +3.8.2 . . . Weapon List +3.8.3 . . . Console Commands +3.9 . . . Hit Group Configuration +3.10 . . Infection Module +3.11 . . Damage Control Settings +3.12 . . Overlay Settings +3.13 . . Money Settings +3.14 . . Visual Effects Configuration +3.15 . . Sound Effects Configuration +3.16 . . Respawn Configuration +3.17 . . Spawn Command Configuration +3.18 . . Spawn Protect Configuration +3.19 . . Teleport Configuration +3.20 . . HP Display Settings +3.21 . . Jump Boost Settings +3.22 . . Anti-Stick Configuration +3.23 . . Volumetric Feature Configuration +3.23.1 . . Volume Attributes +3.23.2 . . Feature Attributes +3.23.3 . . Anti-Camp Feature + +4.0 . . How To Play +4.1 . . . Game Rules +4.2 . . . Chat Commands +4.3 . . . Using The Menus +4.4 . . . Teamwork +4.5 . . . Playing As Human +4.5.1 . . . Finding A Place To Hide +4.5.2 . . . Making Barricades +4.5.3 . . . Playing Fair +4.6 . . . Playing As Zombie +4.6.1 . . . Chasing Humans +4.6.2 . . . Avoiding Knockback +4.6.3 . . . Taking Advantage Of The Class Skills +4.7 . . . Physics Stuff +4.7.1 . . . Glitching Through Walls +4.7.2 . . . Jumping Through Non-Solid Props +4.7.3 . . . Jumping Fast In Small Areas + +5.0 . . Troubleshooting +5.1 . . . Verifying Requirements +5.2 . . . Startup +5.3 . . . Error and Warning Messages +5.4 . . . Common Problems + +6.0 . . Gameplay Guidelines +6.1 . . . Briefing - Map Configuration Files +6.2 . . . Map Balance +6.3 . . . Knockback Settings +6.4 . . . Map Time +6.5 . . . Servers With Unlimited Ammo And No Reloading + +7.0 . . Reporting Bugs and Improvements + + +1.0 INTRODUCTION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +1.1 ABOUT THE PLUGIN +----------------------- + +Zombie:Reloaded remake of Zombie Mod with a lot of new features and +improvements. It's made for a Counter-Strike: Source server and runs on a +powerful scripting platform called SourceMod. + + +1.2 GAME OBJECTIVES +---------------------- + +The objectives is to change the game into humans versus zombies. Humans try +to survive by camping, barricading and hiding. Zombies try to zombify humans +by using their knife. + +At a random time after the round starts, one or more random humans are turned +into zombies. Zombies have certain advantages as running faster and more +health points. Humans have huge amounts of ammo (or unlimited), and their +bullets knock back zombies. A lot more attributes can be adjusted for both +zombies and humans. + + +1.3 CREDITS +-------------- + +Concept: + c0ldfyr3 + - The developer of Zombie Mod . + +Developers and testers: + Greyscale + - Author of Zombie:Reloaded. The one who started remaking Zombie Mod for the + SourceMod platform. + + Richard Helgeby + - Zombie:Reloaded developer. Started working on the plugin from version + 2.5.1. Fixed bugs and made new features. + + Cpt. Moore + - Owner of the Zombie:Reloaded server "Zombie World Domination by + SwissQuake". Helped testing and debuging issues. Made some new features, + and used the server for testing. + + +Additional testers: + Grey Echo + zhelev81 + + +2.0 INSTALLATION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +2.1 REQUIREMENTS +------------------- + +Zombie: Reloaded requires that the following stuff is installed on the server: + + 1. Metamod:Source - A simplified API for server plugins. The original + Zombie Mod is run on this one. It makes it easier for developers to + make plugins like SourceMod: + + + + 2. SourceMod - A scripting platform: + + + + + 3. ZRTools extension (bundled). Provides some extra functions needed by + Zombie:Reloaded. See Plugin Installation (2.2). + + +2.2 PLUGIN INSTALLATION +-------------------------- + +Extract the content of the zip file into "cstrike/" on the server. + +This plugin is often confused by Zombie Mod, which is actually ovbious since +Zombie:Reloaded is a SourceMod alternative to Zombie Mod. + +We suggest having "Zombie:Reloaded" instead of "Zombie Mod" in the server name +if that's the case. No offense to the Zombie Mod team, of course, but we just +suggest this to help marketing Zombie:Reloaded. + + +2.3 TEST RUN +--------------- + +The plugin should work with default configuration. Start the server and join a +team. Once the round starts there sould be some messages at the chat with +"[ZR]". Or type "!zmenu" in the chat to bring up the zombie menu to confirm +that the plugin is running. + +Next check error logs from SourceMod and look if there are any entries from +"zombiereloaded.smx". If the plugin doesn't work at all or there are error +logs, see Troubleshooting at section 5.0. + + +3.0 CONFIGURATION +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +3.1 UNDERSTANDING SYNTAX +--------------------------- + +In this manual commands or paths may be written in a certain style that tells +how to use it. + +Note that the style itself is not written, but it's used as an indicator to +tell if a parameter is optional or not. + +Example syntax of a command: + + zr_class_modify [is_multiplier] + +Some paths may look like: + + cfg/sourcemod/zombiereloaded/.cfg + +How to read syntaxes like this is explained below. + + +3.1.1 OPTIONAL PARAMETERS + +Optional parameters is not required and usually have a default value or action. +They are marked with brackets. + +Example: + + zr_somecommand [number] + +Usage examples: + + zr_somecommand + zr_somecommand 10 + + +3.1.2 REQUIRED PARAMETERS + +Required parameters must be specified for the command to function. Usually if +no parameters are written the command replies with some info about the syntax. + +Less than (<) and greather than (>) symbols marks required parameters. + +Examples: + + zr_somecommand + zr_infect + +Usage examples: + + zr_somecommand 100 + zr_infect "unnamed" + + +3.1.3 MULTIPLE OPTIONS IN THE SAME PARAMETER + +Some commands have parameters that support multiple pre defined options. +Usually it's specifying a name, a index or a predefined value. Each option is +separated by a "|" symbol. Only one of the options listed is used in a command. + +Example: + + zr_do_something + +Usage examples: + + zr_do_something 1 + zr_do_something "all" + zr_do_something "unnamed" + + +3.1.4 TEXT AS PARAMETERS + +Since parameters are separated by spaces, text (strings) should be quoted. It's +a good habit to do this on all string parameters to avoid parsing mistakes. + +Example: + + zr_infect "unnamed" "player" + zr_do_something "example text. test." + +Example of bad usage: + + zr_do_something example text. test. + +The last example actually have 3 parameters while it should be only one. This +may cause unexpected results and is an example of why strings should be quoted. + + +3.2 CONFIGURATION FILES +-------------------------- + +These are the default configuration files. The paths are relative to the +"cstrike" folder. + + Type: File: + =========================================================================== + Main conf. cfg/sourcemod/zombiereloaded/zombiereloaded.cfg + Map conf. cfg/sourcemod/zombiereloaded/.cfg + Post map conf. cfg/sourcemod/zombiereloaded/.post.cfg + Hitgroup conf. addons/sourcemod/configs/zr/hitgroups.txt + Class conf. addons/sourcemod/configs/zr/playerclasses.txt + Weapon conf. addons/sourcemod/configs/zr/weapons.txt + Download list addons/sourcemod/configs/zr/downloads.txt + Model list addons/sourcemod/configs/zr/models.txt + +The post map configuration file is executed after all features of ZR is done +loading. Commands that modify loaded data must be put in post configuration +files. How to configure each file is explained in their own sections. + + +3.3 LOGGING +-------------- + +The log system used in Zombie:Reloaded is pretty powerful and customizable. +It's based on logging flags and a module filter. + +The flags tell what kind of events to log. Those flags are stored as a numeric +value in a bit field where each bit tell wether to log a certain event or not. +See for technical details. + +The module filter is a list of modules to enable log events from. This filter +gives extra control of what stuff to log. Use console commands below in the +main configuration file to add or remove modules to the filter. + +These commands might not work properly until bug 3828 in SourceMod is fixed +(http://bugs.alliedmods.net/show_bug.cgi?id=3828). It's a bug where console +commands in plugin configuration files are executed late so a command like +zr_log_add_module is too late. + +There are console variables for different log settings and exceptions. Place +them in the main configuration file. + +Console variables: + + Console variable: Default: + =========================================================================== + zr_log "1" + --------------------------------------------------------------------------- + Enable logging of events in the plugin. Fatal errors or errors are + independendt on this setting and always logged. + + Options: + 0 or 1 + + zr_log_flags "3" + --------------------------------------------------------------------------- + A bit field that specify what event types to log. + + Options: + Number - See Log Flags (3.3.1) + + zr_log_module_filter "0" + --------------------------------------------------------------------------- + Enable module filtering. Only log events from listed modules will be + logged. Use console commands below to add or remove modules from the + filter. + + Options: + 0 or 1 + + zr_log_ignore_console "1" + --------------------------------------------------------------------------- + Don't log events triggered by console that are executed by the console + itself, like commands in configs. Enable this command to avoid spamming + logs with events like weapon restrictions. + + Options: + 0 or 1 + + zr_log_print_admins "0" + --------------------------------------------------------------------------- + Print log events to admin chat in addition to the log file. + + Options: + 0 or 1 + + zr_log_print_chat "0" + --------------------------------------------------------------------------- + Print log events to public chat in addition to the log file. + + Options: + 0 or 1 + +Console commands: + + Syntax: + =========================================================================== + zr_log_add_module [modules...] + --------------------------------------------------------------------------- + Adds one or more modules to the module filter. Use short module names, + see List Of Modules (3.3.2). + + Parameters: + module Name of the module to add. + modules Additional modules to add. + + zr_log_remove_module [modules...] + --------------------------------------------------------------------------- + Removes one or more modules from the module filter. Use short module + names, see List Of Modules (3.3.2). + + Parameters: + module Name of the module to remove. + modules Additional modules to remove. + + zr_log_list + --------------------------------------------------------------------------- + Lists current log flag settings and module filtering settings. + + +3.3.1 LOG FLAGS + + Flag: Bit No.: Value: Description: + =========================================================================== + LOG_CORE_EVENTS 1 1 Log events from the plugin core like config + validation and other messages. + LOG_GAME_EVENTS 2 2 Log admin commands, console commands, and + game related events from modules like, + suicide attempts and weapon restrictions. + LOG_PLAYER_COMMANDS 3 4 Log events that are triggered by players, + like chat triggers, teleporting and class + changes. + LOG_DEBUG 4 8 Log debug messages, if any. Usually only + developers enable this log flag. + LOG_DEBUG_DETAIL 5 16 Log additional debug messages with more + details. May cause spam depending on module + filter settings. Usually only developers + enable this log flag. + +To combine several logging flags use the sum of their values. The default +value is 3, which is these log flags: + + LOG_CORE_EVENTS + LOG_GAME_EVENTS + 1 + 2 + +Most server setups donesn't need different flag settings. Default is fine. + +To decode the value you must convert it from decimals to binary, and count from +right to left what bits that are 1. Look up the bit number (not value) in the +table above. + +As an example on using the number 11 it's 1011 in binary. Counting from right +we see that the following bit numbers are on: 1, 2, and 4. That is the flags: + + LOG_CORE_EVENTS + LOG_GAME_EVENTS + LOG_DEBUG + +Most operating systems or distributions have a calculator that can convert +between binary and decimal numbers with scientific mode enabled. An online +unit converter like below can also be used. + + + + +3.3.2 LIST OF MODULES + + Short name: Description: + =========================================================================== + account Money manager + antistick Anti-Stick feature + config Configuration file manager + cvars Console variables + damage Damage manager + downloads File download manager + hitgroups Hit group feature + infect Infection manager + models Model list file manager + playerclasses Class manager + veffects Visual effect manager + seffects Sound effect manager + tools Helper functions (offsets) + volfeatures Volumetric features + weapons Weapon manager + weaponrestrict Weapon restriction manager + zspawn Spawn command manager + ztele Teleport manager + + +3.4 CUSTOM MAP CONFIGURATION FILES +------------------------------------- + +Configuration files for each map is supported. They're executed after the main +configuration files are executed, and are ideal for customizing map settings. +These files are just regular configuration files and can also have standard +console commands like setting map time. These files are optional. + +The main purpose of these files is to make it possible to change settings for +Zombie:Reloaded on certain maps. That could be scaling knockback, restricting +certain weapons, changing class attributes or changing ambience sound. + + +3.4.1 TYPES + +There are two kinds of map configs; pre and post. Pre map configuration files +are executed before the modules are loaded. They're useful for changing +configuration sets for certain modules like classes. Post map configuration +files are executed after the modules are loaded. Certain stuff have to be +placed in this one to take effect, like changing class attributes. + + Type: Executed: Path: + =========================================================================== + Pre Before modules cfg/sourcemod/zombiereloaded/.cfg + Post After modules cfg/sourcemod/zombiereloaded/.post.cfg + +If not explicit specified in the module documentation, use pre configuration. + + +3.5 MODEL CONFIGURATION +-------------------------- + +Note: Work in progress. Some flags explained in this section doesn't exist yet. + +The model configuration file is a list of models used on the server. Each line +contains the path including the model name, but not the file extension. + +The models listed in this file are also precached when the server starts. +Custom models used, but not listed in this file will cause a "model not +precached" error on the server, so remember to list them in this file. + +In addition certain flags can be added to mark the model as special, such as +only for admins/donators, hidden from random selection or only for mother +zombies. + +Each line is separated into two fields with ";". The last field is optional and +if no flag is specified it's treated as a regular public model. + +Model line syntax: + + [; flag] + +Available flags: + + "adminonly" - Model can only be used by admins. + "donator" - Model can only be used by donators. + "hidden" - Model is not included in random selections. + "motherzombie" - Model can only be used on mother zombies. + +Example usages: + + models/player/zh/zh_charple001 + models/player/zh/zh_corpse002; adminonly + models/player/zh/zh_zombie003; hidden + models/player/ics/hellknight_red/t_guerilla; motherzombie + +Put the list of models in: + + addons/sourcemod/configs/zr/models.txt + + +3.6 DOWNLOAD LIST +-------------------- + +Custom models, materials and overlays must be listed in the download list so +clients will download them. The paths must be relative to the "cstrike" folder. + +List files to be downloaded in: + + addons/sourcemod/configs/zr/downloads.txt + + +3.7 CLASS CONFIGURATION +-------------------------- + +The class system makes it possible to have different zombies and humans with +customized skills. It cannot be turned off. If there are only one class in each +team, the class selections menus are automatically disabled. + +The class configurations are stored in Valve's key/value format, and the file +that's loaded should be specified in the "zr_classes_file" console variable. +It's possible to change this variable with per-map configuration files to have +different sets of classes on one or more maps. + +Default path is: + + configs/zr/playerclasses.txt + +NOTE: The path is relative to the "sourcemod" folder. + +The file contains a short description of all attributes. Details are explained +below. + + +3.7.1 CLASS TYPES + +There are three class types; zombies, humans and admin-mode. Default classes +are selected on the player depending on console variables and the class file. + +Admin-mode classes are currently incomplete and will be validated, but ignored +in the game. This is a special mode in the game, but not the same as admin-only +classes. + + +3.7.2 CLASS ATTRIBUTES + +The list below explains all available class attributes in detail: + + Attribute: Value type: Limits/Requirements: + =========================================================================== + enabled boolean 0 or 1 + --------------------------------------------------------------------------- + Enables or disables the class. Disabled classes won't show up in the + class selection menus. Also, if some attributes failed to validate the + class will be disabled. + + team number 0 - 2 + --------------------------------------------------------------------------- + Specifies the class type (team ID). Class types are filtered in the + class selection menus, so only zombies can use zombie class types, and + only humans can use human class types. These are the allowed team IDs: + + 0 - Zombie classes + 1 - Human classes + 2 - Admin-mode classes + + The admin class type sets the player in spectacting like mode, but + allows admins to walk around. They can't take or give damage, and they + won't affect the game rules in any way. This feature is incomplete and + classes of this type is ignored in the game. + + See the "flags" attribute for admin-only classes. + + team_default boolean 0 or 1 + --------------------------------------------------------------------------- + Marks the class as the default class for its specified team. This class + will be automatically selected on new players when they join the + server, depending on what's specified as default in the main + configuration file (zr_classes_default_*). If multiple classes in the + same team is marked as default the first class marked as default is + used. + + flags number 0 - 3 + --------------------------------------------------------------------------- + Special class flags that are stored in a bit field (explained in 3.3, + Logging section). Available flags: + + 1 - Admins only. + Marks the class to be used by admins only. Classes with this option + on will not be visible for regular players in the class menu. + + 2 - Mother zombie. + Marks the class as a mother zombie class. These classes will be + used on mother zombies. Note that zr_classes_default_mother_zombie + setting must be set to "motherzombies" for this flag to take + effect. + + Remember that these flags can be used in a combination (1 + 2), so + it's a mother zombie class for admins only. + + name text Unique, not empty, max 64 charact. + --------------------------------------------------------------------------- + A unique name for the class that is displayed in the class selection + menus. Cannot be empty. If multiple classes have the same name, the + first one found is used. + + description text Max 256 characters, not empty + --------------------------------------------------------------------------- + The description of the class, used in class selection menus. Cannot be + empty. + + model_path text Max 256 characters, not empty + --------------------------------------------------------------------------- + The model file to use on the player, path is relative to the "cstrike" + folder. There are two special values supported by this attribute: + + "default" - Don't change model, use default CS models. + "random" - Selects a random model for the current team. + + alpha_spawn number 0 - 255 + --------------------------------------------------------------------------- + The initial transparency value on the player, where 255 is fully + visible and 0 is invisible. + + alpha_damaged number 0 - 255 + --------------------------------------------------------------------------- + Transparency on the player when a certain amount of damage is done. + 255 is fully visible and 0 is invisible. + + alpha_damage number 0 - 20000 + --------------------------------------------------------------------------- + How much damage that needs to be done before the players alpha changes + from "aplha_spawn" to "aplha_damaged". + + overlay_path text Max 256 characters + --------------------------------------------------------------------------- + Optional. Overlay texture to be displayed at the player. It can be + controlled by the night vision key ("n" by default). The path is + relative to "cstrike/materials". Leave blank to disable. + + nvgs boolean 0 or 1 + --------------------------------------------------------------------------- + Gives night vision to the player. + + fov number 15 - 165 + --------------------------------------------------------------------------- + The field of view on the player. Note that the weapon hud disappear if + FOV is anything else than 90. + + has_napalm boolean 0 or 1 + --------------------------------------------------------------------------- + Human classes only. Specifies whether the human can trow napalm + grenades or not. + + napalm_time decimal 0.0 - 600.0 + --------------------------------------------------------------------------- + Zombie classes only. Specifies how long in seconds zombies will burn + when hit by napalm grenades. 0.0 or a negative value will disable this + feature on the current class. This attribute has no effect on human + classes. + + immunity_mode number 0 - 2 + --------------------------------------------------------------------------- + The immunity mode. This feature is currently incomplete and values are + ignored. + + immunity_amount decimal (incomplete) + --------------------------------------------------------------------------- + The value for the specified immunity mode. This feature is currently + incomplete and values are ignored. + + no_fall_damage boolean 0 or 1 + --------------------------------------------------------------------------- + Blocks fall damage on the player. + + health number 0 - 20000 + --------------------------------------------------------------------------- + Initial health points on the player. + + health_regen_interval decimal 0.0 - 900.0 + --------------------------------------------------------------------------- + The health regeneration interval, in seconds. Use 0.0 to disable + regeneration. + + health_regen_amount number 0 - 10000 + --------------------------------------------------------------------------- + How many health points to give per interval. Regeneration stops when + the players health is above the initial health. + + health_infect_gain number 0 - 20000 + --------------------------------------------------------------------------- + Zombie classes only. How many health points to give the zombie each + time it infect a human. + + kill_bonus number 0 - 16 + --------------------------------------------------------------------------- + Human classes only. How many points to give the player each time he + kill a zombie. + + speed decimal 10.0 - 2000.0 + --------------------------------------------------------------------------- + The players running speed. + + knockback decimal -30.0 - 30.0 + --------------------------------------------------------------------------- + Zombie classes only. Force to apply on the zombie when shot at. The + zombie is pushed in the same direction as the bullet. + + jump_height decimal -500.0 - 500.0 + --------------------------------------------------------------------------- + Extra upward boost when jumping. + + jump_distance decimal -500.0 - 500.0 + --------------------------------------------------------------------------- + Extra forward boost when jumping. + + +3.7.3 CLASS REQUIREMENTS + +At least one zombie class and one human class with no special flags set is +required. Otherwise the plugin will fail to load. + +Requirements: + + - At least one human class (teamid 1). + - At least one zombie class (teamid 0) + - In addition both above classes shouldn't have special flags set. They + must be clean classes, which is flags set to "0". + +Errors are logged to SourceMod error logs if it can't parse the file or if +class attributes have invalid values. + +In case of incorrect values a warning will be logged and the class will be +disabled. The class index and the error flags (bit field) in the log message +tells what attributes that failed to validate. + +Attribute flags: + + Attribute: Bit: value: + ============================================= + enabled 1 1 + team 2 2 + team_default 3 4 + flags 4 8 + name 5 16 + description 6 32 + model_path 7 64 + alpha_initial 8 128 + alpha_damaged 9 256 + alpha_damage 10 512 + overlay_path 11 1024 + nvgs 12 2048 + fov 13 4096 + has_napalm 14 8192 + napalm_time 15 16384 + immunity_mode 16 32768 + immunity_amount 17 65536 + no_fall_damage 18 131072 + health 19 262144 + health_regen_interval 20 524288 + health_regen_amount 21 1048576 + infect_gain 22 2097152 + kill_bonus 23 4194304 + speed 24 8388608 + knockback 25 16777216 + jump_height 26 33554432 + jump_distance 27 67108864 + +The error flags are stored in a bit field (explained in the log configuration +in section 3.2). + +Another quick way to decode it would be to use the calculator in Windows. +Enable scientific mode and enter the decimal value. Then switch to binary mode +(F8) and count from right to left what bits that are 1. Look up the bit numbers +in the table above to see what attributes that didn't validate. + + +3.7.4 CLASS CONSOLE VARIABLES + +There are several console variables to set default class settings for players. +Place these console variables in the main configuration file: + + cfg/sourcemod/zombiereloaded/zombiereloaded.cfg + +And/or in a map config file: + + cfg/sourcemod/zombiereloaded/[.post].cfg + +Example map config files: + + cfg/sourcemod/zombiereloaded/zm_panic.cfg + cfg/sourcemod/zombiereloaded/zm_panic.post.cfg + +Class console variables: + + Console variable: Default: + =========================================================================== + zr_config_path_playerclasses "configs/zr/playerclasses.txt" + --------------------------------------------------------------------------- + Specifies what class configuration file to load. Several class + templates can be used with map configurations. + + Path is relative to "sourcemod". + + If used in map configuration files this console variable must be placed + in pre map configuration files. Post configuration files won't have any + effect because the class module is done loading. + + zr_classes_spawn 0 + --------------------------------------------------------------------------- + Re-display class menu every spawn. + + Options: + 0 or 1 + + zr_classes_random 0 + --------------------------------------------------------------------------- + Assign random classes to all players each round. + + Options: + 0 or 1 + + zr_classes_default_zombie "random" + --------------------------------------------------------------------------- + Default zombie class selected for all players when they connect. + + Options: + - Specify a class name to use as default zombie. + "default" - Use the default class in the class configuration. + "random" - Select a random class from the class configuration. + + zr_classes_default_mother_zombie "motherzombies" + --------------------------------------------------------------------------- + Default mother zombie class to be set on mother zombies. If no mother + zombie class exist it will use the class selected by the player. + + Options: + - Specify a class name to use as default mother zombie. + "random" - Select a random regular zombie class. + "motherzombies" - Select a random zombie class with mother zombie flag. + "disabled" - No change. Use the zombie class selected by the + player. + + zr_classes_default_human "random" + --------------------------------------------------------------------------- + Default human class selected for all players when they connect. + + Options: + - Specify a class name to use as default zombie. + "default" - Use the default class in the class configuration. + "random" - Select a random class from the class configuration. + + zr_classes_default_admin "random" + --------------------------------------------------------------------------- + Default admin-mode class selected for all players when they connect, if + found. This feature is incomplete and ignored. + + Options: + - Specify a class name to use as default. + "default" - Use the default class in the class configuration. + "random" - Select a random class from the class configuration. + + +3.7.5 MODIFYING CLASS ATTRIBUTES + +Classes can be modified after they're loaded. This is useful in map configs +to do stuff like scaling knockback to tune map balance. + +All attributes can be modified, and some can also be scaled with a multiplier. +The value in the original class cache is multiplied with the specified value +and written back to the modified cache. + +When multiplying, the value is always based on the original value, not +multiplying the earlier multiplied value. This also makes it easy to restore +the original value. + +Console commands: + + Syntax: + =========================================================================== + zr_class_modify [is_multiplier] + --------------------------------------------------------------------------- + Modify settings on one or more classes. + + Parameters: + class The class to modify. Can be any class name, or one of + the following team names; "all", "humans", "zombies" or + "admins". + attribute The name of the class attribute. + value Value to set, or multiplier if a multiplier. + is_multiplier Optional. Specifies wether the original value should be + multiplied by the specified value. Default is false. + + +3.8 WEAPON CONFIGURATION +--------------------------- + +The weapon module can be used to restict weapons or scale knockback. + + +3.8.1 WEAPON ATTRIBUTES + +Weapon attributes are stored by default in: + + addons/sourcemod/configs/zr/weapons.txt + +Custom file may be specified in the console variable "zr_config_path_weapons". +If used in per map configuration files it must be in a pre configuration file. + +These are the allowed attributes: + + Attribute: Type: Limits/Requirements: + =========================================================================== + weapontype text Separate items by ", ". + --------------------------------------------------------------------------- + A list of weapon groups and the weapon type. + + Pre defined options: + - All + - Pistol + - Shotgun + - SMG + - Rifle + - Sniper + - Machine Gun + - Melee + - Projectile + - Equipment + + weaponslot number 0 - 3. + --------------------------------------------------------------------------- + The slot index the weapon resides in. Don't change this! + + Options: + 0 - Primary weapon slot + 1 - Secondary weapon slot + 2 - Knife slot + 3 - Equipment slot + + restrictdefault text "yes" or "no" + --------------------------------------------------------------------------- + The default restricted status of the weapon on map start. + + Options: + "yes" - Enable + "no" - Disable + + toggleable text "yes" or "no" + --------------------------------------------------------------------------- + Enable weapon to have restrictions toggled mid-game. + + Options: + "yes" - Enable + "no" - Disable + + ammotype text - + --------------------------------------------------------------------------- + Ammo entity that belongs to weapons. Don't change this! + + Options: + ammo_50ae - deagle + ammo_762mm - scout, ak47, g3sg1, aug + ammo_556mm_box - m249 + ammo_556mm - galil, sg552, famas, m4a1, sg550 + ammo_338mag - awp + ammo_9mm - mp5navy, tmp, glock, elite + ammo_buckshot - m3, xm1014 + ammo_45acp - ump45, mac10, usp + ammo_357sig - P228 + ammo_57mm - p90, fiveseven + + ammoprice number - + --------------------------------------------------------------------------- + Price of ammo for this weapon. + + knockback decimal - + --------------------------------------------------------------------------- + The knock back multiplier for the weapon. 1.0 is no change, "0.5" gives + half knock back, and 2.0 gives double knock back. + + zmarketprice number - + --------------------------------------------------------------------------- + The price of the weapon in ZMarket. Default in configuration file is + CS:S buymenu price. + + zmarketpurchasemax number - + --------------------------------------------------------------------------- + The max number of purchases allowed per spawn for the weapon. + +The file structure is Valve's key/value format where the root section is named +"weapons" and a sub section for each weapon using short names from the list +below. + + +3.8.2 WEAPON LIST + + Weapon name: Type: Full name: + =========================================================================== + "Glock" Pistol Glock 18 Select Fire (9X19mm Sidearm) + "USP" Pistol .45 USP (K&M .45 Tactical) + "P228" Pistol 228 Compact + "Deagle" Pistol Desert Eagle .50C (Night Hawk .50C) + "Elite" Pistol .40 Dual Elites + "Fiveseven" Pistol ES Five-Seven + + "M3" Shotgun Benelli M3 (Leone 12 Gauge Super) + "XM1014" Shotgun Benelli XM1014 (Leone YG1265 Auto Shotgun) + + "Mac10" SMG Ingram MAC-10 + "TMP" SMG Steyr TMP (Schmidt Machine Pistol) + "MP5Navy" SMG HK MP5 Navy (KM Sub-Machine Gun) + "UMP45" SMG K&M UMP45 + "P90" SMG FN P90 (ES C90) + + "Galil" Rifle IMI Galil (IDF Defender) + "Famas" Rifle Giat FAMAS (Clarion 5.56) + "AK47" Rifle AK-47 (CV-47) + "M4A1" Rifle M4A1 Carbine (Maverick M4A1 Carbine) + "SG552" Rifle SIG SG552 (Krieg 552 Commando) + "AUG" Rifle Steyr AUG (Bullpup) + + "M249" Machine gun FN M249 (ES M249 Para) + + "Scout" Sniper Steyr Scout (Schmidt Scout) + "SG550" Sniper SIG SG550 (Krieg 550 Commando) + "G3SG1" Sniper G3/SG-1 (D3/AU-1) + "AWP" Sniper Arctic Warfare Magnum (Magnum Sniper Rifle) + + "hegrenade" Grenade High explosive grenade + "flashbang" Grenade Flash bang + "smokegrenade" Grenade Smoke grenade + + "NVGs" Equipment Night vision goggles + + +3.8.3 WEAPON COMMANDS + +Available commands for managing weapon restrictions. These can be used in the +main configuration file, or on a per-map basis with map configuration files. + + Syntax: + =========================================================================== + zr_restrict [weapon|weapontype] ... + --------------------------------------------------------------------------- + Restricts one or more weapons or weapon types (group). + + Parameters: + weapon The weapon name. + weapon type The weapon type group. + + zr_unrestrict + --------------------------------------------------------------------------- + Unrestricts one or more weapons or weapon types (group). + + Parameters: + weapon The weapon name. + weapon type The weapon type group. + + zmarket + --------------------------------------------------------------------------- + Displays the ZMarket weapon menu. + + +3.9 HIT GROUP CONFIGURATION +------------------------------ + +A hit group configuration makes it possible to disable damage or adjust knock +back per hit group. This is useful for fine tuning game balance. + +The hit group configuration file is a file in Valve's key/value format with +the root key "hitgroups" and a sub key for each hit group. + +The default file is: + + addons/sourcemod/configs/zr/hitgroups.txt + +Console commands: + + Syntax: + =========================================================================== + zr_hitgroup [value] + --------------------------------------------------------------------------- + Toggles or sets if a zombie's hitgroup can be damaged. + + Parameters: + hitgrup name Name of the hit group to adjust. Options: + "generic" + "head" + "chest" + "stomach" + "leftarm" + "rightarm" + "leftleg" + "rightleg" + "gear" + value Optional. Enable hit group damage. Default action is + to toggle setting. Options: 0 or 1 + + +3.9.1 HIT GROUP ATTRIBUTES + + Attribute: Type: Limits/Requirements: + =========================================================================== + index number - + --------------------------------------------------------------------------- + The hit group index. + + Options: + 0 - Generic + 1 - Head + 2 - Chest + 3 - Stomach + 4 - Left Arm + 5 - Right Arm + 6 - Left Leg + 7 - Right Leg + 8 - Gear + + damage text "yes" or "no" + --------------------------------------------------------------------------- + Allows damage to be done on the specified hit group for zombies. + + Options: + "yes" - Allow damage + "no" - Ignore damage + + knockback decimal - + --------------------------------------------------------------------------- + The knock back multiplier for the hitgroup. 1.0 for no change. + + +3.10 INFECTION MODULE +----------------------- + +The infection module handles all infection events and does random infection on +mother zombies. + +Number of mother zombies is based on a ratio setting, so on server with many +players more mother zombies will be spawned than on a server with few players. +Server admins can adjust this ratio to tune game balance. + +In addition several infection effects can be enabled or disabled. + +These are the console variables for the infection module: + + Console variable: Default: + =========================================================================== + zr_infect_mzombie_ratio 5 + --------------------------------------------------------------------------- + Mother zombie ratio. Every random N-th player is infected, in this case + it's 5. If it's set to 0 there will be only 1 mother zombie. + + Options: + 0 or a positive number + + zr_infect_mzombie_respawn 0 + --------------------------------------------------------------------------- + Teleport mother zombies to spawn place when infected. + + Options: + 0 or 1 + + zr_infect_spawntime_min 30.0 + --------------------------------------------------------------------------- + Minimum time when mother zombies spawn. Time is in seconds. + + zr_infect_spawntime_max 50.0 + --------------------------------------------------------------------------- + Maximum time when mother zombies spawn. Time is in seconds. + + zr_infect_consecutive_block 1 + --------------------------------------------------------------------------- + Blocks players from being mother zombie twice in a row. + + Options: + 0 or 1 + + zr_infect_weapons_drop 1 + --------------------------------------------------------------------------- + Force players to drop weapons and grenades when infected. So other + players can use them. + + Options: + 0 or 1 + + zr_infect_sound "npc/fast_zombie/fz_scream1.wav" + --------------------------------------------------------------------------- + Sound played when infected. The file path is relative to the "sounds" + folder. Leave blank ("") to disable infection sound. + + zr_infect_explosion 1 + --------------------------------------------------------------------------- + Enable explosion effects. If disabled, this setting will also disable + the following CVARs: + + zr_infect_fireball + zr_infect_smoke + zr_infect_smoke + + Options: + 0 or 1 + + zr_infect_fireball 1 + --------------------------------------------------------------------------- + Spawn a fire ball effect around the player on infection. + + Options: + 0 or 1 + + zr_infect_smoke 1 + --------------------------------------------------------------------------- + Spawn a smoke cloud effect around the player on infection. + + Options: + 0 or 1 + + zr_infect_sparks 1 + --------------------------------------------------------------------------- + Emit sparks from the the player on infection. + + Options: + 0 or 1 + + zr_infect_esplash 1 + --------------------------------------------------------------------------- + Emit an energy splash effect from the player on infection. + + Options: + 0 or 1 + + zr_infect_shake 1 + --------------------------------------------------------------------------- + Shake the player's view on infection. + + Options: + 0 or 1 + + zr_infect_shake_amp 15.0 + --------------------------------------------------------------------------- + Shake amplitude, how strong the shake is. Amplitude is in units. + + zr_infect_shake_frequency 1.0 + --------------------------------------------------------------------------- + Shake frequency, how fast the shake is. Frequency is in hertz (cycles + per second). + + zr_infect_shake_duration 5.0 + --------------------------------------------------------------------------- + Duration of shake, how long the shake lasts. Time is in seconds. + +Console commands: + + Syntax: + =========================================================================== + zr_infect [respawn] + --------------------------------------------------------------------------- + Infects one or more players. + + Parameters: + target A SourceMod target string with one or more players. + respawn Teleport players to spawn. + + zr_human [respawn] + --------------------------------------------------------------------------- + Turn one or more zombies into humans. + + Parameters: + target A SourceMod target string with one or more players. + respawn Teleport players to spawn. + + +3.11 DAMAGE CONTROL SETTINGS +------------------------------ + +With damage control it's possible to block suicide attempts, fall damage, blast +damage and hit group damage. See Hit Group Configuration (3.9) on how to +configure hit groups. + +Damage control console variables: + + Console variable: Default: + =========================================================================== + zr_damage_hitgroups 1 + --------------------------------------------------------------------------- + Enables hit group damage control. See Hit Group Configuration (3.9) on + how to configure hit groups. + + Options: + 0 or 1 + + zr_damage_block_ff 1 + --------------------------------------------------------------------------- + Block friendly fire between zombies. + + Options: + 0 or 1 + + zr_damage_block_blast 1 + --------------------------------------------------------------------------- + Block blast damage inflicted on self or teammates. + + Options: + 0 or 1 + + zr_damage_suicide_zombie 0 + --------------------------------------------------------------------------- + Block suicide attempts by regular zombies. + + Options: + 0 or 1 + + zr_damage_suicide_mzombie 1 + --------------------------------------------------------------------------- + Block suicide attempts by mother zombies. + + Options: + 0 or 1 + + zr_damage_suicide_human 0 + --------------------------------------------------------------------------- + Block suicide attempts by humans. + + Options: + 0 or 1 + + zr_damage_suicide_cmds "kill, spectate, jointeam" + --------------------------------------------------------------------------- + List of console commands that are treated as suicide attempts. + Separated by ", ". These commands are often bound to a key on the + client, like "m" is bound to "jointeam". + + +3.12 OVERLAY SETTINGS +------------------------ + +Overlays are pictures displayed on players' screen on certain events. However, +these overlays require DirectX 9 or higher to work. Players with lower DirectX +version won't see these overlays. + +Since these overlays doesn't last forever, they must be redisplayed at a +certain interval. A refresh once per seconds seems to be enough. + +When the round ends, overlays for either humans or zombies are displayed, +depending on the winning team. + +Overlays are also used as a class attribute, like the zombie vision effect. + +These are the overlay console variables: + + Console variable: Default: + =========================================================================== + zr_overlays_update_time 1.0 + --------------------------------------------------------------------------- + How often overlays are refreshed. Time is in seconds. + + zr_roundend_overlay 1 + --------------------------------------------------------------------------- + Show overlays for the winning team when the round ends. + + Options: + 0 or 1 + + zr_roundend_overlays_human "overlays/zr/humans_win" + --------------------------------------------------------------------------- + Overlay to be displayed when humans win. Path is relative to the + "materials" folder. + + zr_roundend_overlays_zombie "overlays/zr/zombies_win" + --------------------------------------------------------------------------- + Overlay to be displayed when zombies win. Path is relative to the + "materials" folder. + + +3.13 MONEY CONFIGURATION +--------------------------- + +Players' cash can be modified on every spawn if enabled. + + Console variable: Default: + =========================================================================== + zr_account_cashfill 1 + --------------------------------------------------------------------------- + Resets player's cash every spawn. Cash amount is specified in + zr_account_cashfill_value. + + Options: + 0 or 1 + + zr_account_cashfill_value 12000 + --------------------------------------------------------------------------- + How much cash to give each spawn, if enabled. + + Min: 0 + Max: 16000 + + zr_account_cashdmg 0 + --------------------------------------------------------------------------- + Attacker receives amount of cash equivalent to the damage that was + inflicted. If this one is enabled, the zr_account_cashfill and + zr_account_cashfill_value console variables is ignored. + + Options: + 0 or 1 + + +3.14 VISUAL EFFECTS CONFIGURATION +------------------------------------ + +With visual effects it makes it possible to give a creepy ambience. It's +possible to change light style in maps and set dissolve effects on players' +bodies when they die. + +It supposed to have support for adding fog, but because of technical limits in +SourceMod it's not possible yet. For developers who wonder why, it's because +it must be a env_fog_controller entity in the map. That entity isn't networked +so SourceMod can't modify or create that entity type. SourceMod may get this +feature in future versions. + +Console variables for visual effects: + + Console variable: Default: + =========================================================================== + zr_veffects_lightstyle 1 + --------------------------------------------------------------------------- + Change light style (brightness) in the map. + + Options: + 0 or 1 + + zr_veffects_lightstyle_value "b" + --------------------------------------------------------------------------- + Light brightness value. The brightness is represented by characters + from "a" to "z" where "a" is dark, "n" is normal, and "z" is bright. + + Options: + a (dark) to z (bright) + + zr_veffects_sky 1 + --------------------------------------------------------------------------- + Change skybox of the map. + + Options: + 0 or 1 + + zr_veffects_sky_path "sky_borealis01up.vmt" + --------------------------------------------------------------------------- + The skybox to use, if enabled. Path is relative to "materials/skybox". + + zr_veffects_sun_disable 1 + --------------------------------------------------------------------------- + Remove the sun entity on the map. Disables sun rendering on the map. + + Options: + 0 or 1 + + zr_veffects_fog 0 + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Enable fog on the map. + + Options: + 0 or 1 + + zr_veffects_fog_override 0 + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Override existing fog on the map. If fog exists already on the map, + replace it with the new modified fog. + + Options: + 0 or 1 + + zr_veffects_fog_pcolor "255 255 255" + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Sets the primary fog color. Three values from 0 to 255 separated by a + space, representing amount of red, green and blue. + + Examples: + "255 255 0" - Yellow + "255 0 255" - Purpule + "96 96 96" - Dark grey + + zr_veffects_fog_scolor "255 255 255" + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Sets the secondary fog color. Three values from 0 to 255 separated by a + space, representing amount of red, green and blue. + + Examples: + "255 255 0" - Yellow + "255 0 255" - Purpule + "96 96 96" - Dark grey + + zr_veffects_fog_density 0.8 + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Density (thickness) of the fog. The value is in percent, 0.0 to 1.0. + + Options: + 0.0 to 1.0 + + zr_veffects_fog_startdist 0 + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Distance from player to start rendering foremost fog. Distance is in + game units (1 unit is ~1 inch). For reference, default player models + are ~75 units tall. + + + zr_veffects_fog_enddist 400 + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Distance from player to stop rendering fog. Distance is in game units + (1 unit is ~1 inch). For reference, default player models are ~75 units + tall. + + zr_veffects_fog_farz 2000 + --------------------------------------------------------------------------- + (NOT SUPPORTED!) + Distance to stop render everything, for optimizing purposes. This + should be equal to or bigger than fog end distance. There's no reason + to render stuff that can't be seen anyways. + + zr_veffects_ragdoll_remove 1 + --------------------------------------------------------------------------- + Remove players' bodies when dying. + + Options: + 0 or 1 + + zr_veffects_ragdoll_dissolve -1 + --------------------------------------------------------------------------- + Dissolve effect to use when removing bodies. + + Options: + -2 No effect + -1 Random effect + 0 Energy dissolve + 1 Heavy electrical dissolve + 2 Light electrical dissolve + 3 Core dissolve + + zr_veffects_ragdoll_delay 0.5 + --------------------------------------------------------------------------- + Time to wait before removing dead bodies. Time is in seconds. + + zr_napalm_ignite 1 + --------------------------------------------------------------------------- + Ignite grenades that players throws. Humans need the class attribute + "has_napalm" set for this setting to take effect. + + Options: + 0 or 1 + + +3.15 SOUND EFFECTS CONFIGURATION +----------------------------------- + +The sound effects make zombies groan, in addition to the ambience sound file +that can be played. + +Currently it doesn't support any other custom files than the ambience file. +Other sounds are pre-configured. Instead it's possible to specify how often +the sounds should be played, if enabled. + +The lenght of the ambience file must be specified because SourceMod currently +can't detect lenght of MP3 files. + +Sound effect console variables: + + Console variable: Default: + =========================================================================== + zr_seffects_moan 30.0 + --------------------------------------------------------------------------- + Time between emission of a moan sound from a zombie. Time is in + secons. + + zr_seffects_groan 5 + --------------------------------------------------------------------------- + The probability that a groan sound will be emitted from a zombie when + shot. Probability is in percent. + + Options: + 0 to 100 + + zr_seffects_death 1 + --------------------------------------------------------------------------- + Emit a death sound when a zombie dies. + + Options: + 0 or 1 + + zr_ambientsounds 1 + --------------------------------------------------------------------------- + Enable ambient sound (background sound) to all players during gameplay. + + Options: + 0 or 1 + + zr_ambientsounds_file "ambient/zr/zr_ambience.mp3" + --------------------------------------------------------------------------- + The ambient sound file to play as ambienece. Path is relative to the + "sounds" folder, and MP3 files are supported. This sound is also + looped, so only use sounds that support loops. Otherwise it might sound + bad when it restarts. + + zr_ambientsounds_length 60.0 + --------------------------------------------------------------------------- + Length of the ambient sound. Length is in seconds. If the specified + length is shorter than the real sound length, the sound will start play + again before the previous sound finished. + + zr_ambientsounds_volume 0.8 + --------------------------------------------------------------------------- + Volume of ambient sound file. Volume is in percent. + + Options + 0.0 to 1.0 + + +3.16 RESPAWN CONFIGURATION +----------------------------- + +Respawning makes players spawn into the game again after death. It keeps the +game active and is less annoying for people who don't like to wait too much. + +If the mother zombie haven't spawned yet, players are always spawned as humans. + +Respawn console variables: + + Console variable: Default: + =========================================================================== + zr_respawn 1 + --------------------------------------------------------------------------- + Enable respawning. + + Options: + 0 or 1 + + zr_respawn_delay 1.0 + --------------------------------------------------------------------------- + Time after death to respawn. Time is in seconds. + + zr_respawn_team_zombie 1 + --------------------------------------------------------------------------- + Respawn as zombie. If the mother zombie haven't spawned yet, players + are always spawned as humans. + + Options: + 0 or 1 + + zr_respawn_team_zombie_world 1 + --------------------------------------------------------------------------- + Respawn as zombie if the player was killed by world damage. If the + mother zombie haven't spawned yet, players are always spawned as humans. + + Options: + 0 or 1 + + +3.17 SPAWN COMMAND CONFIGURATION +----------------------------------- + +The spawn command (zspawn) lets players join the game late, depending on the +time configured. To avoid abusing, there are settings that decides what team to +spawn on, and a time limit when the command is allowed to be used. + +ZSpawn console variables: + + Console variable: Default: + =========================================================================== + zr_zspawn 1 + --------------------------------------------------------------------------- + Enable spawn command. + + Options: + 0 or 1 + + zr_zspawn_team_overrride 1 + --------------------------------------------------------------------------- + Override what team to spawn to when using the spawn command. If + disabled it will use the zr_respawn_team_zombie setting. + + Options: + 0 or 1 + + zr_zspawn_team_zombie 0 + --------------------------------------------------------------------------- + Spawn as zombie if override setting is enabled. + + Options: + 0 or 1 + + zr_zspawn_timelimit 1 + --------------------------------------------------------------------------- + Put a time limit on the spawn command. + + Options: + 0 or 1 + + zr_zspawn_timelimit_time 120.0 + --------------------------------------------------------------------------- + How long the spawn command is available after round start, if enabled. + Time is in seconds. + + zr_zspawn_timelimit_zombie 1 + --------------------------------------------------------------------------- + Spawn as zombie if using the spawn command after the time limit is up. + + Options: + 0 or 1 + + +3.18 SPAWN PROTECT CONFIGURATION +----------------------------------- + +Spawning humans can have spawn protection settings that give them certain +advantages for a limited time. + +Spawn protection console variables: + + Console variable: Default: + =========================================================================== + zr_spawnprotect 1 + --------------------------------------------------------------------------- + Enable spawn protection for humans. + + Options: + 0 or 1 + + zr_spawnprotect_time 10 + --------------------------------------------------------------------------- + How long the spawn protection lasts. Time is in seconds. + + zr_spawnprotect_speed 600.0 + --------------------------------------------------------------------------- + Running speed for spawn protected players. Normal running speed is + 300.0. + + zr_spawnprotect_alpha 0 + --------------------------------------------------------------------------- + Transparency setting on spawn protected players. + + Options: + 0 (transparent) to 255 (fully visible) + +Console commands: + + Syntax: + =========================================================================== + zr_zspawn_force [spawn team] + --------------------------------------------------------------------------- + Force one or more players to spawn. + + Parameters: + target A SourceMod target string with one or more players. + spawn team Optional. Specify what team to spawn to. Options: + 0 (humans) or 1 (zombies) + + +3.19 TELEPORT CONFIGURATION +------------------------------ + +Zombie:Reloaded got a built in teleport feature with support for limits, delays +and abuse protection. + +Teleport console variables: + + Console variable: Default: + =========================================================================== + zr_ztele_zombie 1 + --------------------------------------------------------------------------- + Allow zombies to use the teleporter. + + Options: + 0 or 1 + + zr_ztele_human_before 1 + --------------------------------------------------------------------------- + Allow humans to use the teleporter before mother zombies have spawned. + + Options: + 0 or 1 + + zr_ztele_human_after 0 + --------------------------------------------------------------------------- + Allow humans to use the teleporter after mother zombies have spawned. + + Options: + 0 or 1 + + zr_ztele_delay_zombie 3.0 + --------------------------------------------------------------------------- + Delay between teleport command and teleport for zombies. Time is in + seconds. + + zr_ztele_delay_human 3.0 + --------------------------------------------------------------------------- + Delay between teleport command and teleport for humans. Time is in + seconds. + + zr_ztele_max_zombie 3 + --------------------------------------------------------------------------- + Maximum number of teleports zombies can do in a round. + + zr_ztele_max_human 1 + --------------------------------------------------------------------------- + Maximum number of teleports humans can do in a round. + + zr_ztele_autocancel 1 + --------------------------------------------------------------------------- + Automatically cancel a teleport in progress if moving a certain + distance. + + Options: + 0 or 1 + + zr_ztele_autocancel_distance 20 + --------------------------------------------------------------------------- + Maximum distance for automatically canceling a teleport. Distance is in + feet. 1 feet is 16 game units where a game unit is ~1 inch. For + reference a player is ~75 units tall. + +Teleport console commands: + + Syntax: + =========================================================================== + zr_tele_force + --------------------------------------------------------------------------- + Force teleport on a player. Does not add delay or add to teleport + count. + + Parameters: + client Single target player. Support SourceMod targets like + @me and @aim. + + +3.20 HP DISPLAY SETTINGS +--------------------------- + +The HP display is a small panel on the center at the bottom of the screen that +displays players' health. Players can disable this, and the setting can also be +saved in player cookies. + +Console variables: + + Console variable: Default: + =========================================================================== + zr_zhp 1 + --------------------------------------------------------------------------- + Enable HP display for zombies. + + Options: + 0 or 1 + + zr_zhp_default 1 + --------------------------------------------------------------------------- + Default HP display state on connecting players. + + Options: + 0 or 1 + + +3.21 JUMP BOOST SETTINGS +--------------------------- + +Jump boost can be abused to do bunny hops. There are settings for configuring +maximum allowed velocity when jumping. If maximum speed is reached no +horizontal jump boost is applied. + +Console variables: + + Console variable: Default: + =========================================================================== + zr_jumpboost_bhop_protect 1 + --------------------------------------------------------------------------- + Enable bunny hop protection. + + Options: + 0 or 1 + + zr_jumpboost_bhop_max 300.0 + --------------------------------------------------------------------------- + Maximum horizontal velocity allowed when jumping. Normal running speed + for the player is 300.0 + + +3.22 ANTI-STICK SETTINGS +--------------------------- + +The anti-stick system is a no-block system that turns off collisions on players +that are stuck together, and enable collision again when they're unstuck. + +To know if players are stuck, it needs some extra info about each model used in +the game. Data for these models are stored in the following file: + + "data/antistick.dat" + +The file path is relative to the "sourcemod" folder. + +Console variables: + + Console variable: Default: + =========================================================================== + zr_antistick 1 + --------------------------------------------------------------------------- + Enable anti-stick system + + Options: + 0 or 1 + + zr_antistick_default_width 32.0 + --------------------------------------------------------------------------- + Default model width used to detect if players are stuck together. Width + is in game units. + + Do not touch this variable if you don't know what you're doing! + + zr_antistick_file_path "data/antistick.dat" + --------------------------------------------------------------------------- + File to store anti-stick model hull data. Path is default to the + "sourcemod" folder. + + +3.23 VOLUMETRIC FEATURE CONFIGURATION +---------------------------------------- + +3.23.1 VOLUME ATTRIBUTES + +3.23.2 FEATURE ATTRIBUTES + +3.23.3 ANTI-CAMP FEATURE + + +4.0 HOW TO PLAY +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +(how to defend against zombies, in a fair way) +(zombie tricks, getting through non-solid props) + +4.1 GAME RULES +----------------- + + +4.2 CHAT COMMANDS +-------------------- + + +4.3 USING THE MENUS +---------------------- + + +4.4 TEAMWORK +--------------- + + +4.5 PLAYING AS HUMAN +----------------------- + +4.5.1 FINDING A PLACE TO HIDE + + +4.5.2 MAKING BARRICADES + + +4.5.3 PLAYING FAIR + + +4.6 PLAYING AS ZOMBIE +------------------------ + +4.6.1 CHASING HUMANS + + +4.6.2 AVOIDING KNOCKBACK + + +4.6.3 TAKING ADVANTAGE OF THE CLASS SKILLS + +(bunny jump) +(invisible, act as a spy and surprise humans) + + +4.7 PHYSICS STUFF +-------------------- + +There are glitches and simplified physics stuff that can be used to get an +advantage. Some servers may not allow all of these tricks. + + +4.7.1 GLITCHING THROUGH WALLS + +(bad thing to do, and should not be allowed) + + +4.7.2 JUMPING THROUGH NON-SOLID PROPS + +Realistic physics in multiplayer games is a expensive task for the server and +it appears to be laggy for players. The solution to this is simplified physics +on props (that is simplified collision detection). + +Some props aren't solid but pushes players away from it's origin (center of the +object). This is NOT a engine bug, but a simplified solution. These props are +useful to _delay_ zombies in barricades, but they're still fair to use. If +players got enough speed they can run and jump through them. + +There's another trick that works quite good if the knock back is balanced +correctly. If a player look straight down or straight up it's possible to +simply walk through non-solid props, or at the same time, jumping slowly +through them. + + +4.7.3 JUMPING FAST IN SMALL AREAS + +When zombies have to crouch to enter a area where humans camp (like tubes and +vents), jumping fast helps a lot. + +When jumping it's not easy for humans to hit the head and they can't get that +good knock back anymore. With multiple zombies jumping fast, pushing eachother +on their way into a tube, the humans are doomed. The tube camping problem much +better balanced. + + +5.0 TROUBLESHOOTING +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +5.1 VERIFY REQUIREMENTS +-------------------------- + + +5.2 STARTUP +-------------- + + +5.3 ERROR MESSAGES +--------------------- + + +5.4 COMMON PROBLEMS +---------------------- + + +6.0 GAMEPLAY GUIDELINES +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +6.1 BRIEFING - MAP CONFIGURATION FILES +----------------------------------------- + + +6.2 MAP BALANCE +------------------- + + +6.3 KNOCKBACK SETTINGS +------------------------- + + +6.4 MAP TIME +--------------- + + +6.5 SERVERS WITH UNLIMITED AMMO AND NO RELOADING +--------------------------------------------------- + + +7.0 REPORTING BUGS AND IMPROVEMENTS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/include/zrtools.inc b/src/include/zrtools.inc index 94734a7..ed20afe 100644 --- a/src/include/zrtools.inc +++ b/src/include/zrtools.inc @@ -125,6 +125,81 @@ native ZRTools_HookOnTakeDamage(client, ZRTools_OnTakeDamage:callback); */ native ZRTools_UnhookOnTakeDamage(hookid); +/** + * Callback function for StartTouch. + * + * @param client The client index. + * @param entity The entity index of the entity being touched. + */ +functag public ZRTools_Action:ZRTools_StartTouch(client, entity); + +/** + * Hooks StartTouch on a client. + * + * @param client The client index. + * @param callback The callback function for hook. + * @return The unique HookID. + */ +native ZRTools_HookStartTouch(client, ZRTools_StartTouch:callback); + +/** + * Unhooks StartTouch on a client. + * + * @param hookid The HookID of the hook. + * @error Invalid HookID. + */ +native ZRTools_UnhookStartTouch(hookid); + +/** + * Callback function for Touch. + * + * @param client The client index. + * @param entity The entity index of the entity being touched. + */ +functag public ZRTools_Action:ZRTools_Touch(client, entity); + +/** + * Hooks Touch on a client. + * + * @param client The client index. + * @param callback The callback function for hook. + * @return The unique HookID. + */ +native ZRTools_HookTouch(client, ZRTools_Touch:callback); + +/** + * Unhooks Touch on a client. + * + * @param hookid The HookID of the hook. + * @error Invalid HookID. + */ +native ZRTools_UnhookTouch(hookid); + +/** + * Callback function for EndTouch. + * + * @param client The client index. + * @param entity The entity index of the entity being touched. + */ +functag public ZRTools_Action:ZRTools_EndTouch(client, entity); + +/** + * Hooks EndTouch on a client. + * + * @param client The client index. + * @param callback The callback function for hook. + * @return The unique HookID. + */ +native ZRTools_HookEndTouch(client, ZRTools_EndTouch:callback); + +/** + * Unhooks EndTouch on a client. + * + * @param hookid The HookID of the hook. + * @error Invalid HookID. + */ +native ZRTools_UnhookEndTouch(hookid); + /** * Callback function for Weapon_CanUse. * Called when a client attempts to pick up a weapon. diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index aa8f4f0..87c55fd 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zombiereloaded.sp * Type: Base @@ -136,7 +136,6 @@ public OnMapStart() RoundEndOnMapStart(); InfectOnMapStart(); SEffectsOnMapStart(); - AntiStickOnMapStart(); ZSpawnOnMapStart(); } @@ -163,6 +162,7 @@ public OnConfigsExecuted() InfectLoad(); VEffectsLoad(); SEffectsLoad(); + AntiStickLoad(); ClassLoad(); VolLoad(); @@ -185,6 +185,7 @@ public OnClientPutInServer(client) InfectClientInit(client); DamageClientInit(client); SEffectsClientInit(client); + AntiStickClientInit(client); SpawnProtectClientInit(client); RespawnClientInit(client); ZTeleClientInit(client); @@ -203,6 +204,7 @@ public OnClientDisconnect(client) WeaponsOnClientDisconnect(client); InfectOnClientDisconnect(client); DamageOnClientDisconnect(client); + AntiStickOnClientDisconnect(client); ZSpawnOnClientDisconnect(client); VolOnPlayerDisconnect(client); } diff --git a/src/zr/account.inc b/src/zr/account.inc index 22f2cb2..191d23c 100644 --- a/src/zr/account.inc +++ b/src/zr/account.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: account.inc * Type: Module diff --git a/src/zr/antistick.inc b/src/zr/antistick.inc index f6c3cf8..e215445 100644 --- a/src/zr/antistick.inc +++ b/src/zr/antistick.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: antistick.inc * Type: Module @@ -35,58 +35,58 @@ */ /** - * @section Offsets relating to player hull dimensions. -*/ -#define ANTISTICK_PLAYER_HULL_XY_OFFSET 32 -#define ANTISTICK_PLAYER_HULL_Z_OFFSET 12 -#define ANTISTICK_PLAYER_HULL_STACK_OFFSET 14 -/** - * @endsection -*/ + * Default player hull width. + */ +#define ANTISTICK_DEFAULT_HULL_WIDTH GetConVarFloat(g_hCvarsList[CVAR_ANTISTICK_DEFAULT_WIDTH]) /** - * Variable to store antistick offset value. + * Handle to keyvalue structure where data is stored. */ -new g_iToolsCollisionGroup; +new Handle:g_kvAntiStick = INVALID_HANDLE; /** - * Handle to keep track of AntiStickTimer. + * Stores "StartTouch" HookID's for each client. */ -new Handle:tAntiStick = INVALID_HANDLE; +new g_iStartTouchHookID[MAXPLAYERS + 1] = {-1, ...}; /** - * Find antistick-specific offsets here. + * List of components that make up the model's rectangular boundaries. + * + * F = Front + * B = Back + * L = Left + * R = Right + * U = Upper + * D = Down */ -AntiStickOnOffsetsFound() +enum AntiStickBoxBound { - // If offset "m_CollisionGroup" can't be found, then stop the plugin. - g_iToolsCollisionGroup = FindSendPropInfo("CBaseEntity", "m_CollisionGroup"); - if (g_iToolsCollisionGroup == -1) - { - LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Antistick, "Offsets", "Offset \"CBaseEntity::m_CollisionGroup\" was not found."); - } + BoxBound_FUR = 0, /** Front upper right */ + BoxBound_FUL, /** etc.. */ + BoxBound_FDR, + BoxBound_FDL, + BoxBound_BUR, + BoxBound_BUL, + BoxBound_BDR, + BoxBound_BDL, } - /** - * Map is starting. + * Create commands related to antistick here. */ -AntiStickOnMapStart() +AntiStickOnCommandsCreate() { - // Reset timer handle. - tAntiStick = INVALID_HANDLE; -} - -/** - * The round is starting. - */ -AntiStickOnRoundStart() -{ - // If timer is running, kill it. - if (tAntiStick != INVALID_HANDLE) - { - KillTimer(tAntiStick); - } + // Create public command to list model data. + RegConsoleCmd("zr_antistick_list_models", AntiStickListModelsCommand, "Lists all players and their model data in console. Usage: zr_antistick_list_models"); + // Create admin command to set model hull width. + RegAdminCmd("zr_antistick_set_width", AntiStickSetWidthCommand, ADMFLAG_GENERIC, "Sets the width of a model's hull. (See zr_antistick_list_models) Usage: zr_antistick_set_width "); +} + +/** + * Creates/loads antistick data file. + */ +AntiStickLoad() +{ // If antistick is disabled, then stop. new bool:antistick = GetConVarBool(g_hCvarsList[CVAR_ANTISTICK]); if (!antistick) @@ -94,118 +94,441 @@ AntiStickOnRoundStart() return; } - new Float:interval = GetConVarFloat(g_hCvarsList[CVAR_ANTISTICK_INTERVAL]); - tAntiStick = CreateTimer(interval, AntiStickTimer, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); + // Create antistick keyvalues if it hasn't been created yet. + if (g_kvAntiStick == INVALID_HANDLE) + { + g_kvAntiStick = CreateKeyValues("antistick"); + } + + // Initialize keyvalues. + if (!AntiStickLoadData()) + { + AntiStickSaveData(); + } +} + +/** + * Client is joining the server. + * + * @param client The client index. + */ +AntiStickClientInit(client) +{ + // Hook "StartTouch" and "EndTouch" on client. + g_iStartTouchHookID[client] = ZRTools_HookStartTouch(client, AntiStickStartTouch); +} + +/** + * Unhook StartTouch and EndTouch function on a client. + * + * @param client The client index. + */ +AntiStickOnClientDisconnect(client) +{ + // Unhook "StartTouch" callback, and reset variable. + if (g_iStartTouchHookID[client] != -1) + { + ZRTools_UnhookStartTouch(g_iStartTouchHookID[client]); + g_iStartTouchHookID[client] = -1; + } +} + +/** + * Load antistick data from file. + * + * @return True if loaded successfully, false if file wasn't found. + */ +stock bool:AntiStickLoadData() +{ + // Get cvar's path. + decl String:filepath[PLATFORM_MAX_PATH]; + GetConVarString(g_hCvarsList[CVAR_ANTISTICK_FILE_PATH], filepath, sizeof(filepath)); + + // Build full path in return string. + decl String:fullpath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, fullpath, PLATFORM_MAX_PATH, filepath); + + // Log action to game events. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_AntiStick, "Loaded Data", "Antistick data has been loaded from \"%s\"", fullpath); + + // Retrieve keyvalue data from a file, and store in server's memory. + KvRewind(g_kvAntiStick); + return FileToKeyValues(g_kvAntiStick, fullpath); +} + +/** + * Save antistick data to file. + */ +stock AntiStickSaveData() +{ + // Get cvar's path. + decl String:filepath[PLATFORM_MAX_PATH]; + GetConVarString(g_hCvarsList[CVAR_ANTISTICK_FILE_PATH], filepath, sizeof(filepath)); + + // Build full path in return string. + decl String:fullpath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, fullpath, PLATFORM_MAX_PATH, filepath); + + // Log action to game events. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_AntiStick, "Saved Data", "Antistick data has been saved to \"%s\"", fullpath); + + // Dump keyvalue structure into a file from the server's memory. + KvRewind(g_kvAntiStick); + KeyValuesToFile(g_kvAntiStick, fullpath); +} + +/** + * Get hull width on a client's model. (or return default) + * + * @param client The client index. + * @param model If a client index of 0 is given, this model is used. + */ +stock Float:AntiStickGetModelHullWidth(client, const String:model[] = "") +{ + decl String:clientmodel[PLATFORM_MAX_PATH]; + + if (ZRIsClientValid(client)) + { + // Get client's model. + GetClientModel(client, clientmodel, sizeof(clientmodel)); + } + else + { + // Copy given model to 'clientmodel.' + strcopy(clientmodel, sizeof(clientmodel), model); + } + + // Find model in antistick data. + KvRewind(g_kvAntiStick); + if (KvJumpToKey(g_kvAntiStick, clientmodel)) + { + // Return value from file. + return KvGetFloat(g_kvAntiStick, "hull_width", ANTISTICK_DEFAULT_HULL_WIDTH); + } + else + { + // Return default CS:S hull width. + return ANTISTICK_DEFAULT_HULL_WIDTH; + } +} + +/** + * Set hull width on a client's model. + * + * @param client The client index. + * @param model If a client index of 0 is given, this model is used. + * @param hull_width The width of the model hull. + */ +stock AntiStickSetModelHullWidth(client, const String:model[] = "", Float:hull_width) +{ + decl String:clientmodel[PLATFORM_MAX_PATH]; + + if (ZRIsClientValid(client)) + { + // Get client's model. + GetClientModel(client, clientmodel, sizeof(clientmodel)); + } + else + { + // Copy given model to 'clientmodel.' + strcopy(clientmodel, sizeof(clientmodel), model); + } + + // Replace "/" with "-" because a slash indicates a new level in keyvalues. + ReplaceString(clientmodel, sizeof(clientmodel), "/", "-"); + + // Find model in antistick data. + KvRewind(g_kvAntiStick); + + // Create key if it doesn't already exist. + KvJumpToKey(g_kvAntiStick, clientmodel, true); + + // Set value. + KvSetFloat(g_kvAntiStick, "hull_width", hull_width); +} + +/** + * Callback function for StartTouch. + * + * @param client The client index. + * @param entity The entity index of the entity being touched. + */ +public ZRTools_Action:AntiStickStartTouch(client, entity) +{ + // If client isn't in-game, then stop. + if (!IsClientInGame(client)) + { + return; + } + + // If client is touching themselves, then leave them alone :P + if (client == entity) + { + return; + } + + // If touched entity isn't a valid client, then stop. + if (!ZRIsClientValid(entity)) + { + return; + } + + // If the clients aren't colliding, then stop. + if (!AntiStickIsModelBoxColliding(client, entity)) + { + return; + } + + // Disable collisions to unstick, and start timers to re-solidify. + if (AntiStickClientCollisionGroup(client) == ANTISTICK_COLLISIONS_ON) + { + AntiStickClientCollisionGroup(client, true, ANTISTICK_COLLISIONS_OFF); + CreateTimer(0.0, AntiStickSolidifyTimer, client, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); + } + + if (AntiStickClientCollisionGroup(entity) == ANTISTICK_COLLISIONS_ON) + { + AntiStickClientCollisionGroup(entity, true, ANTISTICK_COLLISIONS_OFF); + CreateTimer(0.0, AntiStickSolidifyTimer, entity, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); + } +} + +/** + * Callback function for EndTouch. + * + * @param client The client index. + * @param entity The entity index of the entity being touched. + */ +public Action:AntiStickSolidifyTimer(Handle:timer, any:client) +{ + // If client has left, then stop the timer. + if (!IsClientInGame(client)) + { + return Plugin_Stop; + } + + // If the client's collisions are already on, then stop. + if (AntiStickClientCollisionGroup(client) == ANTISTICK_COLLISIONS_ON) + { + return Plugin_Stop; + } + + // Loop through all client's and check if client is stuck in them. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // Don't compare the same clients. + if (client == x) + { + continue; + } + + // If the client is colliding with a client, then allow timer to continue. + if (AntiStickIsModelBoxColliding(client, x)) + { + return Plugin_Continue; + } + } + + // Change collisions back to normal. + AntiStickClientCollisionGroup(client, true, ANTISTICK_COLLISIONS_ON); + + return Plugin_Stop; +} + +/** + * Build the model box by finding all vertices. + * + * @param client The client index. + * @param boundaries Array with 'AntiStickBoxBounds' for indexes to return bounds into. + * @param width The width of the model box. + */ +stock AntiStickBuildModelBox(client, Float:boundaries[AntiStickBoxBound][3], Float:width) +{ + new Float:clientloc[3]; + new Float:twistang[3]; + new Float:cornerang[3]; + new Float:sideloc[3]; + new Float:finalloc[4][3]; + + // Get needed vector info. + GetClientAbsOrigin(client, clientloc); + + // Set the pitch to 0. + twistang[1] = 90.0; + cornerang[1] = 0.0; + + for (new x = 0; x < 4; x++) + { + // Jump to point on player's left side. + AntiStickJumpToPoint(clientloc, twistang, width / 2, sideloc); + + // From this point, jump to the corner, which would be half the width from the middle of a side. + AntiStickJumpToPoint(sideloc, cornerang, width / 2, finalloc[x]); + + // Twist 90 degrees to find next side/corner. + twistang[1] += 90.0; + cornerang[1] += 90.0; + + // Fix angles. + if (twistang[1] > 180.0) + { + twistang[1] -= 360.0; + } + + if (cornerang[1] > 180.0) + { + cornerang[1] -= 360.0; + } + } + + // Copy all horizontal model box data to array. + boundaries[BoxBound_FUR][0] = finalloc[3][0]; + boundaries[BoxBound_FUR][1] = finalloc[3][1]; + boundaries[BoxBound_FUL][0] = finalloc[0][0]; + boundaries[BoxBound_FUL][1] = finalloc[0][1]; + boundaries[BoxBound_FDR][0] = finalloc[3][0]; + boundaries[BoxBound_FDR][1] = finalloc[3][1]; + boundaries[BoxBound_FDL][0] = finalloc[0][0]; + boundaries[BoxBound_FDL][1] = finalloc[0][1]; + boundaries[BoxBound_BUR][0] = finalloc[2][0]; + boundaries[BoxBound_BUR][1] = finalloc[2][1]; + boundaries[BoxBound_BUL][0] = finalloc[1][0]; + boundaries[BoxBound_BUL][1] = finalloc[1][1]; + boundaries[BoxBound_BDR][0] = finalloc[2][0]; + boundaries[BoxBound_BDR][1] = finalloc[2][1]; + boundaries[BoxBound_BDL][0] = finalloc[1][0]; + boundaries[BoxBound_BDL][1] = finalloc[1][1]; + + // Set Z bounds. + new Float:eyeloc[3]; + GetClientEyePosition(client, eyeloc); + + boundaries[BoxBound_FUR][2] = eyeloc[2]; + boundaries[BoxBound_FUL][2] = eyeloc[2]; + boundaries[BoxBound_FDR][2] = clientloc[2] + 15.0; + boundaries[BoxBound_FDL][2] = clientloc[2] + 15.0; + boundaries[BoxBound_BUR][2] = eyeloc[2]; + boundaries[BoxBound_BUL][2] = eyeloc[2]; + boundaries[BoxBound_BDR][2] = clientloc[2] + 15.0; + boundaries[BoxBound_BDL][2] = clientloc[2] + 15.0; +} + +/** + * Jumps from a point to another based off angle and distance. + * + * @param vec Point to jump from. + * @param ang Angle to base jump off of. + * @param distance Distance to jump + * @param result Resultant point. + */ +stock AntiStickJumpToPoint(const Float:vec[3], const Float:ang[3], Float:distance, Float:result[3]) +{ + new Float:viewvec[3]; + + // Turn client angle, into a vector. + GetAngleVectors(ang, viewvec, NULL_VECTOR, NULL_VECTOR); + + // Normalize vector. + NormalizeVector(viewvec, viewvec); + + // Scale to the given distance. + ScaleVector(viewvec, distance); + + // Add the vectors together. + AddVectors(vec, viewvec, result); +} + +/** + * Get the max/min value of a 3D box on any axis. + * + * @param axis The axis to check. + * @param boundaries The boundaries to check. + * @param min Return the min value instead. + */ +stock Float:AntiStickGetBoxMaxBoundary(axis, Float:boundaries[AntiStickBoxBound][3], bool:min = false) +{ + // Create 'outlier' with initial value of first boundary. + new Float:outlier = boundaries[0][axis]; + + // x = Boundary index. (Start at 1 because we initialized 'outlier' with the 0 index's value) + new size = sizeof(boundaries); + for (new x = 1; x < size; x++) + { + if (!min && boundaries[x][axis] > outlier) + { + outlier = boundaries[x][axis]; + } + else if (min && boundaries[x][axis] < outlier) + { + outlier = boundaries[x][axis]; + } + } + + // Return value. + return outlier; } /** * Checks if a player is currently stuck within another player. * - * @param client The client index. - * @return The client index of the other stuck player, -1 when - * player is not stuck. + * @param client1 The first client index. + * @param client2 The second client index. + * @return True if they are stuck together, false if not. */ -AntiStickIsStuck(client) +stock bool:AntiStickIsModelBoxColliding(client1, client2) { - new Float:clientloc[3]; - new Float:stuckloc[3]; + new Float:client1modelbox[AntiStickBoxBound][3]; + new Float:client2modelbox[AntiStickBoxBound][3]; - GetClientAbsOrigin(client, clientloc); + // Get model hull widths. + new Float:hull_width1 = AntiStickGetModelHullWidth(client1); + new Float:hull_width2 = AntiStickGetModelHullWidth(client2); - // x = client index. - for (new x = 1; x <= MaxClients; x++) + // Build model boxes for each client. + AntiStickBuildModelBox(client1, client1modelbox, hull_width1); + AntiStickBuildModelBox(client2, client2modelbox, hull_width2); + + // Compare x values. + new Float:max1x = AntiStickGetBoxMaxBoundary(0, client1modelbox); + new Float:max2x = AntiStickGetBoxMaxBoundary(0, client2modelbox); + new Float:min1x = AntiStickGetBoxMaxBoundary(0, client1modelbox, true); + new Float:min2x = AntiStickGetBoxMaxBoundary(0, client2modelbox, true); + + if (max1x < min2x || min1x > max2x) { - // Validate player is in-game, alive, and isn't the player being checked. ('client') - if (!IsClientInGame(x) || !IsPlayerAlive(x) || x == client) - { - continue; - } - - GetClientAbsOrigin(x, stuckloc); - - // x-y plane distance formula: sqrt((x2-x1)^2 + (y2-y1)^2) - new Float:xydistance = SquareRoot(Pow(stuckloc[0] - clientloc[0], 2.0) + Pow(stuckloc[1] - clientloc[1], 2.0)); - if (xydistance < ANTISTICK_PLAYER_HULL_XY_OFFSET) - { - if (clientloc[2] <= stuckloc[2]) - { - new Float:eyeloc[3]; - GetClientEyePosition(client, eyeloc); - - // Get the distance between the eyes and feet and subtract the stack "view crush." - new Float:eyedistance = FloatAbs(eyeloc[2] - clientloc[2]) - ANTISTICK_PLAYER_HULL_STACK_OFFSET; - new Float:zdistance = FloatAbs(stuckloc[2] - clientloc[2]); - - if (zdistance <= eyedistance + ANTISTICK_PLAYER_HULL_Z_OFFSET) - { - return x; - } - } - } + return false; } - return -1; -} - -/** - * Timer callback, automatically unsticks players that are stuck together. - */ -public Action:AntiStickTimer(Handle:timer) -{ - // x = client index - for (new x = 1; x <= MaxClients; x++) + // Compare y values. + new Float:max1y = AntiStickGetBoxMaxBoundary(1, client1modelbox); + new Float:max2y = AntiStickGetBoxMaxBoundary(1, client2modelbox); + new Float:min1y = AntiStickGetBoxMaxBoundary(1, client1modelbox, true); + new Float:min2y = AntiStickGetBoxMaxBoundary(1, client2modelbox, true); + + if (max1y < min2y || min1y > max2y) { - // Validate player is in-game and alive. - if (!IsClientInGame(x) || !IsPlayerAlive(x)) - { - continue; - } - - // Stop if the player isn't stuck. - new stuckindex = AntiStickIsStuck(x); - if (stuckindex == -1) - { - continue; - } - - if (AntiStickClientCollisionGroup(x, false) == ANTISTICK_COLLISIONS_ON) - { - AntiStickClientCollisionGroup(x, true, ANTISTICK_COLLISIONS_OFF); - CreateTimer(0.5, AntiStickSolidify, x, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); - } - - if (AntiStickClientCollisionGroup(stuckindex, false) == ANTISTICK_COLLISIONS_ON) - { - AntiStickClientCollisionGroup(stuckindex, true, ANTISTICK_COLLISIONS_OFF); - CreateTimer(0.5, AntiStickSolidify, stuckindex, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); - } - } -} - -/** - * Repeated timer function. - * Re-solidifies a player being unstuck. - * - * @param timer The timer handle. - * @param client The client index. - */ -public Action:AntiStickSolidify(Handle:timer, any:client) -{ - // Validate player is in-game, alive, and is being unstuck. - if (!IsClientInGame(client) || !IsPlayerAlive(client) || AntiStickClientCollisionGroup(client, false) == ANTISTICK_COLLISIONS_ON) - { - return Plugin_Stop; + return false; } - // Stop if the player is still stuck. - if (AntiStickIsStuck(client) > -1) + // Compare z values. + new Float:max1z = AntiStickGetBoxMaxBoundary(2, client1modelbox); + new Float:max2z = AntiStickGetBoxMaxBoundary(2, client2modelbox); + new Float:min1z = AntiStickGetBoxMaxBoundary(2, client1modelbox, true); + new Float:min2z = AntiStickGetBoxMaxBoundary(2, client2modelbox, true); + + if (max1z < min2z || min1z > max2z) { - return Plugin_Continue; + return false; } - AntiStickClientCollisionGroup(client, true, ANTISTICK_COLLISIONS_ON); - - return Plugin_Stop; + // They are intersecting. + return true; } /** @@ -214,14 +537,110 @@ public Action:AntiStickSolidify(Handle:timer, any:client) * @param collisiongroup Collision group flag. * @return The collision group on the client, -1 if applying collision group. */ -AntiStickClientCollisionGroup(client, bool:apply = true, collisiongroup = 0) +AntiStickClientCollisionGroup(client, bool:apply = false, collisiongroup = 0) { if (apply) { - SetEntData(client, g_iToolsCollisionGroup, collisiongroup, 1, true); + SetEntProp(client, Prop_Data, "m_CollisionGroup", collisiongroup); return -1; } - return GetEntData(client, g_iToolsCollisionGroup, 1); + return GetEntProp(client, Prop_Data, "m_CollisionGroup"); } + +/** + * Command callback (zr_antistick_list_models) + * Lists all player's models and model hull data. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:AntiStickListModelsCommand(client, argc) +{ + // Tell client we are listing model data. + TranslationPrintToConsole(client, "AntiStick command list models list"); + + decl String:clientname[MAX_NAME_LENGTH]; + decl String:modelname[PLATFORM_MAX_PATH]; + new Float:hull_width; + + // x = Client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // Get all needed data. + GetClientName(x, clientname, sizeof(clientname)); + GetClientModel(x, modelname, sizeof(modelname)); + hull_width = AntiStickGetModelHullWidth(x); + + TranslationPrintToConsole(client, "AntiStick command list models name", clientname, modelname, hull_width); + } + + return Plugin_Handled; +} + +/** + * Command callback (zr_antistick_set_width) + * Set the hull width on any model. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:AntiStickSetWidthCommand(client, argc) +{ + // If not enough arguments given, then stop. + if (argc < 2) + { + TranslationReplyToCommand(client, "AntiStick command set width syntax"); + return Plugin_Handled; + } + + // Get target model. + decl String:model[PLATFORM_MAX_PATH]; + GetCmdArg(1, model, sizeof(model)); + + // If model doesn't exist, then stop. + if (!FileExists(model)) + { + new target = FindTarget(client, model); + if (target <= 0) + { + TranslationReplyToCommand(client, "AntiStick command set width invalid model", model); + return Plugin_Handled; + } + else + { + // Get the target's model. + GetClientModel(target, model, sizeof(model)); + } + } + + // Get the given hull width.. + decl String:strHullwidth[PLATFORM_MAX_PATH]; + GetCmdArg(2, strHullwidth, sizeof(strHullwidth)); + + new Float:hull_width = StringToFloat(strHullwidth); + if (hull_width <= 0.0) + { + TranslationReplyToCommand(client, "AntiStick command set width invalid width", hull_width); + return Plugin_Handled; + } + + // Set hull width. + AntiStickSetModelHullWidth(0, model, hull_width); + + // Tell client it was successful. + TranslationReplyToCommand(client, "AntiStick command set width successful", model, hull_width); + + // Save data. + AntiStickSaveData(); + + return Plugin_Handled; +} + \ No newline at end of file diff --git a/src/zr/commands.inc b/src/zr/commands.inc index 4dcb552..4635133 100644 --- a/src/zr/commands.inc +++ b/src/zr/commands.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: commands.inc * Type: Core @@ -39,6 +39,7 @@ CommandsInit() InfectOnCommandsCreate(); MenuOnCommandsCreate(); ZAdminOnCommandsCreate(); + AntiStickOnCommandsCreate(); ZCookiesOnCommandsCreate(); ZSpawnOnCommandsCreate(); ZTeleOnCommandsCreate(); @@ -51,200 +52,3 @@ CommandsInit() ClassOnCommandsHook(); DamageOnCommandsHook(); } - -/*CreateCommands() -{ - RegAdminCmd("zr_infect", Command_Infect, ADMFLAG_GENERIC, "Infects the specified player"); - RegAdminCmd("zr_spawn", Command_Respawn, ADMFLAG_GENERIC, "Respawns the specified player following auto-respawning rules"); - - - //RegAdminCmd("zr_set_class_knockback", Command_SetClassKnockback, ADMFLAG_GENERIC, "Sets the knockback to the specified class. Usage: zr_set_class_knockback "); - //RegAdminCmd("zr_get_class_knockback", Command_GetClassKnockback, ADMFLAG_GENERIC, "Gets the knockback to the specified class. Usage: zr_get_class_knockback "); - - RegAdminCmd("zr_admin", Command_AdminMenu, ADMFLAG_GENERIC, "Displays the admin menu for Zombie: Reloaded."); - //RegAdminCmd("zr_knockback_m", Command_KnockbackMMenu, ADMFLAG_GENERIC, "Displays the knockback multiplier menu."); - - RegAdminCmd("zr_anticamp_create_volume", Command_AnticampCreateVolume, ADMFLAG_GENERIC, "Creates a rectangular hurt volume between two points. Usage: ht_create_volume "); - RegAdminCmd("zr_anticamp_remove_volume", Command_AnticampRemoveVolume, ADMFLAG_GENERIC, "Removes a volume. Use zr_anticamp_list to list volumes. Usage: zr_anticamp_remove_volume "); - RegAdminCmd("zr_anticamp_list", Command_AnticampList, ADMFLAG_GENERIC, "List current volumes."); - - RegConsoleCmd("zr_log_flags", Command_LogFlags, "List available logging flags."); -}*/ - -/*public Action:Command_Infect(client, argc) -{ - new bool:enabled = GetConVarBool(g_hCvarsList[CVAR_ENABLE]); - if (argc < 1 || !enabled) - { - return Plugin_Handled; - } - - decl String:arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - - decl String:target_name_list[MAX_TARGET_LENGTH]; - new targets[MAXPLAYERS]; - new bool:tn_is_ml; - - new tcount = ProcessTargetString(arg1, client, targets, MAXPLAYERS, COMMAND_FILTER_ALIVE, target_name_list, sizeof(target_name_list), tn_is_ml); - if (tcount <= 0) - { - ReplyToTargetError(client, tcount); - return Plugin_Handled; - } - - decl String:target_name[64]; - decl String:client_name[64]; - - if (client > 0) - { - GetClientName(client, client_name, sizeof(client_name)); - } - else - { - client_name = "Console\0"; - } - - for (new x = 0; x < tcount; x++) - { - InfectHumanToZombie(targets[x]); - if (LogCheckFlag(LOG_GAME_EVENTS, LOG_MODULE_COMMANDS)) - { - GetClientName(targets[x], target_name, sizeof(target_name)); - LogMessageFormatted(client, "admin commands", "infect", "\"%s\" infected \"%s\".", true, client_name, target_name); - } - } - - return Plugin_Handled; -} - -public Action:Command_Respawn(client, argc) -{ - new bool:enabled = GetConVarBool(g_hCvarsList[CVAR_ENABLE]); - if (argc < 1 || !enabled) - { - return Plugin_Handled; - } - - decl String:arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - - decl String:target_name_list[MAX_TARGET_LENGTH]; - new targets[MAXPLAYERS]; - new bool:tn_is_ml; - - new tcount = ProcessTargetString(arg1, client, targets, MAXPLAYERS, COMMAND_FILTER_DEAD, target_name_list, sizeof(target_name_list), tn_is_ml); - if (tcount <= 0) - { - ReplyToTargetError(client, tcount); - return Plugin_Handled; - } - - decl String:client_name[64]; - decl String:target_name[64]; - - if (client > 0) - { - GetClientName(client, client_name, sizeof(client_name)); - } - else - { - client_name = "Console\0"; - } - - new team; - for (new x = 0; x < tcount; x++) - { - team = GetClientTeam(targets[x]); - if (team == CS_TEAM_T || team == CS_TEAM_CT) - { - if (LogCheckFlag(LOG_GAME_EVENTS, LOG_MODULE_COMMANDS)) - { - GetClientName(targets[x], target_name, sizeof(target_name)); - LogMessageFormatted(targets[x], "admin commands", "spawn", "\"%s\" spawned player \"%s\".", true, client_name, target_name); - } - - RespawnSpawnClient(targets[x]); - } - } - - return Plugin_Handled; -}*/ - -/*public Action:Command_AdminMenu(client, argc) -{ - if (ZRIsClientValid(client)) - { - ZRAdminMenu(client); - } - else - { - // BAD! - // ReplyToCommand(client, "This menu cannot be used from the console."); - } - return Plugin_Handled; -} - -public Action:Command_KnockbackMMenu(client, argc) -{ - if (ZRIsClientValid(client)) - { - // Disabled, under construction. - // ZRKnockbackMMenu(client); - } - else - { - // Tsk tsk no translation? :P - //ReplyToCommand(client, "This menu cannot be used from the console."); - } - return Plugin_Handled; -} - -public Action:Command_TeleMenu(client, argc) -{ - if (ZRIsClientValid(client)) - { - ZRZTeleMenu(client); - } - else - { - // BAD! - ReplyToCommand(client, "This menu cannot be used from the console."); - } - return Plugin_Handled; -} - -public Action:Command_LogFlags(client, argc) -{ - decl String:message[2048]; - message[0] = 0; - - StrCat(message, sizeof(message), "LOG_CORE_EVENTS (1) - Log core events like executing files, error messages, etc.\n"); - StrCat(message, sizeof(message), "LOG_GAME_EVENTS (2) - Log game events like admin commands, suicide prevention and anticamp kills.\n"); - StrCat(message, sizeof(message), "LOG_PLAYER_COMMANDS (4) - Log commands made by the player.\n"); - StrCat(message, sizeof(message), "LOG_DEBUG (8) - Enable debug messages (if they exist).\n"); - StrCat(message, sizeof(message), "LOG_DEBUG_DETAIL (16) - Detailed debug messages. May cause spam.\n"); - StrCat(message, sizeof(message), "LOG_DEBUG_MAX_DETAIL (32) - Low level detailed debug messages. Causes spam! Only enable right before and after testing.\n"); - StrCat(message, sizeof(message), "LOG_LOG_TO_ADMINS (64) - Display log messages to admin chat.\n"); - StrCat(message, sizeof(message), "LOG_LOG_TO_CLIENT (128) - Display log messages to the client that executed the event/command.\n"); - StrCat(message, sizeof(message), "LOG_IGNORE_CONSOLE (256) - Don't log messages from client 0 (console).\n"); - StrCat(message, sizeof(message), "LOG_MODULES_ENABLED (512) - Enable detailed log control for developers. Module logs overrides previous flags.\n"); - StrCat(message, sizeof(message), "LOG_MODULE_ZOMBIE (1024) - zombie.inc"); - - ReplyToCommand(client, message); - message[0] = 0; - - StrCat(message, sizeof(message), "LOG_MODULE_AMBIENTSOUNDS (2048) - ambientsounds.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_OVERLAYS (4096) - overlays.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_SAYTRIGGERS (8192) - sayhooks.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_TELEPORT (16384) - teleport.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_CLASSES (32768) - classes.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_WEAPONRESTICT (65536) - weaponrestrict.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_COMMANDS (131072) - commands.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_ANTICAMP (262144) - anticamp.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_DAMAGE (524288) - damage.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_OFFSETS (524288) - offsets.inc"); - - ReplyToCommand(client, message); - return Plugin_Handled; -}*/ diff --git a/src/zr/config.inc b/src/zr/config.inc index ead5501..82d2cb8 100644 --- a/src/zr/config.inc +++ b/src/zr/config.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: config.inc * Type: Core @@ -254,7 +254,7 @@ ConfigOnModulesLoaded() ServerCommand("exec %s", mapconfig); // Log action. - LogEvent(false, LogType_Normal, LOG_CORE_EVENTS, LogModule_Config, "Executed post map config file: %s", path); + LogEvent(false, LogType_Normal, LOG_CORE_EVENTS, LogModule_Config, "Post Map Configs", "Executed post map config file: %s", path); } /** @@ -422,9 +422,10 @@ stock ConfigGetConfigAlias(ConfigFile:config, String:alias[], maxlen) * * @param config The config file to load. * @param arrayConfig Handle of the main array containing file data. + * @param blocksize The max length of the contained strings. * @return True if file was loaded successfuly, false otherwise. */ -stock bool:ConfigLoadConfig(ConfigFile:config, &Handle:arrayConfig) +stock bool:ConfigLoadConfig(ConfigFile:config, &Handle:arrayConfig, blocksize = CONFIG_MAX_LENGTH) { // Get config's structure. new ConfigStructure:structure = ConfigGetConfigStructure(config); @@ -441,7 +442,7 @@ stock bool:ConfigLoadConfig(ConfigFile:config, &Handle:arrayConfig) if (arrayConfig == INVALID_HANDLE) { // Create array in handle. - arrayConfig = CreateArray(CONFIG_MAX_LENGTH); + arrayConfig = CreateArray(blocksize); } switch(structure) @@ -463,17 +464,8 @@ stock bool:ConfigLoadConfig(ConfigFile:config, &Handle:arrayConfig) decl String:line[PLATFORM_MAX_PATH]; - while(!IsEndOfFile(hFile)) + while(ReadFileLine(hFile, line, sizeof(line))) { - // 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) { @@ -518,7 +510,7 @@ stock bool:ConfigLoadConfig(ConfigFile:config, &Handle:arrayConfig) do { // Create new array to store information for config entry. - new Handle:arrayConfigEntry = CreateArray(CONFIG_MAX_LENGTH); + new Handle:arrayConfigEntry = CreateArray(blocksize); // Push the key name into the config entry's array. decl String:keyname[CONFIG_MAX_LENGTH]; @@ -884,15 +876,15 @@ public Action:ConfigReloadAllCommand(client, argc) } /** - * Converts string of "yes" or "no" to a boolean value. + * Converts string of "yes/on" or "no/off" to a boolean value. * - * @param option "yes" or "no" string to be converted. + * @param option "yes/on" or "no/off" string to be converted. * @return True if string is "yes", false otherwise. */ stock bool:ConfigSettingToBool(const String:option[]) { // If option is equal to "yes," then return true. - if (StrEqual(option, "yes", false)) + if (StrEqual(option, "yes", false) || StrEqual(option, "on", false)) { return true; } @@ -904,8 +896,8 @@ stock bool:ConfigSettingToBool(const String:option[]) /** * Converts boolean value to "yes" or "no". * - * @param bOption True/false value to be converted to "yes"/"no", respectively. - * @param option Destination string buffer to store "yes" or "no" in. + * @param bOption True/false value to be converted to "yes/on"/"no/off", respectively. + * @param option Destination string buffer to store "yes/on" or "no/off" in. * @param maxlen Length of destination string buffer (wont't be more than 4). * @param yesno When true, returns "yes/no", false returns "on/off." */ diff --git a/src/zr/cookies.inc b/src/zr/cookies.inc index 4e44c14..8c3c316 100644 --- a/src/zr/cookies.inc +++ b/src/zr/cookies.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: cookies.inc * Type: Module diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index 4efcc38..3ef22a3 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: cvars.inc * Type: Core @@ -73,6 +73,7 @@ enum CvarsList Handle:CVAR_DAMAGE_BLOCK_FF, Handle:CVAR_DAMAGE_BLOCK_BLAST, Handle:CVAR_DAMAGE_SUICIDE_ZOMBIE, + Handle:CVAR_DAMAGE_SUICIDE_MZOMBIE, Handle:CVAR_DAMAGE_SUICIDE_HUMAN, Handle:CVAR_DAMAGE_SUICIDE_CMDS, Handle:CVAR_SAYHOOKS_QUIET, @@ -125,7 +126,8 @@ enum CvarsList Handle:CVAR_AMBIENTSOUNDS_LENGTH, Handle:CVAR_AMBIENTSOUNDS_VOLUME, Handle:CVAR_ANTISTICK, - Handle:CVAR_ANTISTICK_INTERVAL, + Handle:CVAR_ANTISTICK_DEFAULT_WIDTH, + Handle:CVAR_ANTISTICK_FILE_PATH, Handle:CVAR_SPAWNPROTECT, Handle:CVAR_SPAWNPROTECT_TIME, Handle:CVAR_SPAWNPROTECT_SPEED, @@ -234,7 +236,7 @@ CvarsCreate() g_hCvarsList[CVAR_CLASSES_SPAWN] = CreateConVar("zr_classes_spawn", "0", "Re-display class selection menu every spawn."); g_hCvarsList[CVAR_CLASSES_RANDOM] = CreateConVar("zr_classes_random", "0", "Player is assigned a random class every spawn. [Override: zr_classes_spawn and zr_classes_default_*]"); g_hCvarsList[CVAR_CLASSES_DEFAULT_ZOMBIE] = CreateConVar("zr_classes_default_zombie", "random", "Zombie class assigned to players on connect. [\"random\" = Random zombie class | \"\" = Class config default]"); - g_hCvarsList[CVAR_CLASSES_DEFAULT_M_ZOMB] = CreateConVar("zr_classes_default_mother_zombie", "random", "Zombie class assigned to mother zombies. [\"motherzombies\" = Random mother zombie class | \"random\" = Random regular zombie class | \"disabled\" = Don't change class on mother zombies]"); + g_hCvarsList[CVAR_CLASSES_DEFAULT_M_ZOMB] = CreateConVar("zr_classes_default_mother_zombie", "motherzombies","Zombie class assigned to mother zombies. [\"motherzombies\" = Random mother zombie class | \"random\" = Random regular zombie class | \"disabled\" = Don't change class on mother zombies]"); g_hCvarsList[CVAR_CLASSES_DEFAULT_HUMAN] = CreateConVar("zr_classes_default_human", "random", "Human class assigned to players on connect. [\"random\" = Random human class | \"\" = Class config default]"); g_hCvarsList[CVAR_CLASSES_DEFAULT_ADMIN] = CreateConVar("zr_classes_default_admin", "random", "Admin class assigned to admins on connect. [\"random\" = Random admin class | \"\" = Class config default]"); @@ -307,8 +309,9 @@ CvarsCreate() g_hCvarsList[CVAR_DAMAGE_BLOCK_BLAST] = CreateConVar("zr_damage_block_blast", "1", "Block blast damage inflicted on self or teammates."); // Suicide Intercept - g_hCvarsList[CVAR_DAMAGE_SUICIDE_ZOMBIE] = CreateConVar("zr_damage_suicide_zombie", "1", "Intercept suicide commands attempted by zombies."); - g_hCvarsList[CVAR_DAMAGE_SUICIDE_HUMAN] = CreateConVar("zr_damage_suicide_human", "1", "Intercept suicide commands attempted by humans."); + g_hCvarsList[CVAR_DAMAGE_SUICIDE_ZOMBIE] = CreateConVar("zr_damage_suicide_zombie", "0", "Intercept suicide commands attempted by zombies."); + g_hCvarsList[CVAR_DAMAGE_SUICIDE_MZOMBIE] = CreateConVar("zr_damage_suicide_mzombie", "1", "Intercept suicide commands attempted by mother zombies."); + g_hCvarsList[CVAR_DAMAGE_SUICIDE_HUMAN] = CreateConVar("zr_damage_suicide_human", "0", "Intercept suicide commands attempted by humans."); g_hCvarsList[CVAR_DAMAGE_SUICIDE_CMDS] = CreateConVar("zr_damage_suicide_cmds", "kill, spectate, jointeam", "List of client commands to intercept as suicide attempts. [Delimiter: \", \"]"); @@ -385,8 +388,9 @@ CvarsCreate() // =========================== // Anti-Stick (module) // =========================== - g_hCvarsList[CVAR_ANTISTICK] = CreateConVar("zr_antistick", "1", "Automatically unstick players when stuck within each others' collision hull."); - g_hCvarsList[CVAR_ANTISTICK_INTERVAL] = CreateConVar("zr_antistick_interval", "0.5", "Time between each check for stuck players. [Dependency: zr_antistick]"); + g_hCvarsList[CVAR_ANTISTICK] = CreateConVar("zr_antistick", "1", "Automatically unstick players when stuck within each others' collision hull."); + g_hCvarsList[CVAR_ANTISTICK_DEFAULT_WIDTH] = CreateConVar("zr_antistick_default_width", "32.0", "The default width of player models, don't touch if you don't know what you're doing. [Dependency: zr_antistick]"); + g_hCvarsList[CVAR_ANTISTICK_FILE_PATH] = CreateConVar("zr_antistick_file_path", "data/antistick.dat", "File to store antistick model hull data. [Dependency: zr_antistick]"); // =========================== // Spawn Protect (module) diff --git a/src/zr/damage.inc b/src/zr/damage.inc index 0c5e650..b261986 100644 --- a/src/zr/damage.inc +++ b/src/zr/damage.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: damage.inc * Type: Core @@ -48,6 +48,11 @@ new g_iDamageTraceAttackHookID[MAXPLAYERS + 1] = {-1, ...}; */ new g_iDamageOnTakeDamageHookID[MAXPLAYERS + 1] = {-1, ...}; +/** + * Array to keep track of normal/mother zombies. + */ +new bool:g_bDamageMotherZombie[MAXPLAYERS + 1]; + /** * Hook commands related to damage here. */ @@ -106,6 +111,18 @@ DamageOnClientDisconnect(client) } } +/** + * A client was infected. + * + * @param client The client index. + * @param motherinfect True if the zombie is mother, false if not. + */ +DamageOnClientInfected(client, bool:motherinfect) +{ + // Update if client is a mother zombie or not. + g_bDamageMotherZombie[client] = motherinfect; +} + /** * Hook: TraceAttack * Called right before the bullet enters a client. @@ -153,6 +170,13 @@ public ZRTools_Action:DamageTraceAttack(client, inflictor, attacker, Float:damag // Here we know that attacker and client are different teams. + // If client is a human, then allow damage. + if (InfectIsClientHuman(client)) + { + // Allow damage. + return ZRTools_Continue; + } + // If damage hitgroups cvar is disabled, then allow damage. new bool:damagehitgroups = GetConVarBool(g_hCvarsList[CVAR_DAMAGE_HITGROUPS]); if (!damagehitgroups) @@ -317,18 +341,29 @@ public Action:DamageSuicideIntercept(client, argc) return Plugin_Continue; } - // Get zombie flag on client. - new bool:clientzombie = InfectIsClientInfected(client); - // Get cvar values for suicide interception. new bool:suicidezombie = GetConVarBool(g_hCvarsList[CVAR_DAMAGE_SUICIDE_ZOMBIE]); + new bool:suicidezombiemother = GetConVarBool(g_hCvarsList[CVAR_DAMAGE_SUICIDE_MZOMBIE]); new bool:suicidehuman = GetConVarBool(g_hCvarsList[CVAR_DAMAGE_SUICIDE_HUMAN]); - // Determine whether to block suicide based off of the client's zombie flag and cvar values. - new bool:blocksuicide = clientzombie ? suicidezombie : suicidehuman; + // Check if client is a zombie. + if (InfectIsClientInfected(client)) + { + // If client is a normal zombie, and suicide intercept is disabled for zombies, then let command go. + if (!g_bDamageMotherZombie[client] && !suicidezombie) + { + return Plugin_Continue; + } + + // If client is a mother zombie, and suicide intercept is disabled for mother zombies, then let command go. + if (g_bDamageMotherZombie[client] && !suicidezombiemother) + { + return Plugin_Continue; + } + } - // If cvar for this team is disabled, then stop. - if (!blocksuicide) + // If client is a human, and suicide intercept is disabled for humans, then let command go. + if (InfectIsClientHuman(client) && !suicidehuman) { return Plugin_Continue; } diff --git a/src/zr/downloads.inc b/src/zr/downloads.inc index 8634c5d..91e80e4 100644 --- a/src/zr/downloads.inc +++ b/src/zr/downloads.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: downloads.inc * Type: Core @@ -53,7 +53,7 @@ DownloadsLoad() ConfigSetConfigPath(File_Downloads, pathdownloads); // Load config from file and create array structure. - new bool:success = ConfigLoadConfig(File_Downloads, arrayDownloads); + new bool:success = ConfigLoadConfig(File_Downloads, arrayDownloads, PLATFORM_MAX_PATH); // Unexpected error, stop plugin. if (!success) diff --git a/src/zr/event.inc b/src/zr/event.inc index b98c157..ed93272 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: event.inc * Type: Core @@ -87,7 +87,6 @@ public Action:EventRoundStart(Handle:event, const String:name[], bool:dontBroadc RoundEndOnRoundStart(); InfectOnRoundStart(); SEffectsOnRoundStart(); - AntiStickOnRoundStart(); ZSpawnOnRoundStart(); VolOnRoundStart(); @@ -138,6 +137,7 @@ public Action:EventRoundEnd(Handle:event, const String:name[], bool:dontBroadcas new reason = GetEventInt(event, "reason"); // Forward event to modules. + WeaponsOnRoundEnd(); RoundEndOnRoundEnd(reason); InfectOnRoundEnd(); SEffectsOnRoundEnd(); @@ -184,23 +184,13 @@ public Action:EventPlayerSpawn(Handle:event, const String:name[], bool:dontBroad AccountOnClientSpawn(index); // Some modules depend on this to finish first. ClassOnClientSpawn(index); WeaponsOnClientSpawn(index); + RoundStartOnClientSpawn(index); SEffectsOnClientSpawn(index); - SpawnProtectOnClientSpawn(index); RespawnOnClientSpawn(index); ZTeleOnClientSpawn(index); ZHPOnClientSpawn(index); VolOnPlayerSpawn(index); - // Get public chat trigger prefix. - decl String:publictrigger[4]; - SayHooksGetPublicChatTrigger(publictrigger, sizeof(publictrigger)); - - // If public chat trigger is disabled, then don't print message. - if (!StrEqual(publictrigger, "N/A", false)) - { - TranslationPrintToChat(index, "General zmenu reminder", publictrigger, SAYHOOKS_KEYWORD_ZMENU); - } - // Fire post player_spawn event. CreateTimer(0.0, EventPlayerSpawnPost, index); } diff --git a/src/zr/global.inc b/src/zr/global.inc index 5fe306c..031b685 100644 --- a/src/zr/global.inc +++ b/src/zr/global.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: global.inc * Type: Core diff --git a/src/zr/hitgroups.inc b/src/zr/hitgroups.inc index 37c5def..3d567f9 100644 --- a/src/zr/hitgroups.inc +++ b/src/zr/hitgroups.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: hitgroup.inc * Type: Core @@ -349,6 +349,154 @@ stock Float:HitgroupsGetKnockback(index) return Float:GetArrayCell(arrayHitgroup, _:HITGROUPS_DATA_KNOCKBACK); } +/** + * Sends list of hitgroups to client. + * + * @param client The client index. + * @return True if sent successfully, false if not. + */ +bool:HitgroupsMenuHitgroups(client) +{ + // If hitgroups is disabled, then stop. + new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]); + if (!hitgroups) + { + return false; + } + + // Create menu handle. + new Handle:menu_hitgroups = CreateMenu(HitgroupsMenuHitgroupsHandle); + + // Set client as translation target. + SetGlobalTransTarget(client); + + SetMenuTitle(menu_hitgroups, "%t\n ", "Hitgroups menu hitgroups title"); + + decl String:enableall[32]; + decl String:headshotsonly[32]; + + // Format menu options. + Format(enableall, sizeof(enableall), "%t", "Hitgroups menu hitgroups enable all"); + Format(headshotsonly, sizeof(headshotsonly), "%t\n ", "Hitgroups menu hitgroups headshots only"); + + // Add options to menu. + AddMenuItem(menu_hitgroups, "Enable All", enableall); + AddMenuItem(menu_hitgroups, "Headshots Only", headshotsonly); + + decl String:hitgroupoption[MAX_NAME_LENGTH]; + decl String:hitgroupcandamage[MAX_NAME_LENGTH]; + decl String:hitgroupid[4]; + + // x = Hitgroup index. + new size = GetArraySize(arrayHitgroups); + for (new x = 0; x < size; x++) + { + // Get hitgroup name. + HitgroupsGetName(x, hitgroupoption, sizeof(hitgroupoption)); + IntToString(x, hitgroupid, sizeof(hitgroupid)); + + // Convert bool to "On/Off" + ConfigBoolToSetting(HitgroupsCanDamage(x), hitgroupcandamage, sizeof(hitgroupcandamage), false); + + // Format "on/off" to the option. + Format(hitgroupoption, sizeof(hitgroupoption), "%s: %s", hitgroupoption, hitgroupcandamage); + + // Add option to menu. + AddMenuItem(menu_hitgroups, hitgroupid, hitgroupoption); + } + + // Create a "Back" button to the main admin menu. + SetMenuExitBackButton(menu_hitgroups, true); + + // Send menu. + DisplayMenu(menu_hitgroups, client, MENU_TIME_FOREVER); + + return true; +} + +/** + * Called when client selects option in the infect clients menu, and handles it. + * @param menu_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). + */ +public HitgroupsMenuHitgroupsHandle(Handle:menu_hitgroups, MenuAction:action, client, slot) +{ + // Client selected an option. + if (action == MenuAction_Select) + { + switch(slot) + { + // Enable all hitgroups. + case 0: + { + // x = Hitgroup index. + new size = GetArraySize(arrayHitgroups); + for (new x = 0; x < size; x++) + { + // Enable hitgroup. + HitgroupsSetDamage(x, true); + } + + // Tell the server that all hitgroups have been enabled. + TranslationPrintToChatAll(true, false, "Hitgroups command enable all successful"); + } + // Headshots only. + case 1: + { + // x = Hitgroup index. + new size = GetArraySize(arrayHitgroups); + for (new x = 0; x < size; x++) + { + if (HitgroupsGetIndex(x) == HITGROUP_HEAD) + { + // Enable hitgroup. + HitgroupsSetDamage(x, true); + + continue; + } + + // Disable hitgroup. + HitgroupsSetDamage(x, false); + } + + // Tell the server that headshots only been enabled. + TranslationPrintToChatAll(true, false, "Hitgroups command headshots only successful"); + } + default: + { + // Get selected hitgroup index. + decl String:hitgroupid[4]; + GetMenuItem(menu_hitgroups, slot, hitgroupid, sizeof(hitgroupid)); + new hitgroup = StringToInt(hitgroupid); + + // Toggle value. + new bool:hitgroupcandamage = HitgroupsCanDamage(hitgroup); + HitgroupsSetDamage(hitgroup, !hitgroupcandamage); + } + } + + // Re-send menu. + HitgroupsMenuHitgroups(client); + } + // Client closed the menu. + if (action == MenuAction_Cancel) + { + // Client hit "Back" button. + if (slot == MenuCancel_ExitBack) + { + // Re-open admin menu. + ZAdminMenu(client); + } + } + // Client hit "Exit" button. + else if (action == MenuAction_End) + { + CloseHandle(menu_hitgroups); + } +} + /** * Command callback (zr_hitgroup) * Toggles or sets if a zombie's hitgroup can be damaged. @@ -358,6 +506,14 @@ stock Float:HitgroupsGetKnockback(index) */ public Action:HitgroupsCommand(client, argc) { + // If module is disabled, then stop. + new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]); + if (!hitgroups) + { + TranslationReplyToCommand(client, "Feature is disabled"); + return Plugin_Handled; + } + // If not enough arguments given, then stop. if (argc < 1) { @@ -436,17 +592,20 @@ public Action:HitgroupsCommand(client, argc) */ public Action:HitgroupsEnableAllCommand(client, argc) { - new hitgroup; + // If module is disabled, then stop. + new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]); + if (!hitgroups) + { + TranslationReplyToCommand(client, "Feature is disabled"); + return Plugin_Handled; + } // x = Hitgroup index. new size = GetArraySize(arrayHitgroups); for (new x = 0; x < size; x++) { - // Get CS:S hitgroup index. - hitgroup = HitgroupsGetIndex(x); - // Set that hitgroup index to true for damage. - HitgroupsSetDamage(hitgroup, true); + HitgroupsSetDamage(x, true); } // Tell the server that all hitgroups have been enabled. @@ -467,27 +626,30 @@ public Action:HitgroupsEnableAllCommand(client, argc) */ public Action:HitgroupsHeadshotsOnlyCommand(client, argc) { - new hitgroup; + // If module is disabled, then stop. + new bool:hitgroups = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]); + if (!hitgroups) + { + TranslationReplyToCommand(client, "Feature is disabled"); + return Plugin_Handled; + } // x = Hitgroup index. new size = GetArraySize(arrayHitgroups); for (new x = 0; x < size; x++) { - // Get CS:S hitgroup index. - hitgroup = HitgroupsGetIndex(x); - // If this hitgroup is the head, then enable it and stop. - if (hitgroup == HITGROUP_HEAD) + if (HitgroupsGetIndex(x) == HITGROUP_HEAD) { - HitgroupsSetDamage(hitgroup, true); + HitgroupsSetDamage(x, true); continue; } // Set that hitgroup index to true for damage. - HitgroupsSetDamage(hitgroup, false); + HitgroupsSetDamage(x, false); } - // Tell the server that all hitgroups have been enabled. + // Tell the server that headshots only been enabled. TranslationPrintToChatAll(true, false, "Hitgroups command headshots only successful"); // Log action to game events. diff --git a/src/zr/infect.inc b/src/zr/infect.inc index 9996e77..26c2a60 100644 --- a/src/zr/infect.inc +++ b/src/zr/infect.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: infect.inc * Type: Core @@ -556,47 +556,6 @@ InfectHumanToZombie(client, attacker = -1, bool:motherinfect = false, bool:respa // Mark player as zombie. bZombie[client] = true; - // Get a list of all client's weapon indexes. - new weapons[WeaponsSlot]; - WeaponsGetClientWeapons(client, weapons); - - // Check if weapons drop is enabled. - new bool:weaponsdrop = GetConVarBool(g_hCvarsList[CVAR_INFECT_WEAPONS_DROP]); - - // Loop through array slots and force drop. - // x = weapon slot. - for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) - { - // If weapon is invalid, then stop. - if (weapons[x] == -1) - { - continue; - } - - if (weaponsdrop) - { - // If this is the knife slot, then stop. - if (WeaponsSlot:x == Slot_Melee) - { - continue; - } - - // Force client to drop weapon. - WeaponsForceClientDrop(client, weapons[x]); - } - else - { - // Strip weapon. - RemovePlayerItem(client, weapons[x]); - } - } - - // If client has no knife, give them one. - if (GetPlayerWeaponSlot(client, _:Slot_Melee) == -1) - { - GivePlayerItem(client, "weapon_knife"); - } - // Check if consecutive infection protection is enabled. new bool:infectconsecutiveblock = GetConVarBool(g_hCvarsList[CVAR_INFECT_CONSECUTIVE_BLOCK]); @@ -669,9 +628,52 @@ InfectHumanToZombie(client, attacker = -1, bool:motherinfect = false, bool:respa // Forward event to modules. ClassOnClientInfected(client, motherinfect); RoundEndOnClientInfected(); + DamageOnClientInfected(client, motherinfect); SEffectsOnClientInfected(client); ZTeleOnClientInfected(client); ZHPOnClientInfected(client); + + // Get a list of all client's weapon indexes. + new weapons[WeaponsSlot]; + WeaponsGetClientWeapons(client, weapons); + + // Check if weapons drop is enabled. + new bool:weaponsdrop = GetConVarBool(g_hCvarsList[CVAR_INFECT_WEAPONS_DROP]); + + // This must be after the event forwarding because it fixes a problem caused by changing models in ClassOnClientInfected. + // Loop through array slots and force drop. + // x = weapon slot. + for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) + { + // If weapon is invalid, then stop. + if (weapons[x] == -1) + { + continue; + } + + if (weaponsdrop) + { + // If this is the knife slot, then stop. + if (WeaponsSlot:x == Slot_Melee) + { + // Strip knife. + RemovePlayerItem(client, weapons[x]); + + continue; + } + + // Force client to drop weapon. + WeaponsForceClientDrop(client, weapons[x]); + } + else + { + // Strip weapon. + RemovePlayerItem(client, weapons[x]); + } + } + + // Give zombie a new knife. (If you leave the old one there will be glitches with the knife positioning) + GivePlayerItem(client, "weapon_knife"); } /** @@ -701,6 +703,14 @@ InfectZombieToHuman(client, bool:respawn = false, bool:protect = false) RoundEndOnClientInfected(); ZTeleOnClientInfected(client); + // Give human a new knife. (If you leave the old one there will be glitches with the knife positioning) + new knife = GetPlayerWeaponSlot(client, _:Slot_Melee); + if (knife != -1) + { + RemovePlayerItem(client, knife); + GivePlayerItem(client, "weapon_knife"); + } + // Check if we should respawn the client. if (respawn) { @@ -806,7 +816,7 @@ InfectMenuClients(client) SetMenuTitle(menu_infect_clients, "%t\n ", "Infect menu clients title"); - decl String:clientoption[MAX_NAME_LENGTH]; + decl String:clientoption[64]; decl String:clientuserid[8]; // x = Client index. @@ -861,11 +871,8 @@ public InfectMenuClientsHandle(Handle:menu_infect_clients, MenuAction:action, cl // Client selected an option. if (action == MenuAction_Select) { - decl String:clientuserid[8]; - GetMenuItem(menu_infect_clients, slot, clientuserid, sizeof(clientuserid)); - - // Get the targetted client through their userid which was set into the menu slot's info param. - new target = GetClientOfUserId(StringToInt(clientuserid)); + // Get selected client index. + new target = MenuGetClientIndex(menu_infect_clients, slot); // If target has left the server, then stop. if (!target) @@ -899,7 +906,7 @@ public InfectMenuClientsHandle(Handle:menu_infect_clients, MenuAction:action, cl if (slot == MenuCancel_ExitBack) { // Re-open admin menu. - ZRAdminMenu(client); + ZAdminMenu(client); } } // Client hit "Exit" button. diff --git a/src/zr/jumpboost.inc b/src/zr/jumpboost.inc index a46d3e5..1db1d07 100644 --- a/src/zr/jumpboost.inc +++ b/src/zr/jumpboost.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: jumpboost.inc * Type: Module @@ -47,7 +47,7 @@ JumpBoostOnClientJumpPost(client) // Get client's current velocity. ToolsClientVelocity(client, vecVelocity, false); - // If they have exceeded the max jump speed, then stop. + // Only apply horizontal multiplier if it's not a bhop. if (!JumpBoostIsBHop(vecVelocity)) { // Apply horizontal multipliers to jump vector. diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index 0cf2edd..cca1652 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: knockback.inc * Type: Module @@ -78,7 +78,7 @@ KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_hea // Get attackers eye angles. new Float:attackerang[3]; - KnockbackGetClientEyeAngles(attacker, attackerang); + GetClientEyeAngles(attacker, attackerang); // Calculate knockback end-vector. TR_TraceRayFilter(attackerloc, attackerang, MASK_ALL, RayType_Infinite, KnockbackTRFilter); @@ -198,15 +198,4 @@ KnockbackFindExplodingGrenade(Float:heLoc[3]) // Didn't find the grenade. return -1; -} - -/** - * Get client's eye angles. - * - * @param client The client index. - * @param vecAngles The angle vector of the client's eyes. - */ -KnockbackGetClientEyeAngles(client, Float:vecAngles[3]) -{ - SDKCall(g_hToolsEyeAngles, client, vecAngles); -} +} \ No newline at end of file diff --git a/src/zr/log.h.inc b/src/zr/log.h.inc index c363d11..5588165 100644 --- a/src/zr/log.h.inc +++ b/src/zr/log.h.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: log.h.inc * Type: Core @@ -70,7 +70,7 @@ enum LogModules bool:LogModule_Invalid = 0, /** Used as return value when an error occoured.*/ bool:LogModule_Account, - bool:LogModule_Antistick, + bool:LogModule_AntiStick, bool:LogModule_Config, bool:LogModule_Cvars, bool:LogModule_Damage, @@ -84,7 +84,9 @@ enum LogModules bool:LogModule_Tools, bool:LogModule_Volfeatures, bool:LogModule_Weapons, - bool:LogModule_Weaponrestrict + bool:LogModule_Weaponrestrict, + bool:LogModule_ZSpawn, + bool:LogModule_ZTele, } /** diff --git a/src/zr/log.inc b/src/zr/log.inc index a473908..db4d748 100644 --- a/src/zr/log.inc +++ b/src/zr/log.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: log.inc * Type: Core @@ -59,7 +59,7 @@ LogGetModuleNameString(String:buffer[], maxlen, LogModules:module, bool:shortNam { return shortName ? strcopy(buffer, maxlen, "account") : strcopy(buffer, maxlen, "Account"); } - case LogModule_Antistick: + case LogModule_AntiStick: { return shortName ? strcopy(buffer, maxlen, "antistick") : strcopy(buffer, maxlen, "Anti-Stick"); } @@ -119,6 +119,14 @@ LogGetModuleNameString(String:buffer[], maxlen, LogModules:module, bool:shortNam { return shortName ? strcopy(buffer, maxlen, "weaponrestrict") : strcopy(buffer, maxlen, "Weapon Restrictions"); } + case LogModule_ZSpawn: + { + return shortName ? strcopy(buffer, maxlen, "zspawn") : strcopy(buffer, maxlen, "ZSpawn"); + } + case LogModule_ZTele: + { + return shortName ? strcopy(buffer, maxlen, "ztele") : strcopy(buffer, maxlen, "ZTele"); + } } // Module mismatch. @@ -140,7 +148,7 @@ LogModules:LogGetModule(const String:moduleName[]) } else if (StrEqual(moduleName, "antistick", false)) { - return LogModule_Antistick; + return LogModule_AntiStick; } else if (StrEqual(moduleName, "config", false)) { @@ -198,6 +206,14 @@ LogModules:LogGetModule(const String:moduleName[]) { return LogModule_Weaponrestrict; } + else if (StrEqual(moduleName, "zspawn", false)) + { + return LogModule_ZSpawn; + } + else if (StrEqual(moduleName, "ztele", false)) + { + return LogModule_ZTele; + } // No match. return LogModule_Invalid; diff --git a/src/zr/menu.inc b/src/zr/menu.inc index 2b17179..11fe0a0 100644 --- a/src/zr/menu.inc +++ b/src/zr/menu.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: menu.inc * Type: Core @@ -90,10 +90,10 @@ ZMenuMain(client) decl String:zmarket[256]; // Translate each line into client's language. - Format(zadmin, sizeof(zadmin), "%t", "Menu main zadmin", SAYHOOKS_KEYWORD_ZMENU); - Format(zclass, sizeof(zclass), "%t", "Menu main zclass", SAYHOOKS_KEYWORD_ZADMIN); + Format(zadmin, sizeof(zadmin), "%t", "Menu main zadmin", SAYHOOKS_KEYWORD_ZADMIN); + Format(zclass, sizeof(zclass), "%t", "Menu main zclass", SAYHOOKS_KEYWORD_ZCLASS); Format(zcookies, sizeof(zcookies), "%t", "Menu main zcookies", SAYHOOKS_KEYWORD_ZCOOKIES); - Format(zspawn, sizeof(zspawn), "%t", "Menu main zspawn", SAYHOOKS_KEYWORD_ZCLASS); + Format(zspawn, sizeof(zspawn), "%t", "Menu main zspawn", SAYHOOKS_KEYWORD_ZSPAWN); Format(ztele, sizeof(ztele), "%t", "Menu main ztele", SAYHOOKS_KEYWORD_ZTELE); Format(zhp, sizeof(zhp), "%t", "Menu main zhp", SAYHOOKS_KEYWORD_ZHP); Format(zmarket, sizeof(zmarket), "%t", "Menu main zmarket", SAYHOOKS_KEYWORD_ZMARKET); @@ -138,7 +138,7 @@ public ZMenuMainHandle(Handle:menu, MenuAction:action, client, slot) case 0: { // Copy return to resend variable. - resend = !ZRAdminMenu(client); + resend = !ZAdminMenu(client); } // Select ZClass. case 1: @@ -197,12 +197,78 @@ public ZMenuMainHandle(Handle:menu, MenuAction:action, client, slot) } } +/** + * Shows a list of all clients to a client, different handlers can be used for this, as well as title. + * + * @param client The client index. + * @param handler The menu handler. + * @param any Title is a translations phrase. + */ +stock MenuClientList(client, MenuHandler:handler, any:...) +{ + // Create menu handle. + new Handle:menu_clients = CreateMenu(handler); + + // Set client as translation target. + SetGlobalTransTarget(client); + + // Translate phrase. + decl String:translation[TRANSLATION_MAX_LENGTH_CHAT]; + VFormat(translation, sizeof(translation), "%t", 3); + + // Set menu title to the translated phrase. + SetMenuTitle(menu_clients, translation); + + decl String:clientoption[MAX_NAME_LENGTH]; + decl String:clientuserid[8]; + + // x = Client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // Get client info. + GetClientName(x, clientoption, sizeof(clientoption)); + IntToString(GetClientUserId(x), clientuserid, sizeof(clientuserid)); + + // Add option to menu. + AddMenuItem(menu_clients, clientuserid, clientoption); + } + + // Create a "Back" button to the main admin menu. + SetMenuExitBackButton(menu_clients, true); + + // Send menu. + DisplayMenu(menu_clients, client, MENU_TIME_FOREVER); +} + +/** + * Gets the client index of the selected client in the menu. + * + * @param menu The menu handle. + * @param slot The menu slot that was selected. + * @return The client index, 0 if the selected client is no longer in the server. + */ +stock MenuGetClientIndex(Handle:menu, slot) +{ + // Get menu slot's information. + decl String:clientuserid[8]; + GetMenuItem(menu, slot, clientuserid, sizeof(clientuserid)); + + // Return the targetted client through their userid which was set into the menu slot's info param. + return GetClientOfUserId(StringToInt(clientuserid)); +} + /** * Return itemdraw flag for SM menus. * * @param condition If this is true, item will be drawn normally. */ -MenuGetItemDraw(bool:condition) +stock MenuGetItemDraw(bool:condition) { return condition ? ITEMDRAW_DEFAULT : ITEMDRAW_DISABLED; } diff --git a/src/zr/models.inc b/src/zr/models.inc index f71c2ab..d0f2e46 100644 --- a/src/zr/models.inc +++ b/src/zr/models.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: models.inc * Type: Core @@ -63,7 +63,7 @@ ModelsLoad() ConfigSetConfigPath(File_Models, pathmodels); // Load config from file and create array structure. - new bool:success = ConfigLoadConfig(File_Models, arrayModels); + new bool:success = ConfigLoadConfig(File_Models, arrayModels, PLATFORM_MAX_PATH); // Unexpected error, stop plugin. if (!success) @@ -72,7 +72,8 @@ ModelsLoad() } new modelcount; - new modelvalidcount; + new modelpublicvalidcount; + new modelnonpublicvalidcount; new modelfilecount; decl String:modelbase[PLATFORM_MAX_PATH]; @@ -91,9 +92,9 @@ ModelsLoad() // x = model array index. for (new x = 0; x < models; x++) { - // Get base model path (rawline in models.txt) - GetArrayString(arrayModels, x, modelbase, sizeof(modelbase)); - + // Get base model path, excluding the public/non-public setting. + ModelReturnPath(x, modelbase, sizeof(modelbase)); + PrintToServer("PATH BASE [%s]", modelbase); // Explode path into pieces. (separated by "/") new strings = ExplodeString(modelbase, "/", baseexploded, MODELS_PATH_MAX_DEPTH, MODELS_PATH_DIR_MAX_LENGTH); @@ -147,10 +148,18 @@ ModelsLoad() modelfilecount++; } - // Increment modelvalidcount if model files are valid. + // Increment variable if model files are valid. if (modelfilecount) { - modelvalidcount++; + // Increment proper variable. + if (ModelIsPublic(x)) + { + modelpublicvalidcount++; + } + else + { + modelnonpublicvalidcount++; + } } else { @@ -169,12 +178,12 @@ ModelsLoad() } // Log model validation info. - LogEvent(false, LogType_Normal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Total: %d | Successful: %d | Unsuccessful: %d", modelcount, modelvalidcount, modelcount - modelvalidcount); + LogEvent(false, LogType_Normal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "Total: %d | Successful Public: %d | Successful Non-Public: %d | Unsuccessful: %d", modelcount, modelpublicvalidcount, modelnonpublicvalidcount, modelcount - (modelpublicvalidcount + modelnonpublicvalidcount)); // If none of the model paths are valid, then log and fail. - if (!modelvalidcount) + if (!modelpublicvalidcount) { - LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "No usable model paths in %s", pathmodels); + LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Models, "Config Validation", "No usable (public) model paths in %s", pathmodels); } // Set config data. @@ -191,3 +200,118 @@ public ModelsOnConfigReload(ConfigFile:config) // Reload models config. ModelsLoad(); } + +/** + * Checks if a model is public. + * + * @param modelindex The array index of the model to check. + * @return True if public, false if not. + */ +stock bool:ModelIsPublic(modelindex) +{ + // Get the entire model string to parse for what we need. + decl String:modelsetting[PLATFORM_MAX_PATH + 16]; + GetArrayString(arrayModels, modelindex, modelsetting, sizeof(modelsetting)); + + // We define this to use as little memory as possible, because the value won't be used. + decl String:modelpath[1]; + decl String:strpublic[32]; + + if (StrContains(modelsetting, ";") > -1) + { + // Get string index of where the public setting starts. + new strindex = SplitString(modelsetting, ";", modelpath, sizeof(modelpath)); + + // Copy setting to new string + strcopy(strpublic, sizeof(strpublic), modelsetting[strindex]); + + // Trim the whitespace. + TrimString(strpublic); + + // If public, return true, non-public returns false. + return StrEqual(strpublic, "public", false); + } + + // If nothing is specified, assume public. + return true; +} + +/** + * Returns the path of a given model index. + * + * @param modelindex The array index of the model. + * @param modelpath The output string of the model path. + * @param maxlen The maximum length of the output string. + */ +stock ModelReturnPath(modelindex, String:modelpath[], maxlen) +{ + // Get the entire model string to parse for what we need. + decl String:modelsetting[PLATFORM_MAX_PATH + 16]; + GetArrayString(arrayModels, modelindex, modelsetting, sizeof(modelsetting)); + + // Copy to path before split just in case the string has no ";" + strcopy(modelpath, maxlen, modelsetting); + if (StrContains(modelsetting, ";") > -1) + { + SplitString(modelsetting, ";", modelpath, maxlen); + } + + // Trim whitespace. + TrimString(modelpath); +} + +/** + * Get a random model index in arrayModels, allows you to specify a filter. + * + * @param modelpath The output string of the model path. + * @param maxlen The maximum length of the output string. + * @param all True to choose any of the models in the file, false to use 'publicmodels' param. + * @param publicmodels True to find a random public model, false to find non-public. + */ +stock ModelsGetRandomModelIndex(String:modelpath[], maxlen, bool:all = true, bool:publicmodels = true) +{ + new modelindex = -1; + + // Return any random model. + if (all) + { + // Get random model index and return the string in it. + modelindex = GetRandomInt(0, GetArraySize(arrayModels) - 1); + } + else + { + new Handle:modelsarray = CreateArray(PLATFORM_MAX_PATH); + decl String:modelsetting[PLATFORM_MAX_PATH]; + + // x = Array index. + new size = GetArraySize(arrayModels); + for (new x = 0; x < size; x++) + { + if (publicmodels == ModelIsPublic(x)) + { + // Transfer model to temp array. + GetArrayString(arrayModels, x, modelsetting, sizeof(modelsetting)); + PushArrayString(modelsarray, modelsetting); + } + } + + // y = Array index. + size = GetArraySize(modelsarray); + + // If there are no models then copy a blank string to the output. + if (size == 0) + { + strcopy(modelpath, maxlen, ""); + return; + } + + // Get random model index from the temp list, and return the string in it. + modelindex = GetRandomInt(0, GetArraySize(modelsarray) - 1); + + // Destroy the handle. + CloseHandle(modelsarray); + } + + // Get the path to the selected model. + ModelReturnPath(modelindex, modelpath, maxlen); +} \ No newline at end of file diff --git a/src/zr/napalm.inc b/src/zr/napalm.inc index a93a9c7..1cca75e 100644 --- a/src/zr/napalm.inc +++ b/src/zr/napalm.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: napalm.inc * Type: Module @@ -39,6 +39,12 @@ */ NapalmOnClientHurt(client, attacker, const String:weapon[]) { + // If there's no attacker, then stop. + if (!attacker) + { + return; + } + // If player isn't a zombie, then stop. if (!InfectIsClientInfected(client)) { @@ -107,8 +113,8 @@ NapalmOnWeaponFire(client, const String:weapon[]) return; } - // Wait .1 seconds. - CreateTimer(0.1, NapalmIgniteGrenade); + // Wait .15 seconds. + CreateTimer(0.15, NapalmIgniteGrenade); } /** diff --git a/src/zr/overlays.inc b/src/zr/overlays.inc index bbeaf21..db096f7 100644 --- a/src/zr/overlays.inc +++ b/src/zr/overlays.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: overlays.inc * Type: Core diff --git a/src/zr/playerclasses/apply.inc b/src/zr/playerclasses/apply.inc index 625da0e..45fd0bd 100644 --- a/src/zr/playerclasses/apply.inc +++ b/src/zr/playerclasses/apply.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: apply.inc * Type: Core @@ -93,8 +93,7 @@ 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(arrayModels) - 1); - GetArrayString(arrayModels, randmodel, modelpath, sizeof(modelpath)); + ModelsGetRandomModelIndex(modelpath, sizeof(modelpath), false, true); Format(modelpath, sizeof(modelpath), "%s.mdl", modelpath); } @@ -211,8 +210,8 @@ bool:ClassApplyNightVision(client, classindex, cachetype = ZR_CLASS_CACHE_PLAYER nvgs = ClassGetNvgs(classindex, cachetype); } - ToolsClientNightVision(client, nvgs); - ToolsClientNightVision(client, nvgs, false); + ToolsSetClientNightVision(client, nvgs); + ToolsSetClientNightVision(client, nvgs, false); return true; } diff --git a/src/zr/playerclasses/attributes.inc b/src/zr/playerclasses/attributes.inc index d7636f3..65b3e99 100644 --- a/src/zr/playerclasses/attributes.inc +++ b/src/zr/playerclasses/attributes.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: attributes.inc * Type: Core diff --git a/src/zr/playerclasses/classcommands.inc b/src/zr/playerclasses/classcommands.inc index d7354a4..ae6b859 100644 --- a/src/zr/playerclasses/classcommands.inc +++ b/src/zr/playerclasses/classcommands.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: classcommands.inc * Type: Core diff --git a/src/zr/playerclasses/classevents.inc b/src/zr/playerclasses/classevents.inc index 9c5f4d6..9dcbada 100644 --- a/src/zr/playerclasses/classevents.inc +++ b/src/zr/playerclasses/classevents.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: classevents.inc * Type: Core @@ -93,6 +93,12 @@ ClassOnClientSpawn(client) GetClientModel(client, originalmodel, sizeof(originalmodel)); strcopy(ClassOriginalPlayerModel[client], PLATFORM_MAX_PATH, originalmodel); + // Exclude special class flags like mother zombies and admin classes. + new denyflags = ZR_CLASS_SPECIALFLAGS; + + // Allow admin classes if admin. + denyflags -= ZRIsClientAdmin(client) ? ZR_CLASS_FLAG_ADMIN_ONLY : 0; + // Get random class setting. new bool:randomclass = GetConVarBool(g_hCvarsList[CVAR_CLASSES_RANDOM]); @@ -101,15 +107,15 @@ ClassOnClientSpawn(client) if (randomclass || StrEqual(steamid, "BOT")) { // Get random classes for each type. - new randomzombie = ClassGetRandomClass(ZR_CLASS_TEAM_ZOMBIES); - new randomhuman = ClassGetRandomClass(ZR_CLASS_TEAM_HUMANS); + new randomzombie = ClassGetRandomClass(ZR_CLASS_TEAM_ZOMBIES, _, _, denyflags); + new randomhuman = ClassGetRandomClass(ZR_CLASS_TEAM_HUMANS, _, _, denyflags); - // Mark zombie class as selected. + // Save selected zombie class index. ClassSelected[client][ZR_CLASS_TEAM_ZOMBIES] = randomzombie; ClassGetName(randomzombie, classname, sizeof(classname), ZR_CLASS_TEAM_ZOMBIES); TranslationPrintToChat(client, "Classes random assignment", classname); - // Mark human class as selected. + // Save selected human class index. ClassSelected[client][ZR_CLASS_TEAM_HUMANS] = randomhuman; ClassGetName(randomhuman, classname, sizeof(classname), ZR_CLASS_TEAM_HUMANS); TranslationPrintToChat(client, "Classes random assignment", classname); @@ -193,11 +199,29 @@ ClassOnClientInfected(client, bool:motherzombie = false) { // Get random regular zombie class. Remove admin flag if admin. motherindex = ClassGetRandomClass(ZR_CLASS_TEAM_ZOMBIES, _, _, ZR_CLASS_SPECIALFLAGS - isadmin); + + // Validate index. Do not change class if it's invalid. + if (ClassValidateIndex(motherindex)) + { + // Change class. + classindex = motherindex; + } } else if (StrEqual(motherzombiesetting, "motherzombies", false)) { - // Get random mother zombie class. - motherindex = ClassGetRandomClass(ZR_CLASS_TEAM_ZOMBIES, _, ZR_CLASS_FLAG_MOTHER_ZOMBIE, isadmin); + // Get random mother zombie class. Include admin classes if admin. + motherindex = ClassGetRandomClass(ZR_CLASS_TEAM_ZOMBIES, _, ZR_CLASS_FLAG_MOTHER_ZOMBIE + isadmin, ZR_CLASS_FLAG_ADMIN_ONLY - isadmin); + + // Validate index. Do not change class if it's invalid. + if (ClassValidateIndex(motherindex)) + { + // This is a mother zombie class. Reset mother zombie setting so + // class skills aren't improved. + motherzombie = false; + + // Change class. + classindex = motherindex; + } } else { diff --git a/src/zr/playerclasses/classmenus.inc b/src/zr/playerclasses/classmenus.inc index 18130ff..d2283e5 100644 --- a/src/zr/playerclasses/classmenus.inc +++ b/src/zr/playerclasses/classmenus.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: classmenus.inc * Type: Core @@ -384,7 +384,7 @@ public ClassTeamSelectHandle(Handle:menu, MenuAction:action, client, slot) { if (slot == MenuCancel_ExitBack) { - ZRAdminMenu(client); + ZAdminMenu(client); } } } diff --git a/src/zr/playerclasses/clientalpha.inc b/src/zr/playerclasses/clientalpha.inc index e55aef2..2f7f96f 100644 --- a/src/zr/playerclasses/clientalpha.inc +++ b/src/zr/playerclasses/clientalpha.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: clientalpha.inc * Type: Core diff --git a/src/zr/playerclasses/clientoverlays.inc b/src/zr/playerclasses/clientoverlays.inc index 77e53e7..b34baec 100644 --- a/src/zr/playerclasses/clientoverlays.inc +++ b/src/zr/playerclasses/clientoverlays.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: clientoverlays.inc * Type: Core @@ -73,12 +73,8 @@ ClassOverlayOnCommandsHook() */ ClassOverlayOnCookiesCreate() { - // If cookie doesn't already exist, then create it. - g_hOverlayEnabledCookie = FindClientCookie(CLASSOVERLAY_COOKIE_ENABLED); - if (g_hOverlayEnabledCookie == INVALID_HANDLE) - { - g_hOverlayEnabledCookie = RegClientCookie(CLASSOVERLAY_COOKIE_ENABLED, "The toggle state of the class overlay.", CookieAccess_Public); - } + // Create overlay cookie. + g_hOverlayEnabledCookie = RegClientCookie(CLASSOVERLAY_COOKIE_ENABLED, "The toggle state of the class overlay.", CookieAccess_Protected); } /** @@ -141,7 +137,7 @@ ClassOverlayInitialize(client, const String:overlay[]) decl String:togglecmds[CLASSOVERLAY_TOGGLE_MAX_CMDS * CLASSOVERLAY_TOGGLE_MAX_LENGTH]; GetConVarString(g_hCvarsList[CVAR_CLASSES_OVERLAY_TOGGLECMDS], togglecmds, sizeof(togglecmds)); - TranslationPrintHUDText(client, "Classes overlay toggle", togglecmds); + TranslationPrintHintText(client, "Classes overlay toggle", togglecmds); } // Display class overlays. diff --git a/src/zr/playerclasses/filtertools.inc b/src/zr/playerclasses/filtertools.inc index d63ca73..61aa25e 100644 --- a/src/zr/playerclasses/filtertools.inc +++ b/src/zr/playerclasses/filtertools.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: filtertools.inc * Type: Core diff --git a/src/zr/playerclasses/healthregen.inc b/src/zr/playerclasses/healthregen.inc index fca0c40..cb382b8 100644 --- a/src/zr/playerclasses/healthregen.inc +++ b/src/zr/playerclasses/healthregen.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: healthregen.inc * Type: Core diff --git a/src/zr/playerclasses/playerclasses.inc b/src/zr/playerclasses/playerclasses.inc index 8bd3882..92be853 100644 --- a/src/zr/playerclasses/playerclasses.inc +++ b/src/zr/playerclasses/playerclasses.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: playerclasses.inc * Type: Core @@ -166,9 +166,9 @@ #define ZR_CLASS_SPEED_MAX 2000.0 #define ZR_CLASS_KNOCKBACK_MIN -30.0 #define ZR_CLASS_KNOCKBACK_MAX 30.0 -#define ZR_CLASS_JUMP_HEIGHT_MIN -500.0 -#define ZR_CLASS_JUMP_HEIGHT_MAX 500.0 -#define ZR_CLASS_JUMP_DISTANCE_MIN -5.0 +#define ZR_CLASS_JUMP_HEIGHT_MIN 0.0 +#define ZR_CLASS_JUMP_HEIGHT_MAX 5.0 +#define ZR_CLASS_JUMP_DISTANCE_MIN 0.0 #define ZR_CLASS_JUMP_DISTANCE_MAX 5.0 /** * @endsection @@ -488,7 +488,7 @@ ClassLoad(bool:keepMultipliers = false) ClassData[ClassCount][class_health] = KvGetNum(kvClassData, "health", ZR_CLASS_DEFAULT_HEALTH); ClassData[ClassCount][class_health_regen_interval] = KvGetFloat(kvClassData, "health_regen_interval", ZR_CLASS_DEFAULT_HEALTH_REGEN_INTERVAL); ClassData[ClassCount][class_health_regen_amount] = KvGetNum(kvClassData, "health_regen_amount", ZR_CLASS_DEFAULT_HEALTH_REGEN_AMOUNT); - ClassData[ClassCount][class_health_infect_gain] = KvGetNum(kvClassData, "health_infect_bonus", ZR_CLASS_DEFAULT_HEALTH_INFECT_GAIN); + ClassData[ClassCount][class_health_infect_gain] = KvGetNum(kvClassData, "health_infect_gain", ZR_CLASS_DEFAULT_HEALTH_INFECT_GAIN); ClassData[ClassCount][class_kill_bonus] = KvGetNum(kvClassData, "kill_bonus", ZR_CLASS_DEFAULT_KILL_BONUS); ClassData[ClassCount][class_speed] = KvGetFloat(kvClassData, "speed", ZR_CLASS_DEFAULT_SPEED); diff --git a/src/zr/respawn.inc b/src/zr/respawn.inc index c36f3ce..2c67ab2 100644 --- a/src/zr/respawn.inc +++ b/src/zr/respawn.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: respawn.inc * Type: Module diff --git a/src/zr/roundend.inc b/src/zr/roundend.inc index 6e3fe11..081fe39 100644 --- a/src/zr/roundend.inc +++ b/src/zr/roundend.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: roundend.inc * Type: Core @@ -162,6 +162,26 @@ RoundEndOnRoundEnd(reason) // Get outcome of the round. new RoundEndOutcome:outcome = RoundEndReasonToOutcome(reason); + // Update team scores. + new teamscore; + switch(outcome) + { + // Zombies won the round. + case ZombiesWin: + { + // Increment T score. + teamscore = GetTeamScore(CS_TEAM_T); + SetTeamScore(CS_TEAM_T, ++teamscore); + } + // Humans won the round. + case HumansWin: + { + // Increment CT score. + teamscore = GetTeamScore(CS_TEAM_CT); + SetTeamScore(CS_TEAM_CT, ++teamscore); + } + } + // Display the overlay to all clients. RoundEndOverlayStart(outcome); diff --git a/src/zr/roundstart.inc b/src/zr/roundstart.inc index afeaf0c..f5c69f2 100644 --- a/src/zr/roundstart.inc +++ b/src/zr/roundstart.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: roundstart.inc * Type: Core @@ -30,6 +30,33 @@ */ #define ROUNDSTART_OBJECTIVE_ENTITIES "func_bomb_target|func_hostage_rescue|c4|hostage_entity" +/** + * Client is spawning into the game. + * + * @param client The client index. + */ +RoundStartOnClientSpawn(client) +{ + // If client hasn't spawned yet, then stop. + if (!IsPlayerAlive(client)) + { + return; + } + + // Get public chat trigger prefix. + decl String:publictrigger[4]; + SayHooksGetPublicChatTrigger(publictrigger, sizeof(publictrigger)); + + // If public chat trigger is disabled, then don't print message. + if (StrEqual(publictrigger, "N/A", false)) + { + return; + } + + // Print to client, how to access ZMenu. + TranslationPrintToChat(client, "General zmenu reminder", publictrigger, SAYHOOKS_KEYWORD_ZMENU); +} + /** * The round is starting. */ diff --git a/src/zr/sayhooks.inc b/src/zr/sayhooks.inc index 14b9f78..2302c0e 100644 --- a/src/zr/sayhooks.inc +++ b/src/zr/sayhooks.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: sayhooks.inc * Type: Core @@ -90,6 +90,9 @@ SayHooksGetPublicChatTrigger(String:trigger[], maxlen) { strcopy(trigger, maxlen, "N/A"); } + + // Close the handle. + CloseHandle(kvCore); } /** @@ -126,4 +129,7 @@ SayHooksGetSilentChatTrigger(String:trigger[], maxlen) { strcopy(trigger, maxlen, "N/A"); } + + // Close the handle. + CloseHandle(kvCore); } \ No newline at end of file diff --git a/src/zr/soundeffects/ambientsounds.inc b/src/zr/soundeffects/ambientsounds.inc index d205a12..65653e7 100644 --- a/src/zr/soundeffects/ambientsounds.inc +++ b/src/zr/soundeffects/ambientsounds.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: ambientsounds.inc * Type: Core diff --git a/src/zr/soundeffects/soundeffects.inc b/src/zr/soundeffects/soundeffects.inc index ea99c78..53c4ec5 100644 --- a/src/zr/soundeffects/soundeffects.inc +++ b/src/zr/soundeffects/soundeffects.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: soundeffects.inc * Type: Core diff --git a/src/zr/soundeffects/zombiesounds.inc b/src/zr/soundeffects/zombiesounds.inc index fbf50a0..e7270e9 100644 --- a/src/zr/soundeffects/zombiesounds.inc +++ b/src/zr/soundeffects/zombiesounds.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zombiesounds.inc * Type: Core diff --git a/src/zr/spawnprotect.inc b/src/zr/spawnprotect.inc index 5baed7e..9815c9f 100644 --- a/src/zr/spawnprotect.inc +++ b/src/zr/spawnprotect.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: spawnprotect.inc * Type: Module @@ -47,14 +47,17 @@ SpawnProtectClientInit(client) } /** - * Client is spawning into the game. + * Client is spawning into the game. *Post * * @param client The client index. - */ -SpawnProtectOnClientSpawn(client) + */ +SpawnProtectOnClientSpawnPost(client) { - // Disable spawn protection on client. - bInfectImmune[client][INFECT_TYPE_NORMAL] = false; + // If client is dead, then they are joining the server, not spawning. + if (!IsPlayerAlive(client)) + { + return; + } // If timer is currently running, kill it. if (tSpawnProtect[client] != INVALID_HANDLE) @@ -64,15 +67,7 @@ SpawnProtectOnClientSpawn(client) // Reset timer handle. tSpawnProtect[client] = INVALID_HANDLE; -} - -/** - * Client is spawning into the game. *Post - * - * @param client The client index. - */ -SpawnProtectOnClientSpawnPost(client) -{ + // If protect cvar is disabled, then stop. new bool:protect = GetConVarBool(g_hCvarsList[CVAR_SPAWNPROTECT]); if (!protect) @@ -80,6 +75,9 @@ SpawnProtectOnClientSpawnPost(client) return; } + // Disable spawn protection on client. + bInfectImmune[client][INFECT_TYPE_NORMAL] = false; + // Start spawn protection. SpawnProtectStart(client); } @@ -145,7 +143,7 @@ SpawnProtectStart(client) TranslationPrintToChat(client, "Spawn protection begin", protect_time); // Send time left in a hud message. - TranslationPrintHUDText(client, "Spawn Protect", pSpawnProtectTime[client]); + TranslationPrintHintText(client, "Spawn Protect", pSpawnProtectTime[client]); // Start repeating timer. tSpawnProtect[client] = CreateTimer(1.0, SpawnProtectTimer, client, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); @@ -179,7 +177,7 @@ public Action:SpawnProtectTimer(Handle:timer, any:client) pSpawnProtectTime[client]--; // Print time left to client. - TranslationPrintHUDText(client, "Spawn Protect", pSpawnProtectTime[client]); + TranslationPrintHintText(client, "Spawn Protect", pSpawnProtectTime[client]); // Time has expired. if (pSpawnProtectTime[client] <= 0) @@ -188,7 +186,7 @@ public Action:SpawnProtectTimer(Handle:timer, any:client) bInfectImmune[client][INFECT_TYPE_NORMAL] = false; // Tell client spawn protection is over. - TranslationPrintHUDText(client, "Spawn protection end"); + TranslationPrintHintText(client, "Spawn protection end"); // Fix attributes. ToolsSetClientAlpha(client, ClassGetAlphaInitial(client)); diff --git a/src/zr/steamidcache.inc b/src/zr/steamidcache.inc index ad7c173..82ee4e9 100644 --- a/src/zr/steamidcache.inc +++ b/src/zr/steamidcache.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: steamidcache.inc * Type: Core diff --git a/src/zr/tools.inc b/src/zr/tools.inc index d630172..a8a8d8f 100644 --- a/src/zr/tools.inc +++ b/src/zr/tools.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: tools.inc * Type: Core @@ -42,7 +42,6 @@ new g_iToolsDefaultFOV; * Initialize global SDKTools handles. */ new Handle:g_hToolsGameConfig = INVALID_HANDLE; -new Handle:g_hToolsEyeAngles = INVALID_HANDLE; new Handle:g_hToolsTerminateRound = INVALID_HANDLE; new Handle:g_hToolsCSWeaponDrop = INVALID_HANDLE; /** @@ -108,7 +107,6 @@ ToolsFindOffsets() WeaponsOnOffsetsFound(); AccountOnOffsetsFound(); VEffectsOnOffsetsFound(); - AntiStickOnOffsetsFound(); ZMarketOnOffsetsFound(); } @@ -126,18 +124,6 @@ ToolsSetupGameData() LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Tools, "GameData", "Can't load game config file (plugin.zombiereloaded.txt) from the gamedata directory."); } - // Prep the SDKCall for "EyeAngles." - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(g_hToolsGameConfig, SDKConf_Virtual, "EyeAngles"); - PrepSDKCall_SetReturnInfo(SDKType_QAngle, SDKPass_ByValue); - g_hToolsEyeAngles = EndPrepSDKCall(); - - // If offset "EyeAngles" can't be found, then stop the plugin. - if(g_hToolsEyeAngles == INVALID_HANDLE) - { - LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Tools, "GameData", "Offset \"EyeAngles\" was not found."); - } - // Prep the SDKCall for "TerminateRound." StartPrepSDKCall(SDKCall_GameRules); PrepSDKCall_SetFromConf(g_hToolsGameConfig, SDKConf_Signature, "TerminateRound"); diff --git a/src/zr/tools_functions.inc b/src/zr/tools_functions.inc index 928c0c3..892661d 100644 --- a/src/zr/tools_functions.inc +++ b/src/zr/tools_functions.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: tools_functions.inc * Type: Core @@ -33,7 +33,7 @@ * @param stack If modifying velocity, then true will stack new velocity onto the client's * current velocity, false will reset it. */ -ToolsClientVelocity(client, Float:vecVelocity[3], bool:apply = true, bool:stack = true) +stock ToolsClientVelocity(client, Float:vecVelocity[3], bool:apply = true, bool:stack = true) { // If retrieve if true, then get client's velocity. if (!apply) @@ -72,12 +72,30 @@ ToolsClientVelocity(client, Float:vecVelocity[3], bool:apply = true, bool:stack * @param client The client index. * @param value LMV value. (1.0 = default, 2.0 = double) */ -ToolsSetClientLMV(client, Float:fLMV) +stock ToolsSetClientLMV(client, Float:fLMV) { // Set lagged movement value of client. SetEntDataFloat(client, g_iToolsLMV, fLMV / 300.0, true); } +/** + * Get nightvision values on a client. + * @param client The client index. + * @param ownership If true, function will return the value of the client's ownership of nightvision. + * If false, function will return the value of the client's on/off state of the nightvision. + * @return True if aspect of nightvision is enabled on the client, false if not. + */ +stock bool:ToolsGetClientNightVision(client, bool:ownership = true) +{ + // If ownership is true, then toggle the ownership of nightvision on client. + if (ownership) + { + return bool:GetEntData(client, g_iToolsHasNightVision, 1); + } + + return bool:GetEntData(client, g_iToolsNightVisionOn, 1); +} + /** * Control nightvision values on a client. * @param client The client index. @@ -85,7 +103,7 @@ ToolsSetClientLMV(client, Float:fLMV) * @param ownership If true, enable will toggle the client's ownership of nightvision. * If false, enable will toggle the client's on/off state of the nightvision. */ -ToolsClientNightVision(client, bool:enable, bool:ownership = true) +stock ToolsSetClientNightVision(client, bool:enable, bool:ownership = true) { // If ownership is true, then toggle the ownership of nightvision on client. if (ownership) @@ -104,7 +122,7 @@ ToolsClientNightVision(client, bool:enable, bool:ownership = true) * @param client The client index. * @param FOV The field of vision of the client. */ -ToolsSetClientDefaultFOV(client, FOV) +stock ToolsSetClientDefaultFOV(client, FOV) { SetEntData(client, g_iToolsDefaultFOV, FOV, 1, true); } @@ -118,7 +136,7 @@ ToolsSetClientDefaultFOV(client, FOV) * @param value The value of the client's score or deaths. * @return The score or death count of the client, -1 if setting. */ -ToolsClientScore(client, bool:score = true, bool:apply = true, value = 0) +stock ToolsClientScore(client, bool:score = true, bool:apply = true, value = 0) { if (!apply) { @@ -156,7 +174,7 @@ ToolsClientScore(client, bool:score = true, bool:apply = true, value = 0) * @param alpha The alpha value to set client's alpha to. (0-255) * @param weapons Apply alpha to all client's weapons. */ -ToolsSetClientAlpha(client, alpha) +stock ToolsSetClientAlpha(client, alpha) { // Turn rendermode on, on the client. SetEntityRenderMode(client, RENDER_TRANSALPHA); @@ -174,7 +192,7 @@ ToolsSetClientAlpha(client, alpha) * @param client The client index. * @return The alpha value of the client. (0-255) */ -ToolsGetEntityAlpha(entity) +stock ToolsGetEntityAlpha(entity) { static bool:gotconfig = false; static String:prop[32]; diff --git a/src/zr/translation.inc b/src/zr/translation.inc index 1b8ccfa..63658d8 100644 --- a/src/zr/translation.inc +++ b/src/zr/translation.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: translation.inc * Type: Core @@ -49,11 +49,6 @@ * @endsection */ -/** - * HUD text usermsg - */ -#define TRANSLATION_USERMSG_HINTTEXT "HintText" - /** * Load translations file here. */ @@ -285,7 +280,7 @@ stock TranslationPrintCenterText(client, any:...) * @param client The client index. * @param ... Translation formatting parameters. */ -stock TranslationPrintHUDText(client, any:...) +stock TranslationPrintHintText(client, any:...) { // Set translation target SetGlobalTransTarget(client); @@ -295,17 +290,7 @@ stock TranslationPrintHUDText(client, any:...) VFormat(translation, sizeof(translation), "%t", 2); // Print translated phrase to client. - - // If hint text usermsg is invalid, then stop. - new Handle:hHintText = StartMessageOne(TRANSLATION_USERMSG_HINTTEXT, client); - if (hHintText == INVALID_HANDLE) - { - return; - } - - BfWriteByte(hHintText, -1); - BfWriteString(hHintText, translation); - EndMessage(); + PrintHintText(client, translation); } /** diff --git a/src/zr/visualeffects/ragdoll.inc b/src/zr/visualeffects/ragdoll.inc index 69c4a90..ea1c9f1 100644 --- a/src/zr/visualeffects/ragdoll.inc +++ b/src/zr/visualeffects/ragdoll.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: ragdoll.inc * Type: Module diff --git a/src/zr/visualeffects/visualambience.inc b/src/zr/visualeffects/visualambience.inc index 59b8888..4623a1f 100644 --- a/src/zr/visualeffects/visualambience.inc +++ b/src/zr/visualeffects/visualambience.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: visualambience.inc * Type: Module diff --git a/src/zr/visualeffects/visualeffects.inc b/src/zr/visualeffects/visualeffects.inc index 7792f37..eb3d16d 100644 --- a/src/zr/visualeffects/visualeffects.inc +++ b/src/zr/visualeffects/visualeffects.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: visualeffects.inc * Type: Module diff --git a/src/zr/weapons/menu_weapons.inc b/src/zr/weapons/menu_weapons.inc index d57c6fe..4b023da 100644 --- a/src/zr/weapons/menu_weapons.inc +++ b/src/zr/weapons/menu_weapons.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: menu_weapons.inc * Type: Core @@ -104,7 +104,7 @@ public WeaponsMenuMainHandle(Handle:menu_weapons_main, MenuAction:action, client if (slot == MenuCancel_ExitBack) { // Re-open admin menu. - ZRAdminMenu(client); + ZAdminMenu(client); } } // Client hit "Exit" button. @@ -210,7 +210,7 @@ WeaponsMenuTypeWeapons(client) decl String:unrestrictall[64]; Format(restrictall, sizeof(restrictall), "%t", "Weapons menu restrict types restrict all", typename); - Format(unrestrictall, sizeof(unrestrictall), "%t", "Weapons menu restrict types unrestrict all", typename); + Format(unrestrictall, sizeof(unrestrictall), "%t\n ", "Weapons menu restrict types unrestrict all", typename); // 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_iWeaponsCurType[client]))); diff --git a/src/zr/weapons/restrict.inc b/src/zr/weapons/restrict.inc index 1b71e42..280e3b6 100644 --- a/src/zr/weapons/restrict.inc +++ b/src/zr/weapons/restrict.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: restrict.inc * Type: Core @@ -43,6 +43,11 @@ enum RestrictData */ new g_iCanUseHookID[MAXPLAYERS + 1] = {-1, ...}; +/** + * Array to block any client from picking up weapons. + */ +new bool:g_bRestrictBlockWeapon[MAXPLAYERS + 1]; + /** * Array to store a list of different weapon groups */ @@ -134,6 +139,9 @@ RestrictClientInit(client) { // Hook "Weapon_CanUse" on client. g_iCanUseHookID[client] = ZRTools_HookWeapon_CanUse(client, RestrictCanUse); + + // Reset block weapons flag. + g_bRestrictBlockWeapon[client] = false; } /** @@ -161,6 +169,48 @@ RestrictOnClientSpawn(client) // Re-hook "canuse" on client. ZRTools_UnhookWeapon_CanUse(g_iCanUseHookID[client]); g_iCanUseHookID[client] = ZRTools_HookWeapon_CanUse(client, RestrictCanUse); + + // H4x. Unfortunately I can't disable this flag early enough for CS:S to give start USP/Glock. + // So I have to give BOOTLEG weapons. (Sorry Valve) + if (g_bRestrictBlockWeapon[client]) + { + // Reset block weapons flag. + g_bRestrictBlockWeapon[client] = false; + + if (ZRIsClientOnTeam(client, CS_TEAM_T)) + { + GivePlayerItem(client, WEAPONS_SPAWN_T_WEAPON); + } + else if (ZRIsClientOnTeam(client, CS_TEAM_CT)) + { + GivePlayerItem(client, WEAPONS_SPAWN_CT_WEAPON); + } + } +} + +/** + * The round is ending. + */ +RestrictOnRoundEnd() +{ + // x = Client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // If client is a human, then stop. + if (InfectIsClientHuman(x)) + { + continue; + } + + // Enable block weapon flag. + g_bRestrictBlockWeapon[x] = true; + } } /** @@ -181,7 +231,7 @@ public Action:RestrictBuyCommand(client, argc) return Plugin_Handled; } - decl String:weapon[64]; + decl String:weapon[WEAPONS_MAX_LENGTH]; GetCmdArg(1, weapon, sizeof(weapon)); ReplaceString(weapon, sizeof(weapon), "weapon_", ""); @@ -199,7 +249,11 @@ public Action:RestrictBuyCommand(client, argc) // If weapon is restricted, then stop. if (RestrictIsWeaponRestricted(index)) { - TranslationPrintToChat(client, "Weapon is restricted", weapon); + // Get display name. + decl String:weapondisplay[WEAPONS_MAX_LENGTH]; + WeaponsGetName(index, weapondisplay, sizeof(weapondisplay)); + + TranslationPrintToChat(client, "Weapon is restricted", weapondisplay); // Block command. return Plugin_Handled; @@ -545,6 +599,18 @@ public ZRTools_Action:RestrictCanUse(client, weapon) return ZRTools_Continue; } + // If the player is a zombie, then prevent pickup. + if (InfectIsClientInfected(client)) + { + return ZRTools_Handled; + } + + // If client is flagged for not picking up weapons, then stop. + if (g_bRestrictBlockWeapon[client]) + { + return ZRTools_Handled; + } + // If weapons module is disabled, then stop. new bool:weapons = GetConVarBool(g_hCvarsList[CVAR_WEAPONS]); if (!weapons) @@ -575,12 +641,6 @@ public ZRTools_Action:RestrictCanUse(client, weapon) return ZRTools_Handled; } - // If the player is a zombie, then prevent pickup. - if (InfectIsClientInfected(client)) - { - return ZRTools_Handled; - } - // Forward event to weapons module. WeaponsOnItemPickup(client, weapon); diff --git a/src/zr/weapons/weaponalpha.inc b/src/zr/weapons/weaponalpha.inc index 0485092..f428b9f 100644 --- a/src/zr/weapons/weaponalpha.inc +++ b/src/zr/weapons/weaponalpha.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: weaponalpha.inc * Type: Core diff --git a/src/zr/weapons/weaponammo.inc b/src/zr/weapons/weaponammo.inc index 7f9d2a1..f4a6edd 100644 --- a/src/zr/weapons/weaponammo.inc +++ b/src/zr/weapons/weaponammo.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: weaponammo.inc * Type: Core diff --git a/src/zr/weapons/weapons.inc b/src/zr/weapons/weapons.inc index 7c91fa1..8beea92 100644 --- a/src/zr/weapons/weapons.inc +++ b/src/zr/weapons/weapons.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: weapons.inc * Type: Core @@ -31,10 +31,19 @@ #define WEAPONS_MAX_LENGTH 32 /** - * Number of weapon slots (For CS:S) + * Number of REAL weapon slots (For CS:S) */ #define WEAPONS_SLOTS_MAX 5 +/** + * @section CS:S start weapons. + */ +#define WEAPONS_SPAWN_T_WEAPON "weapon_glock" +#define WEAPONS_SPAWN_CT_WEAPON "weapon_usp" +/** + * @endsection + */ + /** * Weapon config data indexes. */ @@ -73,6 +82,7 @@ enum WeaponsSlot Slot_Melee = 2, /** Melee (knife) weapon slot. */ Slot_Projectile = 3, /** Projectile (grenades, flashbangs, etc) weapon slot. */ Slot_Explosive = 4, /** Explosive (c4) weapon slot. */ + Slot_NVGs = 5, /** NVGs (fake) equipment slot. */ } /** @@ -325,6 +335,15 @@ WeaponsOnClientSpawnPost(client) ZMarketOnClientSpawnPost(client); } +/** + * The round is ending. + */ +WeaponsOnRoundEnd() +{ + // Forward event to sub-modules. + RestrictOnRoundEnd(); +} + /** * Called when a client picks up an item. * diff --git a/src/zr/weapons/zmarket.inc b/src/zr/weapons/zmarket.inc index 7fa6359..7010be2 100644 --- a/src/zr/weapons/zmarket.inc +++ b/src/zr/weapons/zmarket.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zmarket.inc * Type: Module @@ -65,25 +65,21 @@ ZMarketOnCommandsCreate() ZMarketOnCookiesCreate() { - // If auto-rebuy cookie doesn't already exist, then create all ZMarket cookies. - g_hZMarketAutoRebuyCookie = FindClientCookie(ZMARKET_COOKIE_AUTOREBUY); - if (g_hZMarketAutoRebuyCookie == INVALID_HANDLE) + // Create all cookies. + g_hZMarketAutoRebuyCookie = RegClientCookie(ZMARKET_COOKIE_AUTOREBUY, "The toggle state of auto-rebuy.", CookieAccess_Protected); + + decl String:rebuycookiename[32]; + decl String:rebuycookiedesc[64]; + + // x = Weapon slot. + for (new x = 0; x < WEAPONS_SLOTS_MAX + 1; x++) { - g_hZMarketAutoRebuyCookie = RegClientCookie(ZMARKET_COOKIE_AUTOREBUY, "The toggle state of auto-rebuy.", CookieAccess_Public); + // Format cookie name and description. + Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); + Format(rebuycookiedesc, sizeof(rebuycookiedesc), "Current loadout weapon for slot %d", x); - decl String:rebuycookiename[32]; - decl String:rebuycookiedesc[64]; - - // x = Weapon slot. - for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) - { - // Format cookie name and description. - Format(rebuycookiename, sizeof(rebuycookiename), "%s_%d", ZMARKET_COOKIE_REBUY, x); - Format(rebuycookiedesc, sizeof(rebuycookiedesc), "Current loadout weapon for slot %d", x); - - // Register client cookie. - RegClientCookie(rebuycookiename, rebuycookiedesc, CookieAccess_Public); - } + // Register client cookie. + RegClientCookie(rebuycookiename, rebuycookiedesc, CookieAccess_Protected); } } @@ -161,6 +157,12 @@ ZMarketOnClientSpawnPost(client) return; } + // If client is a zombie, then stop. + if (InfectIsClientInfected(client)) + { + return; + } + // If auto-rebuy is enabled, then force client to rebuy weapons. if (CookiesGetClientCookieBool(client, g_hZMarketAutoRebuyCookie)) { @@ -382,10 +384,11 @@ bool:ZMarketMenuLoadout(client) decl String:meleeweapon[WEAPONS_MAX_LENGTH]; decl String:projectileweapon[WEAPONS_MAX_LENGTH]; decl String:explosiveweapon[WEAPONS_MAX_LENGTH]; + decl String:nvgsweapon[WEAPONS_MAX_LENGTH]; // Transfer cookie values into an array. new String:rebuyweapons[WeaponsSlot][WEAPONS_MAX_LENGTH]; - ZMarketCookiesToArray(client, rebuyweapons, WEAPONS_SLOTS_MAX, sizeof(rebuyweapons[])); + ZMarketCookiesToArray(client, rebuyweapons, WEAPONS_SLOTS_MAX + 1, sizeof(rebuyweapons[])); // Return the display name for all the client's weapon classname's. WeaponsClassnameToDisplay(rebuyweapons[Slot_Primary], sizeof(rebuyweapons[]), primaryweapon, sizeof(primaryweapon)); @@ -393,6 +396,7 @@ bool:ZMarketMenuLoadout(client) WeaponsClassnameToDisplay(rebuyweapons[Slot_Melee], sizeof(rebuyweapons[]), meleeweapon, sizeof(meleeweapon)); WeaponsClassnameToDisplay(rebuyweapons[Slot_Projectile], sizeof(rebuyweapons[]), projectileweapon, sizeof(projectileweapon)); WeaponsClassnameToDisplay(rebuyweapons[Slot_Explosive], sizeof(rebuyweapons[]), explosiveweapon, sizeof(explosiveweapon)); + WeaponsClassnameToDisplay(rebuyweapons[Slot_NVGs], sizeof(rebuyweapons[]), nvgsweapon, sizeof(nvgsweapon)); // Get the empty translation. decl String:empty[64]; @@ -420,11 +424,16 @@ bool:ZMarketMenuLoadout(client) strcopy(explosiveweapon, sizeof(explosiveweapon), empty); } + // Copy "Yes/No" to NVGs string. + decl String:nvgsbool[8]; + ConfigBoolToSetting(bool:nvgsweapon[0], nvgsbool, sizeof(nvgsbool)); + decl String:primary[64]; decl String:secondary[64]; decl String:melee[64]; decl String:projectile[64]; decl String:explosive[64]; + decl String:nvgs[64]; // Format all the lines of the menu. Format(primary, sizeof(primary), "%t", "Weapons menu zmarket loadout primary", primaryweapon); @@ -432,13 +441,15 @@ bool:ZMarketMenuLoadout(client) Format(melee, sizeof(melee), "%t", "Weapons menu zmarket loadout melee", meleeweapon); Format(projectile, sizeof(projectile), "%t", "Weapons menu zmarket loadout projectile", projectileweapon); Format(explosive, sizeof(explosive), "%t", "Weapons menu zmarket loadout explosive", explosiveweapon); + Format(nvgs, sizeof(nvgs), "%t", "Weapons menu zmarket loadout nvgs", nvgsbool); // Add formatted options to menu. - AddMenuItem(menu_zmarket_loadout, primary, primary, ITEMDRAW_DISABLED); - AddMenuItem(menu_zmarket_loadout, secondary, secondary, ITEMDRAW_DISABLED); - AddMenuItem(menu_zmarket_loadout, melee, melee, ITEMDRAW_DISABLED); - AddMenuItem(menu_zmarket_loadout, projectile, projectile, ITEMDRAW_DISABLED); - AddMenuItem(menu_zmarket_loadout, explosive, explosive, ITEMDRAW_DISABLED); + AddMenuItem(menu_zmarket_loadout, "0", primary, MenuGetItemDraw(!StrEqual(primaryweapon, empty))); + AddMenuItem(menu_zmarket_loadout, "1", secondary, MenuGetItemDraw(!StrEqual(secondaryweapon, empty))); + AddMenuItem(menu_zmarket_loadout, "2", melee, MenuGetItemDraw(!StrEqual(meleeweapon, empty))); + AddMenuItem(menu_zmarket_loadout, "3", projectile, MenuGetItemDraw(!StrEqual(projectileweapon, empty))); + AddMenuItem(menu_zmarket_loadout, "4", explosive, MenuGetItemDraw(!StrEqual(explosiveweapon, empty))); + AddMenuItem(menu_zmarket_loadout, "5", nvgs, MenuGetItemDraw(bool:nvgsweapon[0])); // Set exit back button. SetMenuExitBackButton(menu_zmarket_loadout, true); @@ -457,6 +468,15 @@ bool:ZMarketMenuLoadout(client) */ public ZMarketMenuLoadoutHandle(Handle:menu_zmarket_loadout, MenuAction:action, client, slot) { + // Client selected an option. + if (action == MenuAction_Select) + { + // Clear rebuy slot. + ZMarketSetRebuyCookie(client, WeaponsSlot:slot, ""); + + // Re-send menu. + ZMarketMenuLoadout(client); + } // Client closed the menu. if (action == MenuAction_Cancel) { @@ -779,6 +799,32 @@ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) return false; } + // Copy the 'weapon' variable into a local variable for indexing. + decl String:weaponname[WEAPONS_MAX_LENGTH]; + strcopy(weaponname, sizeof(weaponname), weapon); + + // Get the display name for the weapon. + decl String:weapondisplay[WEAPONS_MAX_LENGTH]; + WeaponsClassnameToDisplay(weaponname, sizeof(weaponname), weapondisplay, sizeof(weapondisplay)); + + // Check to make sure the weapon isn't restricted. + new bool:restricted = RestrictIsWeaponRestricted(weaponindex); + if (restricted) + { + TranslationPrintToChat(client, "Weapon is restricted", weapondisplay); + return false; + } + + // Get the purchase count information for this weapon. + new purchasemax = WeaponsGetZMarketPurchaseMax(weaponindex); + new purchasecount = ZMarketGetPurchaseCount(client, weapon); + new purchasesleft = purchasemax - purchasecount; + if (purchasemax > 0 && purchasesleft <= 0) + { + TranslationPrintToChat(client, "Weapons zmarket purchase max", weapondisplay, purchasemax); + return false; + } + // Get client's current money. new cash = AccountGetClientCash(client); @@ -795,34 +841,16 @@ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) // Set client's new cash after purchase. AccountSetClientCash(client, cash - itemprice); - // Check to make sure the weapon isn't restricted. - new bool:restricted = RestrictIsWeaponRestricted(weaponindex); - if (restricted) - { - TranslationPrintToChat(client, "Weapon is restricted", weapon); - return false; - } - - // Get the purchase count information for this weapon. - new purchasemax = WeaponsGetZMarketPurchaseMax(weaponindex); - new purchasecount = ZMarketGetPurchaseCount(client, weapon); - new purchasesleft = purchasemax - purchasecount; - if (purchasemax > 0 && purchasesleft <= 0) - { - TranslationPrintToChat(client, "Weapons zmarket purchase max", weapon, purchasemax); - return false; - } - // Get a list of the client's current weapons. new weapons[WeaponsSlot]; WeaponsGetClientWeapons(client, weapons); // Check if client is buying the weapon or ammo for it. - if (!hasweapon || slot == Slot_Invalid || slot == Slot_Projectile) + if (!hasweapon || slot == Slot_Projectile || slot == Slot_NVGs) { - // Check if the slot is valid and NOT a projectile (grenade). - if (slot != Slot_Invalid && slot != Slot_Projectile) + // If the item is a projectile or NVGs, then skip. + if (slot != Slot_Projectile && slot != Slot_NVGs) { // If there is already a weapon in the slot, then force client to drop it. if (weapons[slot] > -1) @@ -835,8 +863,8 @@ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) // Format name into entity name. decl String:weaponentity[WEAPONS_MAX_LENGTH]; - // If the slot is invalid, this means the item is not a usable weapon, it's equipment. - if (slot == Slot_Invalid) + // If this is the NVGs slot, then format "item_" in front instead of "weapon_". + if (slot == Slot_NVGs) { Format(weaponentity, sizeof(weaponentity), "item_%s", weapon); } @@ -854,10 +882,10 @@ stock bool:ZMarketEquip(client, const String:weapon[], bool:rebuy = false) // Add 1 to the client's purchase count. ZMarketSetPurchaseCount(client, weapon, 1, true); - if (slot != Slot_Invalid && slot != Slot_Projectile) + if (slot != Slot_Projectile && slot != Slot_NVGs) { // Tell client they bought a weapon. - TranslationPrintToChat(client, "Weapons zmarket purchase", weapon); + TranslationPrintToChat(client, "Weapons zmarket purchase", weapondisplay); } } else if (!rebuy) @@ -926,6 +954,18 @@ bool:ZMarketGetCurrentLoadout(client) ZMarketSetRebuyCookie(client, WeaponsSlot:x, weaponname); } + // Update nightvision ownership. + new bool:nightvision = ToolsGetClientNightVision(client); + if (!nightvision) + { + // Empty rebuy slot. + ZMarketSetRebuyCookie(client, Slot_NVGs, ""); + } + else + { + ZMarketSetRebuyCookie(client, Slot_NVGs, "nvgs"); + } + // Tell client their loadout has been updated. TranslationPrintToChat(client, "Weapons zmarket get current loadout"); @@ -997,6 +1037,12 @@ stock ZMarketSetRebuyCookie(client, WeaponsSlot:slot, const String:value[]) // Find cookie handle, and retrieve its value. new Handle:rebuycookie = FindClientCookie(rebuycookiename); + if (rebuycookie == INVALID_HANDLE) + { + return; + } + + // Set weapon to cookie. SetClientCookie(client, rebuycookie, value); } @@ -1023,10 +1069,10 @@ ZMarketRebuy(client, bool:autorebuy = false) // Transfer cookie values into an array. new String:rebuyweapons[WeaponsSlot][WEAPONS_MAX_LENGTH]; - ZMarketCookiesToArray(client, rebuyweapons, WEAPONS_SLOTS_MAX, sizeof(rebuyweapons[])); + ZMarketCookiesToArray(client, rebuyweapons, WEAPONS_SLOTS_MAX + 1, sizeof(rebuyweapons[])); // x = Weapon slot. - for (new x = 0; x < WEAPONS_SLOTS_MAX; x++) + for (new x = 0; x < WEAPONS_SLOTS_MAX + 1; x++) { // If slot is empty, then stop. if (!rebuyweapons[x][0]) @@ -1036,9 +1082,6 @@ ZMarketRebuy(client, bool:autorebuy = false) ZMarketEquip(client, rebuyweapons[x], true); } - - // Copy values back to cookies. - ZMarketArrayToCookies(client, rebuyweapons, WEAPONS_SLOTS_MAX, sizeof(rebuyweapons)); } /** diff --git a/src/zr/zadmin.inc b/src/zr/zadmin.inc index f77bc11..c40ab52 100644 --- a/src/zr/zadmin.inc +++ b/src/zr/zadmin.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zadmin.inc * Type: Core @@ -51,7 +51,7 @@ public Action:ZAdminCommand(client, argc) } // Send admin menu. - ZRAdminMenu(client); + ZAdminMenu(client); // This stops the "Unknown command" message in client's console. return Plugin_Handled; @@ -62,7 +62,7 @@ public Action:ZAdminCommand(client, argc) * * @param client The client index. */ -bool:ZRAdminMenu(client) +bool:ZAdminMenu(client) { // If client isn't an admin, then stop. if (!ZRIsClientAdmin(client)) @@ -72,7 +72,7 @@ bool:ZRAdminMenu(client) } // Create menu handle. - new Handle:menu_zadmin = CreateMenu(ZRAdminMenuHandle); + new Handle:menu_zadmin = CreateMenu(ZAdminMenuHandle); // Set translation target as the client. SetGlobalTransTarget(client); @@ -80,24 +80,31 @@ bool:ZRAdminMenu(client) SetMenuTitle(menu_zadmin, "%t\n ", "ZAdmin main title"); decl String:classmultipliers[64]; - //decl String:zspawn[64]; - //decl String:ztele[64]; decl String:weapons[64]; + decl String:hitgroups[64]; decl String:infect[64]; + decl String:zspawn[64]; + decl String:ztele[64]; //decl String:logflags[64]; Format(classmultipliers, sizeof(classmultipliers), "%t", "ZAdmin main class multipliers"); Format(weapons, sizeof(weapons), "%t", "ZAdmin main weapons"); + Format(hitgroups, sizeof(hitgroups), "%t", "ZAdmin main hitgroups"); Format(infect, sizeof(infect), "%t", "ZAdmin main zombie"); - //Format(zspawn, sizeof(zspawn), "%t", "!zadmin main spawn"); - //Format(ztele, sizeof(ztele), "%t", "!zadmin main tele"); + Format(zspawn, sizeof(zspawn), "%t", "ZAdmin main force zspawn"); + Format(ztele, sizeof(ztele), "%t", "ZAdmin main force ztele"); //Format(logflags, sizeof(logflags), "%t", "!zadmin main logflags"); + // Get conditions for options. + new bool:hitgroupsenabled = GetConVarBool(g_hCvarsList[CVAR_HITGROUPS]); + + // Add items to menu. AddMenuItem(menu_zadmin, "classmultipliers", classmultipliers); AddMenuItem(menu_zadmin, "weapons", weapons); + AddMenuItem(menu_zadmin, "hitgroups", hitgroups, MenuGetItemDraw(hitgroupsenabled)); AddMenuItem(menu_zadmin, "infect", infect); - //AddMenuItem(menu_zadmin, "zspawn", zspawn); - //AddMenuItem(menu_zadmin, "ztele", ztele, ITEMDRAW_DISABLED); + AddMenuItem(menu_zadmin, "zspawn", zspawn); + AddMenuItem(menu_zadmin, "ztele", ztele); //AddMenuItem(menu_zadmin, "logflags", logflags); // Set "Back" button. @@ -118,7 +125,7 @@ bool:ZRAdminMenu(client) * @param client The client index. * @param slot The menu slot selected. (starting from 0) */ -public ZRAdminMenuHandle(Handle:menu_zadmin, MenuAction:action, client, slot) +public ZAdminMenuHandle(Handle:menu_zadmin, MenuAction:action, client, slot) { if (action == MenuAction_Select) { @@ -137,8 +144,13 @@ public ZRAdminMenuHandle(Handle:menu_zadmin, MenuAction:action, client, slot) { resend = !WeaponsMenuMain(client); } - // Zombie management. + // Hitgroup management. case 2: + { + resend = !HitgroupsMenuHitgroups(client); + } + // Zombie management. + case 3: { // We're not resending this menu. resend = false; @@ -146,12 +158,30 @@ public ZRAdminMenuHandle(Handle:menu_zadmin, MenuAction:action, client, slot) // Send list of clients to infect. InfectMenuClients(client); } + // Force ZSpawn. + case 4: + { + // We're not resending this menu. + resend = false; + + // Send list of clients to infect. + MenuClientList(client, ZSpawnForceHandle, "ZSpawn clients title"); + } + // Force ZTele. + case 5: + { + // We're not resending this menu. + resend = false; + + // Send list of clients to infect. + MenuClientList(client, ZTeleForceHandle, "ZTele clients title"); + } } // Re-send menu if selection failed. if (resend) { - ZRAdminMenu(client); + ZAdminMenu(client); } } diff --git a/src/zr/zcookies.inc b/src/zr/zcookies.inc index e6ea9f7..930ad28 100644 --- a/src/zr/zcookies.inc +++ b/src/zr/zcookies.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zcookies.inc * Type: Module diff --git a/src/zr/zhp.inc b/src/zr/zhp.inc index bba4cd5..a8c96f0 100644 --- a/src/zr/zhp.inc +++ b/src/zr/zhp.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zhp.inc * Type: Module @@ -54,12 +54,8 @@ ZHPOnCommandsCreate() */ ZHPOnCookiesCreate() { - // If cookie doesn't already exist, then create it. - g_hZHPEnabledCookie = FindClientCookie(ZHP_COOKIE_ENABLED); - if (g_hZHPEnabledCookie == INVALID_HANDLE) - { - g_hZHPEnabledCookie = RegClientCookie(ZHP_COOKIE_ENABLED, "The toggle state of ZHP.", CookieAccess_Public); - } + // Create ZHP cookie. + g_hZHPEnabledCookie = RegClientCookie(ZHP_COOKIE_ENABLED, "The toggle state of ZHP.", CookieAccess_Protected); } /** @@ -242,7 +238,7 @@ ZHPUpdateHUD(client) } // Display HP - TranslationPrintHUDText(client, "Display HP", health); + TranslationPrintHintText(client, "Display HP", health); } /** diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index f71ed73..4dbb895 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zombiereloaded.inc * Type: Core @@ -248,6 +248,7 @@ stock bool:ZRIsClientAdmin(client, AdminFlag:flag = Admin_Generic) { return false; } + // If client doesn't have the Admin_Generic flag, then stop. if (!GetAdminFlag(GetUserAdmin(client), flag)) { diff --git a/src/zr/zspawn.inc b/src/zr/zspawn.inc index f746588..6982484 100644 --- a/src/zr/zspawn.inc +++ b/src/zr/zspawn.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: zspawn.inc * Type: Module @@ -42,6 +42,9 @@ ZSpawnOnCommandsCreate() { // Register ZSpawn command. RegConsoleCmd(SAYHOOKS_KEYWORD_ZSPAWN, ZSpawnCommand, "Spawn into the game after joining late."); + + // Register admin command to force ZSpawn. + RegAdminCmd("zr_zspawn_force", ZSpawnForceCommand, ADMFLAG_GENERIC, "Force ZSpawn on a client. Usage: zr_zspawn_force ['0' = Spawn as human | '1' = Spawn as zombie]"); } /** @@ -69,6 +72,12 @@ ZSpawnOnMapStart() */ ZSpawnOnClientDisconnect(client) { + // So people who are connecting that click "cancel" aren't added to the list. + if (!IsClientInGame(client)) + { + return; + } + // Check if client is a bot. if (IsFakeClient(client)) { @@ -162,13 +171,15 @@ ZSpawnOnRoundEnd() * Spawns a late-joining client into the game. * * @param client The client index. + * @param force (Optional) True to force spawning of the client, false to follow rules. + * @param zombie (Optional) If you are forcing spawn, you must override the team here. * @return True if successful, false otherwise. */ -bool:ZSpawnClient(client) +bool:ZSpawnClient(client, bool:force = false, bool:zombie = false) { // If zspawn is disabled, then stop. new bool:zspawn = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN]); - if (!zspawn) + if (!force && !zspawn) { TranslationPrintToChat(client, "Feature is disabled"); return false; @@ -177,60 +188,78 @@ bool:ZSpawnClient(client) // If client isn't on a team, then stop. if (!ZRIsClientOnTeam(client)) { - // Tell client the command may only be used when on a team. - TranslationPrintToChat(client, "Must be on team"); + if (!force) + { + // Tell client the command may only be used when on a team. + TranslationPrintToChat(client, "Must be on team"); + } + return false; } // If client is alive, then stop. if (IsPlayerAlive(client)) { - // Tell client the command may only be used when dead. - TranslationPrintToChat(client, "Must be dead"); + if (!force) + { + // Tell client the command may only be used when dead. + TranslationPrintToChat(client, "Must be dead"); + } + return false; } // Block if client has already played during this round. - if (SteamidCacheClientExists(g_hZSpawnSteamIDCache, client)) + if (!force && SteamidCacheClientExists(g_hZSpawnSteamIDCache, client)) { // Tell client the command may only be used when joining late. TranslationPrintToChat(client, "ZSpawn double spawn"); return false; } - // Check if zspawn override is enabled, and if so get overidden value. - new bool:teamoverride = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_OVERRIDE]); - new bool:teamzombie = teamoverride ? GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_ZOMBIE]) : GetConVarBool(g_hCvarsList[CVAR_RESPAWN_TEAM_ZOMBIE]); + new bool:teamzombie; - // Block is the time limit is up. - new bool:zspawntimelimit = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT]); - if (zspawntimelimit) + if (!force) { - if (tZSpawn == INVALID_HANDLE) + // Check if zspawn override is enabled, and if so get overidden value. + new bool:teamoverride = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_OVERRIDE]); + teamzombie = teamoverride ? GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TEAM_ZOMBIE]) : GetConVarBool(g_hCvarsList[CVAR_RESPAWN_TEAM_ZOMBIE]); + + // Block is the time limit is up. + new bool:zspawntimelimit = GetConVarBool(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT]); + if (zspawntimelimit) { - new zspawntimelimitzombie = GetConVarInt(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_ZOMBIE]); - switch(zspawntimelimitzombie) + if (tZSpawn == INVALID_HANDLE) { - case -1: + new zspawntimelimitzombie = GetConVarInt(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_ZOMBIE]); + switch(zspawntimelimitzombie) { - // Get timelimit - new Float:zspawntime = GetConVarFloat(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_TIME]); - - // Tell client the timelimit for this command has expired. - TranslationPrintToChat(client, "ZSpawn timelimit", RoundToNearest(zspawntime)); - return false; - } - case 0: - { - teamzombie = false; - } - case 1: - { - teamzombie = true; + case -1: + { + // Get timelimit + new Float:zspawntime = GetConVarFloat(g_hCvarsList[CVAR_ZSPAWN_TIMELIMIT_TIME]); + + // Tell client the timelimit for this command has expired. + TranslationPrintToChat(client, "ZSpawn timelimit", RoundToNearest(zspawntime)); + return false; + } + case 0: + { + teamzombie = false; + } + case 1: + { + teamzombie = true; + } } } } } + else + { + // Use the override team in the function if were forcing the spawn. + teamzombie = zombie; + } // Tell respawn module to respawn client. RespawnSpawnClient(client, teamzombie); @@ -238,6 +267,60 @@ bool:ZSpawnClient(client) return true; } +/** + * Menu callback (zspawn_force) + * Forces ZSpawn on a client. + * + * @param menu The menu handle. + * @param action Action client is doing in menu. + * @param client The client index. + * @param slot The menu slot selected. (starting from 0) + */ +public ZSpawnForceHandle(Handle:menu_zspawn_force, MenuAction:action, client, slot) +{ + // Client selected an option. + if (action == MenuAction_Select) + { + // Get the client index of the selected client. + new target = MenuGetClientIndex(menu_zspawn_force, slot); + + // Get the target's name for future use. + decl String:targetname[MAX_NAME_LENGTH]; + GetClientName(target, targetname, sizeof(targetname)); + + // Force ZSpawn on the target. + new bool:success = ZSpawnClient(target, true); + + // Tell admin the outcome of the action. + if (success) + { + TranslationReplyToCommand(client, "ZSpawn command force successful", targetname); + } + else + { + TranslationReplyToCommand(client, "ZSpawn command force unsuccessful", targetname); + } + + // Re-send the menu. + MenuClientList(client, ZSpawnForceHandle, "ZSpawn clients title"); + } + // Client closed the menu. + if (action == MenuAction_Cancel) + { + // Client hit "Back" button. + if (slot == MenuCancel_ExitBack) + { + // Re-open admin menu. + ZAdminMenu(client); + } + } + // Client exited menu. + if (action == MenuAction_End) + { + CloseHandle(menu_zspawn_force); + } +} + /** * Command callback (zspawn) * Spawn into the game after joining late. @@ -261,6 +344,72 @@ public Action:ZSpawnCommand(client, argc) return Plugin_Handled; } +/** + * Command callback (zr_zspawn_force) + * Force ZSpawn on a client. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:ZSpawnForceCommand(client, argc) +{ + // If not enough arguments given, then stop. + if (argc < 1) + { + TranslationReplyToCommand(client, "ZSpawn command force syntax"); + return Plugin_Handled; + } + + decl String:target[MAX_NAME_LENGTH], String:targetname[MAX_NAME_LENGTH]; + new targets[MAXPLAYERS], bool:tn_is_ml, result; + + // Get targetname. + GetCmdArg(1, target, sizeof(target)); + + // Find a target. + result = ProcessTargetString(target, client, targets, sizeof(targets), COMMAND_FILTER_DEAD, targetname, sizeof(targetname), tn_is_ml); + + // Check if there was a problem finding a client. + if (result <= 0) + { + ZRReplyToTargetError(client, result); + return Plugin_Handled; + } + + // Get item to give to client. + decl String:strZombie[4]; + GetCmdArg(2, strZombie, sizeof(strZombie)); + + // Copy value of second (optional) parameter to 'zombie'. + // It will be false if the parameter wasn't specified. + new bool:zombie = bool:StringToInt(strZombie); + + // x = Client index. + for (new x = 0; x < result; x++) + { + // Give client the item. + new bool:success = ZSpawnClient(targets[x], true, zombie); + + // Tell admin the outcome of the command if only 1 client was targetted. + if (result == 1) + { + if (success) + { + TranslationReplyToCommand(client, "ZSpawn command force successful", targetname); + } + else + { + TranslationReplyToCommand(client, "ZSpawn command force unsuccessful", targetname); + } + } + } + + // Log action to game events. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_ZSpawn, "Force ZSpawn", "Admin \"%L\" forced player(s) to spawn. (zr_zspawn_force)", client); + + return Plugin_Handled; +} + /** * Timer callback, resets handle. * diff --git a/src/zr/ztele.inc b/src/zr/ztele.inc index e67118a..c7917e8 100644 --- a/src/zr/ztele.inc +++ b/src/zr/ztele.inc @@ -1,7 +1,7 @@ /* * ============================================================================ * - * Zombie:Reloaded + * Zombie:Reloaded * * File: ztele.inc * Type: Module @@ -55,8 +55,11 @@ new g_iZTeleTimeLeft[MAXPLAYERS + 1]; */ ZTeleOnCommandsCreate() { - // Register ZMenu command. + // Register ZTele command. RegConsoleCmd(SAYHOOKS_KEYWORD_ZTELE, ZTeleCommand, "Teleport back to spawn if you are stuck."); + + // Register admin command to force ZTele. + RegAdminCmd("zr_ztele_force", ZTeleForceCommand, ADMFLAG_GENERIC, "Force ZTele on a client. Usage: zr_ztele_force "); } /** @@ -131,9 +134,11 @@ ZTeleOnClientInfected(client) * Teleports a client back to spawn if conditions are met. * * @param client The client index. + * @param force (Optional) True to force teleporting of the client, false to follow rules. + * @param zombie (Optional) True to teleport instantly, false to use delay. * @return True if teleport was successful, false otherwise. */ -bool:ZTeleClient(client) +bool:ZTeleClient(client, bool:force = false) { // If the client is dead, then stop. if (!IsPlayerAlive(client)) @@ -145,7 +150,7 @@ bool:ZTeleClient(client) // If zombie cvar is disabled and the client is a zombie, then stop. new bool:ztelezombie = GetConVarBool(g_hCvarsList[CVAR_ZTELE_ZOMBIE]); - if (infected && !ztelezombie) + if (!force && infected && !ztelezombie) { // Tell client they must be human to use this feature. TranslationPrintToChat(client, "Must be human"); @@ -155,7 +160,7 @@ bool:ZTeleClient(client) // If zombie has spawned, get before value, get the after value otherwise. // If the cvar is disabled and the client is a human, then stop. new bool:ztelehuman = g_bZombieSpawned ? GetConVarBool(g_hCvarsList[CVAR_ZTELE_HUMAN_AFTER]) : GetConVarBool(g_hCvarsList[CVAR_ZTELE_HUMAN_BEFORE]); - if (!infected && !ztelehuman) + if (!force && !infected && !ztelehuman) { // Tell client that feature is restricted at this time. TranslationPrintToChat(client, "ZTele restricted human"); @@ -164,7 +169,7 @@ bool:ZTeleClient(client) // If the tele limit has been reached, then stop. new ztelemax = infected ? GetConVarInt(g_hCvarsList[CVAR_ZTELE_MAX_ZOMBIE]) : GetConVarInt(g_hCvarsList[CVAR_ZTELE_MAX_HUMAN]); - if (g_iZTeleCount[client] >= ztelemax) + if (!force && g_iZTeleCount[client] >= ztelemax) { // Tell client that they have already reached their limit. TranslationPrintToChat(client, "ZTele max", ztelemax); @@ -174,19 +179,26 @@ bool:ZTeleClient(client) // If teleport is already in progress, then stop. if (tZTele[client] != INVALID_HANDLE) { - TranslationPrintToChat(client, "ZTele in progress"); + if (!force) + { + TranslationPrintToChat(client, "ZTele in progress"); + } + return false; } + // If we are forcing, then teleport now and stop. + if (force) + { + // Teleport client to spawn. + ZTeleTeleportClient(client); + + return true; + } + // Get current location. GetClientAbsOrigin(client, g_vecZTeleOrigin[client]); - // If timer is running, kill it. - if (tZTele[client] != INVALID_HANDLE) - { - KillTimer(tZTele[client]); - } - // Set timeleft array to value of respective cvar. g_iZTeleTimeLeft[client] = infected ? GetConVarInt(g_hCvarsList[CVAR_ZTELE_DELAY_ZOMBIE]) : GetConVarInt(g_hCvarsList[CVAR_ZTELE_DELAY_HUMAN]); if (g_iZTeleTimeLeft[client] > 0) @@ -199,12 +211,10 @@ bool:ZTeleClient(client) } else { - // Reset timer handle. - tZTele[client] = INVALID_HANDLE; - // Teleport client to spawn. ZTeleTeleportClient(client); + // If we're forcing the ZTele, then don't increment the count or print how many teleports they have used. // Tell client they've been teleported. TranslationPrintCenterText(client, "ZTele countdown end", g_iZTeleCount[client], ztelemax); @@ -227,7 +237,119 @@ ZTeleTeleportClient(client) } /** - * Command callback (zmenu) + * Menu callback (ztele_force) + * Forces ZTele on a client. + * + * @param menu The menu handle. + * @param action Action client is doing in menu. + * @param client The client index. + * @param slot The menu slot selected. (starting from 0) + */ +public ZTeleForceHandle(Handle:menu_ztele_force, MenuAction:action, client, slot) +{ + // Client selected an option. + if (action == MenuAction_Select) + { + // Get the client index of the selected client. + new target = MenuGetClientIndex(menu_ztele_force, slot); + + // Get the target's name for future use. + decl String:targetname[MAX_NAME_LENGTH]; + GetClientName(target, targetname, sizeof(targetname)); + + // Force ZSpawn on the target. + new bool:success = ZTeleClient(target, true); + + // Tell admin the outcome of the action. + if (success) + { + TranslationReplyToCommand(client, "ZTele command force successful", targetname); + } + else + { + TranslationReplyToCommand(client, "ZTele command force unsuccessful", targetname); + } + + // Re-send the menu. + MenuClientList(client, ZTeleForceHandle, "ZTele clients title"); + } + // Client closed the menu. + if (action == MenuAction_Cancel) + { + // Client hit "Back" button. + if (slot == MenuCancel_ExitBack) + { + // Re-open admin menu. + ZAdminMenu(client); + } + } + // Client exited menu. + if (action == MenuAction_End) + { + CloseHandle(menu_ztele_force); + } +} + +/** + * Command callback (zr_ztele_force) + * Force ZSpawn on a client. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:ZTeleForceCommand(client, argc) +{ + // If not enough arguments given, then stop. + if (argc < 1) + { + TranslationReplyToCommand(client, "ZTele command force syntax"); + return Plugin_Handled; + } + + decl String:target[MAX_NAME_LENGTH], String:targetname[MAX_NAME_LENGTH]; + new targets[MAXPLAYERS], bool:tn_is_ml, result; + + // Get targetname. + GetCmdArg(1, target, sizeof(target)); + + // Find a target. + result = ProcessTargetString(target, client, targets, sizeof(targets), COMMAND_FILTER_ALIVE, targetname, sizeof(targetname), tn_is_ml); + + // Check if there was a problem finding a client. + if (result <= 0) + { + ZRReplyToTargetError(client, result); + return Plugin_Handled; + } + + // x = Client index. + for (new x = 0; x < result; x++) + { + // Give client the item. + new bool:success = ZTeleClient(targets[x], true); + + // Tell admin the outcome of the command if only 1 client was targetted. + if (result == 1) + { + if (success) + { + TranslationReplyToCommand(client, "ZTele command force successful", targetname); + } + else + { + TranslationReplyToCommand(client, "ZTele command force unsuccessful", targetname); + } + } + } + + // Log action to game events. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_ZTele, "Force ZTele", "Admin \"%L\" forced player(s) to teleport to spawn. (zr_ztele_force)", client); + + return Plugin_Handled; +} + +/** + * Command callback (ztele) * Teleport back to spawn if you are stuck. * * @param client The client index.