Don't like ads? PRO users don't see any ads ;-)
Guest

zp 4.3

By: a guest on Aug 12th, 2012  |  syntax: None  |  size: 337.15 KB  |  hits: 58  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. /*================================================================================
  2.        
  3.                 *****************************************************
  4.                 ************** [Zombie Plague Mod 4.3] **************
  5.                 *****************************************************
  6.        
  7.         ----------------------
  8.         -*- Licensing Info -*-
  9.         ----------------------
  10.        
  11.         Zombie Plague Mod
  12.         Copyright (C) 2008-2009 by MeRcyLeZZ
  13.        
  14.         This program is free software: you can redistribute it and/or modify
  15.         it under the terms of the GNU General Public License as published by
  16.         the Free Software Foundation, either version 3 of the License, or
  17.         (at your option) any later version.
  18.        
  19.         This program is distributed in the hope that it will be useful,
  20.         but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22.         GNU General Public License for more details.
  23.        
  24.         You should have received a copy of the GNU General Public License
  25.         along with this program.  If not, see <http://www.gnu.org/licenses/>.
  26.        
  27.         In addition, as a special exception, the author gives permission to
  28.         link the code of this program with the Half-Life Game Engine ("HL
  29.         Engine") and Modified Game Libraries ("MODs") developed by Valve,
  30.         L.L.C ("Valve"). You must obey the GNU General Public License in all
  31.         respects for all of the code used other than the HL Engine and MODs
  32.         from Valve. If you modify this file, you may extend this exception
  33.         to your version of the file, but you are not obligated to do so. If
  34.         you do not wish to do so, delete this exception statement from your
  35.         version.
  36.        
  37.         -------------------
  38.         -*- Description -*-
  39.         -------------------
  40.        
  41.         Zombie Plague is a Counter-Strike server side modification, developed as
  42.         an AMX Mod X plugin, which completely revamps the gameplay, turning the
  43.         game into an intense "Humans vs Zombies" survival experience.
  44.        
  45.         Even though it's strongly based on the classic zombie infection mods, it
  46.         takes the concept to a new level by introducing:
  47.        
  48.         * New Gameplay Modes: Nemesis, Survivor, Multi Infection, Swarm, Plague
  49.         * Zombie Classes System: allows addding unlimited custom zombie classes
  50.         * Ammo Packs: awarded to skilled players, can be exchanged for goods
  51.         * Extra Items System: allows adding unlimited custom items to buy
  52.         * Custom Grenades: Napalms, Frost Nades, Flares, and Infection Bombs
  53.         * Deathmatch Mode: where zombies or humans can continually respawn
  54.         * Admin Menus: to easily perform the included console commands
  55.         * Special Effects: from the HL Engine, such as dynamic lighting and fog
  56.        
  57.         There is plenty of customization as well, which enables you to create
  58.         several different styles of gameplay. You can:
  59.        
  60.         * Set zombies and humans' health, speed, models, rewards, and more
  61.         * Toggle unlimited ammo and adjustable knockback for weapons
  62.         * Separately enable and customize the new gameplay modes to your liking
  63.         * Change overall map lighting (lightnings available for the dark settings)
  64.         * Set different colors and sizes for flashlight and nightvision
  65.         * Toggle leap (long jumping) and pain shock free (no damage slowdowns)
  66.         * Toggle various infection effects, such as sparks and screen shakes
  67.         * Enable random spawning (CSDM-spawn friendly)
  68.         * Replace sounds or add some background themes
  69.         * And many more...
  70.        
  71.         -------------
  72.         -*- Media -*-
  73.         -------------
  74.        
  75.         * Gameplay Video 1: http://www.youtube.com/watch?v=HFUyF7-_uzw
  76.         * Gameplay Video 2: http://www.youtube.com/watch?v=XByif6Mti-w
  77.        
  78.         --------------------
  79.         -*- Requirements -*-
  80.         --------------------
  81.        
  82.         * Mods: Counter-Strike 1.6 or Condition-Zero
  83.         * AMXX: Version 1.8.0 or later
  84.        
  85.         --------------------
  86.         -*- Installation -*-
  87.         --------------------
  88.        
  89.         Extract the contents from the .zip file to your server's mod directory
  90.         ("cstrike" or "czero"). Make sure to keep folder structure.
  91.        
  92.         -----------------------
  93.         -*- Official Forums -*-
  94.         -----------------------
  95.        
  96.         For the official Zombie Plague forums visit:
  97.         http://forums.alliedmods.net/forumdisplay.php?f=126
  98.        
  99.         There you can:
  100.        
  101.         * Get the latest releases and early betas
  102.         * Discuss new features and suggestions
  103.         * Share sub-plugins (expansions) for the mod
  104.         * Find the support and help you need
  105.         * Report any bugs you might find
  106.         * And all that sort of stuff...
  107.        
  108.         -------------------------------
  109.         -*- CVARS and Customization -*-
  110.         -------------------------------
  111.        
  112.         For a complete and in-depth cvar list, look at the zombieplague.cfg file
  113.         located in the amxmodx\configs directory.
  114.        
  115.         Additionally, you can change player models, sounds, weather effects,
  116.         and some other stuff from the configuration file zombieplague.ini.
  117.        
  118.         As for editing attributes of zombie classes or custom extra items, you'll
  119.         find a zp_zombieclasses.ini and zp_extraitems.ini. These files will be
  120.         automatically updated as you install new custom classes or items with
  121.         new entries for you to edit conveniently.
  122.        
  123.         ---------------
  124.         -*- History -*-
  125.         ---------------
  126.        
  127.         This project started back on late 2007, when the free infection mods
  128.         around were quite buggy and I wanted to make one on my own. With little
  129.         to no experience at AMXX scripting, I had to start from the very scratch.
  130.        
  131.         Not after spending over a week looking at many plugins (mainly Zombie
  132.         Swarm) and scarce tutorials, I somehow managed to have all the basic
  133.         stuff working quite well (even though the code was a real mess). The
  134.         following months were spent polishing things up and trying to fulfill
  135.         new original ideas, most of them quite worth the hard work.
  136.        
  137.         In the meantime, I got the chance to try the plugin out on a 32 man
  138.         server. This meant a huge progress on development, and after lots of
  139.         testing and bug fixing, the mod turned out to be more than the simple
  140.         infection plugin I had originally planned it to be.
  141.        
  142.         The project has come a long way since, and I'm glad to say I'm finally
  143.         making it freely available. All I'm asking in return is to keep my
  144.         name in the plugin.
  145.        
  146.         -Enjoy!
  147.        
  148.         ----------------------
  149.         -*- Infection Mode -*-
  150.         ----------------------
  151.        
  152.         On every round players start out as humans, equip themselves with a few
  153.         weapons and grenades, and head to the closest cover they find, knowing
  154.         that one of them is infected with the T-Virus, and will suddenly turn
  155.         into a vicious brain eating creature.
  156.        
  157.         Only little time after, the battle for survival begins. The first zombie
  158.         has to infect as many humans as possible to cluster a numerous zombie
  159.         horde and take over the world.
  160.        
  161.         Maps are set in the dark by default. Humans must use flashlights to light
  162.         their way and spot any enemies. Zombies, on the other hand, have night
  163.         vision but can only attack melee.
  164.        
  165.         --------------------------
  166.         -*- New Gameplay Modes -*-
  167.         --------------------------
  168.        
  169.         * Nemesis:
  170.            The first zombie may turn into a Nemesis, a powerful fast-moving
  171.            beast. His goal is to kill every human while sustaining the gunfire.
  172.        
  173.         * Survivor:
  174.            Everyone became a zombie except him. The survivor gets a machinegun
  175.            with unlimited ammo and has to stop the never-ending army of undead.
  176.        
  177.         * Multiple Infection:
  178.            The round starts with many humans infected, so the remaining players
  179.            will have to act quickly in order to control the situation.
  180.        
  181.         * Swarm Mode:
  182.            Half of the players turn into zombies, the rest become immune and
  183.            cannot be infected. It's a battle to death.
  184.        
  185.         * Plague Mode: [bonus]
  186.            A full armed Survivor and his soldiers are to face Nemesis and
  187.            his zombie minions. The future of the world is in their hands.
  188.        
  189.         --------------------
  190.         -*- In-Game Menu -*-
  191.         --------------------
  192.        
  193.         Players can access the mod menu by typing "zpmenu" on chat, or by
  194.         pressing the M ("chooseteam") key. The menu allows players to choose
  195.         their zombie class, buy extra items, get unstuck, or see the ingame
  196.         help. Admins will find an additional option to easily perform all
  197.         console commands.
  198.        
  199.         ----------------------
  200.         -*- Admin Commands -*-
  201.         ----------------------
  202.        
  203.         The following console commands are available:
  204.        
  205.         * zp_zombie <target> - Turn someone into a Zombie
  206.         * zp_human <target> - Turn someone back to Human
  207.         * zp_nemesis <target> - Turn someone into a Nemesis
  208.         * zp_survivor <target> - Turn someone into a Survivor
  209.         * zp_respawn <target> - Respawn someone
  210.         * zp_swarm - Start Swarm Mode (*)
  211.         * zp_multi - Start Multi Infection (*)
  212.         * zp_plague - Start Plague Mode (*)
  213.        
  214.         (*) - These commands can only be used at round start, that is, when the
  215.         T-Virus notice is shown on screen.
  216.        
  217.         ------------------
  218.         -*- Plugin API -*-
  219.         ------------------
  220.        
  221.         From version 3.6, some natives and forwards have been added to ease the
  222.         development of sub-plugins, though you may also find them useful to work
  223.         out compatibility issues with existing plugins.
  224.        
  225.         Look for the zombieplague.inc file in your amxmodx\scripting\include
  226.         folder for the full documented list.
  227.        
  228.         ----------------------
  229.         -*- Zombie Classes -*-
  230.         ----------------------
  231.        
  232.         From version 4.0 it is possible to create and add an unlimited number of
  233.         zombie classes to the main mod. They can be made as separate plugins,
  234.         by using the provided zombie class API, and easily distributed.
  235.        
  236.         By default, five zombie classes are included:
  237.        
  238.         * Classic Zombie: well balanced zombie for beginners.
  239.         * Raptor Zombie: fast moving zombie, but also the weakest.
  240.         * Poison Zombie: light weighed zombie, jumps higher.
  241.         * Big Zombie: slow but strong zombie, with lots of hit points.
  242.         * Leech Zombie: regains additional health when infecting.
  243.        
  244.         -------------------
  245.         -*- Extra Items -*-
  246.         -------------------
  247.        
  248.         From version 4.0 it is possible to add an unlimited number of items
  249.         which can be purchased through the Extra Items menu. All you need
  250.         to do is use the provided item registration natives on your custom
  251.         plugins. You can set the name, the cost in ammo packs, and the team
  252.         the extra item should be available for.
  253.        
  254.         By default there is a number of items already included, listed here:
  255.        
  256.         * Night Vision: makes you able to see in the dark for a single round [Human]
  257.         * T-Virus Antidote: makes you turn back to your human form [Zombie]
  258.         * Zombie Madness: you develop a powerful shield for a short time [Zombie]
  259.         * Infection Bomb: infects anyone within its explosion radius [Zombie]
  260.        
  261.         You are also able to choose some weapons to act as extra items, and change
  262.         ammo packs costs in the customization file (zombieplague.ini).
  263.        
  264.         ---------------
  265.         -*- Credits -*-
  266.         ---------------
  267.        
  268.         * AMXX Dev Team: for all the hard work which made this possible
  269.         * Imperio LNJ Community: for providing the first server where I
  270.            could really test the plugin and for everyone's support
  271.         * Mini_Midget: for his Zombie Swarm plugin which I used for reference
  272.            on earliest stages of development
  273.         * Avalanche: for the random spawning code I got from GunGame and the
  274.            original Frostnades concept that I ported in here
  275.         * cheap_suit: for some modelchange and knockback codes that I got from
  276.            Biohazard
  277.         * Simon Logic/ConnorMcLeod: for the Pain Shock Free feature
  278.         * KRoT@L: for some code from Follow the Wounded, used to make the zombie
  279.            bleeding feature
  280.         * VEN: for Fakemeta Utilities and some useful stocks
  281.         * RaaPuar and Goltark: for the custom grenade models
  282.         * Orangutanz: for finding the precached modelindex offset
  283.         * ML Translations: DKs/nunoabc/DarkMarcos (bp), JahMan/KWo (pl), DA (de),
  284.            Zombie Lurker (ls), DoPe^ (da), k1nny (fr), NeWbiE' (cz), skymoon (tc),
  285.            SUPER MATRIX/Shidla/zDemon/4eRT (ru), zsy314 (cn), lOlIl/Seehank (sk),
  286.            Bridgestone (sv), crazyeffect.net/Mave/Wesley (nl), hleV/aaarnas (lt),
  287.            darkbad945 (bg), decongamco (vn), beckham9224 (mn), TehGeorge (gr),
  288.            shadoww_ro/tuty/georgik57/EastSider (ro)
  289.         * Beta testers: for all the feedback, bug reports, and suggestions which
  290.            constantly help improve this mod further
  291.         * And to all zombie-mod supporters out there!
  292.        
  293.         -----------------
  294.         -*- Changelog -*-
  295.         -----------------
  296.        
  297.         * v1.0: (Dec 2007)
  298.            - First Release: most of the basic stuff done.
  299.            - Added: random spawning, HP display on hud, lighting setting,
  300.               simple buy menu, custom nightvision, admin commands, Nemesis
  301.               and Survivor modes, glow and leap settings for them.
  302.        
  303.         * v2.2: (Jan 2008)
  304.            - Added: zombie classes, ammo packs system, buying ammo for weapons,
  305.               custom flashlight, admin skins setting, zombieplague.cfg file
  306.            - Upgraded: weapons menu improved, flashlight and nightvision colors
  307.               now customizable, HamSandwich module used to handle damage.
  308.            - Fixed various bugs.
  309.        
  310.         * v3.0: (Mar 2008)
  311.            - Added: door removal setting, unstuck feature, human cvars, armor
  312.               cvar for zombies, weapon knockback, zombie bleeding, flares,
  313.               extra items (weapons, antidote, infection bomb), pain shock
  314.               free setting, Multiple Infection and Swarm modes.
  315.            - Upgraded: dumped Engine, Fun and Cstrike modules, code optimized,
  316.               new model change method, new gfx effects for zombie infections.
  317.            - Fixed a bunch of gameplay bugs.
  318.        
  319.         * v3.5: (May 2008)
  320.            - Added: deathmatch setting with spawn protection, unlimited ammo
  321.               setting, fire and frost grenades, additional customization cvars,
  322.               new extra items, help menu.
  323.            - Upgraded: better objectives removal method, dropped weapons now
  324.               keep their bpammo, code optimized a lot.
  325.            - Fixed: no more game commencing bug when last zombie/human leaves,
  326.               no more hegrenade infection bug, reduced svc_bad errors, and
  327.               many more.
  328.        
  329.         * v3.6: (Jun 2008)
  330.            - Added: a few natives and forwards for sub-plugins support,
  331.               zombie classes can now have their own models, additional
  332.               knockback customization, bot support, various CVARs.
  333.            - Upgraded: extra items now supporting grenades and pistols, changed
  334.               bomb removal method, players can join on survivor/swarm rounds,
  335.               extended lightnings support to other dark settings.
  336.            - Fixed: a bunch of minor bugs, and a server crash with CZ bots.
  337.        
  338.         * v4.0: (Aug 2008)
  339.            - Added: new gameplay mode (Plague Mode), option to remember weapon
  340.               selection, command to enable/disable the plugin, more CVARs.
  341.            - Upgraded: redid all the menus, extra items and zombie classes now
  342.               support external additions, survivor can now have its own model,
  343.               upgraded model changing method.
  344.            - Fixed: some bugs with bots, win sounds not being precached.
  345.        
  346.         * v4.1: (Oct 2008)
  347.            - Added: more CVARs, more customization, more natives, custom
  348.               leap system, admin zombie models support, and more.
  349.            - Upgraded: custom grenades compatible with Nade Modes, ambience
  350.               sounds specific game mode support, optimized bandwidth usage
  351.               for temp ents, admin commands logged with IP and SteamID.
  352.            - Fixed: lots of bugs (some minor, some not)
  353.        
  354.         * v4.2: (Feb 2009)
  355.            - Added various CVARs for customization, improved prevention of
  356.               svc_bad in some cases, optimized ammo handling code.
  357.            - Fixed server crash with 'msg 35 has not been sent yet' error,
  358.               fixed client overflow issues with ambience sounds, resolved
  359.               many gameplay bugs.
  360.        
  361.         * v4.3: (Apr 2009)
  362.            - Customization settings can now be edited through external files,
  363.               added support for global and multiple random zombie models,
  364.               added even more CVARs for tweaking stuff, extended admin commands'
  365.               functionality, greatly extended API capabilities, implemented a
  366.               more efficient Pain Shock Free code, reworked some menus.
  367.            - Fixed pretty much all reported bugs to the date.
  368.        
  369. =================================================================================*/
  370.  
  371. /*================================================================================
  372.  [Plugin Customization]
  373. =================================================================================*/
  374.  
  375. // All customization settings have been moved
  376. // to external files to allow easier editing
  377. new const ZP_CUSTOMIZATION_FILE[] = "zombieplague.ini"
  378. new const ZP_EXTRAITEMS_FILE[] = "zp_extraitems.ini"
  379. new const ZP_ZOMBIECLASSES_FILE[] = "zp_zombieclasses.ini"
  380.  
  381. // Limiters for stuff not worth making dynamic arrays out of (increase if needed)
  382. const MAX_CSDM_SPAWNS = 128
  383. const MAX_STATS_SAVED = 64
  384.  
  385. /*================================================================================
  386.  Customization ends here! Yes, that's it. Editing anything beyond
  387.  here is not officially supported. Proceed at your own risk...
  388. =================================================================================*/
  389.  
  390. #include <amxmodx>
  391. #include <amxmisc>
  392. #include <cstrike>
  393. #include <fakemeta>
  394. #include <hamsandwich>
  395. #include <xs>
  396.  
  397. /*================================================================================
  398.  [Constants, Offsets, Macros]
  399. =================================================================================*/
  400.  
  401. // Plugin Version
  402. new const PLUGIN_VERSION[] = "4.3"
  403.  
  404. // Customization file sections
  405. enum
  406. {
  407.         SECTION_NONE = 0,
  408.         SECTION_ACCESS_FLAGS,
  409.         SECTION_PLAYER_MODELS,
  410.         SECTION_WEAPON_MODELS,
  411.         SECTION_GRENADE_SPRITES,
  412.         SECTION_SOUNDS,
  413.         SECTION_AMBIENCE_SOUNDS,
  414.         SECTION_BUY_MENU_WEAPONS,
  415.         SECTION_EXTRA_ITEMS_WEAPONS,
  416.         SECTION_HARD_CODED_ITEMS_COSTS,
  417.         SECTION_WEATHER_EFFECTS,
  418.         SECTION_SKY,
  419.         SECTION_LIGHTNING,
  420.         SECTION_ZOMBIE_DECALS,
  421.         SECTION_KNOCKBACK,
  422.         SECTION_OBJECTIVE_ENTS,
  423.         SECTION_SVC_BAD
  424. }
  425.  
  426. // Access flags
  427. enum
  428. {
  429.         ACCESS_ENABLE_MOD = 0,
  430.         ACCESS_ADMIN_MENU,
  431.         ACCESS_MODE_INFECTION,
  432.         ACCESS_MODE_NEMESIS,
  433.         ACCESS_MODE_SURVIVOR,
  434.         ACCESS_MODE_SWARM,
  435.         ACCESS_MODE_MULTI,
  436.         ACCESS_MODE_PLAGUE,
  437.         ACCESS_MAKE_ZOMBIE,
  438.         ACCESS_MAKE_HUMAN,
  439.         ACCESS_MAKE_NEMESIS,
  440.         ACCESS_MAKE_SURVIVOR,
  441.         ACCESS_RESPAWN_PLAYERS,
  442.         ACCESS_ADMIN_MODELS,
  443.         MAX_ACCESS_FLAGS
  444. }
  445.  
  446. // Task offsets
  447. enum (+= 100)
  448. {
  449.         TASK_MODEL = 2000,
  450.         TASK_TEAM,
  451.         TASK_SPAWN,
  452.         TASK_BLOOD,
  453.         TASK_AURA,
  454.         TASK_BURN,
  455.         TASK_NVISION,
  456.         TASK_FLASH,
  457.         TASK_CHARGE,
  458.         TASK_SHOWHUD,
  459.         TASK_MAKEZOMBIE,
  460.         TASK_WELCOMEMSG,
  461.         TASK_THUNDER_PRE,
  462.         TASK_THUNDER,
  463.         TASK_AMBIENCESOUNDS
  464. }
  465.  
  466. // IDs inside tasks
  467. #define ID_MODEL (taskid - TASK_MODEL)
  468. #define ID_TEAM (taskid - TASK_TEAM)
  469. #define ID_SPAWN (taskid - TASK_SPAWN)
  470. #define ID_BLOOD (taskid - TASK_BLOOD)
  471. #define ID_AURA (taskid - TASK_AURA)
  472. #define ID_BURN (taskid - TASK_BURN)
  473. #define ID_NVISION (taskid - TASK_NVISION)
  474. #define ID_FLASH (taskid - TASK_FLASH)
  475. #define ID_CHARGE (taskid - TASK_CHARGE)
  476. #define ID_SHOWHUD (taskid - TASK_SHOWHUD)
  477.  
  478. // BP Ammo Refill task
  479. #define REFILL_WEAPONID args[0]
  480.  
  481. // For weapon buy menu handlers
  482. #define WPN_STARTID g_menu_data[id][1]
  483. #define WPN_MAXIDS ArraySize(g_primary_items)
  484. #define WPN_SELECTION (g_menu_data[id][1]+key)
  485. #define WPN_AUTO_ON g_menu_data[id][2]
  486. #define WPN_AUTO_PRI g_menu_data[id][3]
  487. #define WPN_AUTO_SEC g_menu_data[id][4]
  488.  
  489. // For player list menu handlers
  490. #define PL_ACTION g_menu_data[id][0]
  491.  
  492. // For extra items menu handlers
  493. #define EXTRAS_CUSTOM_STARTID (EXTRA_WEAPONS_STARTID + ArraySize(g_extraweapon_names))
  494.  
  495. // Menu selections
  496. const MENU_KEY_AUTOSELECT = 7
  497. const MENU_KEY_BACK = 7
  498. const MENU_KEY_NEXT = 8
  499. const MENU_KEY_EXIT = 9
  500.  
  501. // Hard coded extra items
  502. enum
  503. {
  504.         EXTRA_NVISION = 0,
  505.         EXTRA_ANTIDOTE,
  506.         EXTRA_MADNESS,
  507.         EXTRA_INFBOMB,
  508.         EXTRA_WEAPONS_STARTID
  509. }
  510.  
  511. // Game modes
  512. enum
  513. {
  514.         MODE_NONE = 0,
  515.         MODE_INFECTION,
  516.         MODE_NEMESIS,
  517.         MODE_SURVIVOR,
  518.         MODE_SWARM,
  519.         MODE_MULTI,
  520.         MODE_PLAGUE
  521. }
  522.  
  523. // ZP Teams
  524. const ZP_TEAM_NO_ONE = 0
  525. const ZP_TEAM_ANY = 0
  526. const ZP_TEAM_ZOMBIE = (1<<0)
  527. const ZP_TEAM_HUMAN = (1<<1)
  528. const ZP_TEAM_NEMESIS = (1<<2)
  529. const ZP_TEAM_SURVIVOR = (1<<3)
  530. new const ZP_TEAM_NAMES[][] = { "ZOMBIE , HUMAN", "ZOMBIE", "HUMAN", "ZOMBIE , HUMAN", "NEMESIS",
  531.                         "ZOMBIE , NEMESIS", "HUMAN , NEMESIS", "ZOMBIE , HUMAN , NEMESIS",
  532.                         "SURVIVOR", "ZOMBIE , SURVIVOR", "HUMAN , SURVIVOR", "ZOMBIE , HUMAN , SURVIVOR",
  533.                         "NEMESIS , SURVIVOR", "ZOMBIE , NEMESIS , SURVIVOR", "HUMAN, NEMESIS, SURVIVOR",
  534.                         "ZOMBIE , HUMAN , NEMESIS , SURVIVOR" }
  535.  
  536. // Zombie classes
  537. const ZCLASS_NONE = -1
  538.  
  539. // HUD messages
  540. const Float:HUD_EVENT_X = -1.0
  541. const Float:HUD_EVENT_Y = 0.17
  542. const Float:HUD_INFECT_X = 0.05
  543. const Float:HUD_INFECT_Y = 0.45
  544. const Float:HUD_SPECT_X = 0.6
  545. const Float:HUD_SPECT_Y = 0.8
  546. const Float:HUD_STATS_X = 0.01
  547. const Float:HUD_STATS_Y = 0.23
  548.  
  549. // CS Player PData Offsets (win32)
  550. const OFFSET_PAINSHOCK = 108 // ConnorMcLeod
  551. const OFFSET_CSTEAMS = 114
  552. const OFFSET_CSMONEY = 115
  553. const OFFSET_FLASHLIGHT_BATTERY = 244
  554. const OFFSET_CSDEATHS = 444
  555. const OFFSET_MODELINDEX = 491 // Orangutanz
  556.  
  557. // CS Player CBase Offsets (win32)
  558. const OFFSET_ACTIVE_ITEM = 373
  559.  
  560. // CS Weapon CBase Offsets (win32)
  561. const OFFSET_WEAPONOWNER = 41
  562.  
  563. // Linux diff's
  564. const OFFSET_LINUX = 5 // offsets 5 higher in Linux builds
  565. const OFFSET_LINUX_WEAPONS = 4 // weapon offsets are only 4 steps higher on Linux
  566.  
  567. // CS Teams
  568. enum
  569. {
  570.         FM_CS_TEAM_UNASSIGNED = 0,
  571.         FM_CS_TEAM_T,
  572.         FM_CS_TEAM_CT,
  573.         FM_CS_TEAM_SPECTATOR
  574. }
  575. new const CS_TEAM_NAMES[][] = { "UNASSIGNED", "TERRORIST", "CT", "SPECTATOR" }
  576.  
  577. // Some constants
  578. const HIDE_MONEY = (1<<5)
  579. const UNIT_SECOND = (1<<12)
  580. const DMG_HEGRENADE = (1<<24)
  581. const IMPULSE_FLASHLIGHT = 100
  582. const USE_USING = 2
  583. const USE_STOPPED = 0
  584. const STEPTIME_SILENT = 999
  585. const BREAK_GLASS = 0x01
  586. const FFADE_IN = 0x0000
  587. const FFADE_STAYOUT = 0x0004
  588. const PEV_SPEC_TARGET = pev_iuser2
  589.  
  590. // Max BP ammo for weapons
  591. new const MAXBPAMMO[] = { -1, 52, -1, 90, 1, 32, 1, 100, 90, 1, 120, 100, 100, 90, 90, 90, 100, 120,
  592.                         30, 120, 200, 32, 90, 120, 90, 2, 35, 90, 90, -1, 100 }
  593.  
  594. // Max Clip for weapons
  595. new const MAXCLIP[] = { -1, 13, -1, 10, -1, 7, -1, 30, 30, -1, 30, 20, 25, 30, 35, 25, 12, 20,
  596.                         10, 30, 100, 8, 30, 30, 20, -1, 7, 30, 30, -1, 50 }
  597.  
  598. // Amount of ammo to give when buying additional clips for weapons
  599. new const BUYAMMO[] = { -1, 13, -1, 30, -1, 8, -1, 12, 30, -1, 30, 50, 12, 30, 30, 30, 12, 30,
  600.                         10, 30, 30, 8, 30, 30, 30, -1, 7, 30, 30, -1, 50 }
  601.  
  602. // Ammo IDs for weapons
  603. new const AMMOID[] = { -1, 9, -1, 2, 12, 5, 14, 6, 4, 13, 10, 7, 6, 4, 4, 4, 6, 10,
  604.                         1, 10, 3, 5, 4, 10, 2, 11, 8, 4, 2, -1, 7 }
  605.  
  606. // Ammo Type Names for weapons
  607. new const AMMOTYPE[][] = { "", "357sig", "", "762nato", "", "buckshot", "", "45acp", "556nato", "", "9mm", "57mm", "45acp",
  608.                         "556nato", "556nato", "556nato", "45acp", "9mm", "338magnum", "9mm", "556natobox", "buckshot",
  609.                         "556nato", "9mm", "762nato", "", "50ae", "556nato", "762nato", "", "57mm" }
  610.  
  611. // Weapon IDs for ammo types
  612. new const AMMOWEAPON[] = { 0, CSW_AWP, CSW_SCOUT, CSW_M249, CSW_AUG, CSW_XM1014, CSW_MAC10, CSW_FIVESEVEN, CSW_DEAGLE,
  613.                         CSW_P228, CSW_ELITE, CSW_FLASHBANG, CSW_HEGRENADE, CSW_SMOKEGRENADE, CSW_C4 }
  614.  
  615. // Primary and Secondary Weapon Names
  616. new const WEAPONNAMES[][] = { "", "\yP228 Compact", "", "\ySchmidt Scout", "", "\rXM1014 M4", "", "\rIngram MAC-10", "\rSteyr AUG A1",
  617.                         "", "\rDual Elite Berettas", "\rFiveseveN", "\rUMP 45", "\rSG-550 Auto-Sniper", "\rIMI Galil", "\rFamas",
  618.                         "\rUSP .45 ACP Tactical", "\rGlock 18C", "\rAWP Magnum Sniper", "\rMP5 Navy", "\rM249 Para Machinegun",
  619.                         "\rM3 Super 90", "\rM4A1 Carbine", "\rSchmidt TMP", "\rG3SG1 Auto-Sniper", "", "\rDesert Eagle .50 AE",
  620.                         "\rSG-552 Commando", "\rAK-47 Kalashnikov", "", "\rES P90" }
  621.  
  622. // Weapon entity names
  623. new const WEAPONENTNAMES[][] = { "", "weapon_p228", "", "weapon_scout", "weapon_hegrenade", "weapon_xm1014", "weapon_c4", "weapon_mac10",
  624.                         "weapon_aug", "weapon_smokegrenade", "weapon_elite", "weapon_fiveseven", "weapon_ump45", "weapon_sg550",
  625.                         "weapon_galil", "weapon_famas", "weapon_usp", "weapon_glock18", "weapon_awp", "weapon_mp5navy", "weapon_m249",
  626.                         "weapon_m3", "weapon_m4a1", "weapon_tmp", "weapon_g3sg1", "weapon_flashbang", "weapon_deagle", "weapon_sg552",
  627.                         "weapon_ak47", "weapon_knife", "weapon_p90" }
  628.  
  629. // CS sounds
  630. new const sound_flashlight[] = "items/flashlight1.wav"
  631. new const sound_buyammo[] = "items/9mmclip1.wav"
  632. new const sound_armorhit[] = "player/bhit_helmet-1.wav"
  633.  
  634. // Explosion radius for custom grenades
  635. const Float:NADE_EXPLOSION_RADIUS = 240.0
  636.  
  637. // HACK: pev_ field used to store additional ammo on weapons
  638. const PEV_ADDITIONAL_AMMO = pev_iuser1
  639.  
  640. // HACK: pev_ field used to store custom nade types and their values
  641. const PEV_NADE_TYPE = pev_flTimeStepSound
  642. const NADE_TYPE_INFECTION = 1111
  643. const NADE_TYPE_NAPALM = 2222
  644. const NADE_TYPE_FROST = 3333
  645. const NADE_TYPE_FLARE = 4444
  646. const PEV_FLARE_COLOR = pev_punchangle
  647. const PEV_FLARE_DURATION = pev_flSwimTime
  648.  
  649. // Weapon bitsums
  650. const PRIMARY_WEAPONS_BIT_SUM = (1<<CSW_SCOUT)|(1<<CSW_XM1014)|(1<<CSW_MAC10)|(1<<CSW_AUG)|(1<<CSW_UMP45)|(1<<CSW_SG550)|(1<<CSW_GALIL)|(1<<CSW_FAMAS)|(1<<CSW_AWP)|(1<<CSW_MP5NAVY)|(1<<CSW_M249)|(1<<CSW_M3)|(1<<CSW_M4A1)|(1<<CSW_TMP)|(1<<CSW_G3SG1)|(1<<CSW_SG552)|(1<<CSW_AK47)|(1<<CSW_P90)
  651. const SECONDARY_WEAPONS_BIT_SUM = (1<<CSW_P228)|(1<<CSW_ELITE)|(1<<CSW_FIVESEVEN)|(1<<CSW_USP)|(1<<CSW_GLOCK18)|(1<<CSW_DEAGLE)
  652.  
  653. // Allowed weapons for zombies (added grenades/bomb for sub-plugin support, since they shouldn't be getting them anyway)
  654. const ZOMBIE_ALLOWED_WEAPONS_BITSUM = (1<<CSW_KNIFE)|(1<<CSW_HEGRENADE)|(1<<CSW_FLASHBANG)|(1<<CSW_SMOKEGRENADE)|(1<<CSW_C4)
  655.  
  656. // Classnames for separate model entities
  657. new const MODEL_ENT_CLASSNAME[] = "player_model"
  658. new const WEAPON_ENT_CLASSNAME[] = "weapon_model"
  659.  
  660. // Menu keys
  661. const KEYSMENU = MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MENU_KEY_8|MENU_KEY_9|MENU_KEY_0
  662.  
  663. // Ambience Sounds
  664. enum
  665. {
  666.         AMBIENCE_SOUNDS_INFECTION = 0,
  667.         AMBIENCE_SOUNDS_NEMESIS,
  668.         AMBIENCE_SOUNDS_SURVIVOR,
  669.         AMBIENCE_SOUNDS_SWARM,
  670.         AMBIENCE_SOUNDS_PLAGUE,
  671.         MAX_AMBIENCE_SOUNDS
  672. }
  673.  
  674. // Admin menu actions
  675. enum
  676. {
  677.         ACTION_ZOMBIEFY_HUMANIZE = 0,
  678.         ACTION_MAKE_NEMESIS,
  679.         ACTION_MAKE_SURVIVOR,
  680.         ACTION_RESPAWN_PLAYER,
  681.         ACTION_MODE_SWARM,
  682.         ACTION_MODE_MULTI,
  683.         ACTION_MODE_PLAGUE
  684. }
  685.  
  686. // Custom forward return values
  687. const ZP_PLUGIN_HANDLED = 97
  688.  
  689. /*================================================================================
  690.  [Global Variables]
  691. =================================================================================*/
  692.  
  693. // Player vars
  694. new g_zombie[33] // is zombie
  695. new g_nemesis[33] // is nemesis
  696. new g_survivor[33] // is survivor
  697. new g_firstzombie[33] // is first zombie
  698. new g_lastzombie[33] // is last zombie
  699. new g_lasthuman[33] // is last human
  700. new g_frozen[33] // is frozen (can't move)
  701. new g_nodamage[33] // has spawn protection/zombie madness
  702. new g_respawn_as_zombie[33] // should respawn as zombie
  703. new g_nvision[33] // has night vision
  704. new g_nvisionenabled[33] // has night vision turned on
  705. new g_zombieclass[33] // zombie class
  706. new g_zombieclassnext[33] // zombie class for next infection
  707. new g_flashlight[33] // has custom flashlight turned on
  708. new g_flashbattery[33] = { 100, ... } // custom flashlight battery
  709. new g_canbuy[33] // is allowed to buy a new weapon through the menu
  710. new g_ammopacks[33] // ammo pack count
  711. new g_damagedealt[33] // damage dealt to zombies (used to calculate ammo packs reward)
  712. new Float:g_lastleaptime[33] // time leap was last used
  713. new Float:g_lastflashtime[33] // time flashlight was last toggled
  714. new g_playermodel[33][32] // current model's short name [player][model]
  715. new g_menu_data[33][5] // data for some menu handlers
  716. new g_ent_playermodel[33] // player model entity
  717. new g_ent_weaponmodel[33] // weapon model entity
  718. new g_burning_duration[33] // burning task duration
  719.  
  720. // Game vars
  721. new g_pluginenabled // ZP enabled
  722. new g_newround // new round starting
  723. new g_endround // round ended
  724. new g_nemround // nemesis round
  725. new g_survround // survivor round
  726. new g_swarmround // swarm round
  727. new g_plagueround // plague round
  728. new g_modestarted // mode fully started
  729. new g_lastmode // last played mode
  730. new g_scorezombies, g_scorehumans // team scores
  731. new g_spawnCount, g_spawnCount2 // available spawn points counter
  732. new Float:g_spawns[MAX_CSDM_SPAWNS][3], Float:g_spawns2[MAX_CSDM_SPAWNS][3] // spawn points data
  733. new g_lights_i // lightning current lights counter
  734. new g_lights_cycle[32] // current lightning cycle
  735. new g_lights_cycle_len // lightning cycle length
  736. new Float:g_models_targettime // for adding delays between Model Change messages
  737. new Float:g_teams_targettime // for adding delays between Team Change messages
  738. new g_MsgSync, g_MsgSync2 // message sync objects
  739. new g_trailSpr, g_exploSpr, g_flameSpr, g_smokeSpr, g_glassSpr // grenade sprites
  740. new g_modname[32] // for formatting the mod name
  741. new g_freezetime // whether CS's freeze time is on
  742. new g_maxplayers // max players counter
  743. new g_czero // whether we are running on a CZ server
  744. new g_hamczbots // whether ham forwards are registered for CZ bots
  745. new g_fwSpawn, g_fwPrecacheSound // spawn and precache sound forward handles
  746. new g_infbombcounter, g_antidotecounter, g_madnesscounter // to limit buying some items
  747. new g_arrays_created // to prevent stuff from being registered before initializing arrays
  748. new g_lastplayerleaving // flag for whenever a player leaves and another takes his place
  749. new g_switchingteam // flag for whenever a player's team change emessage is sent
  750.  
  751. // Message IDs vars
  752. new g_msgScoreInfo, g_msgNVGToggle, g_msgScoreAttrib, g_msgAmmoPickup, g_msgScreenFade,
  753. g_msgDeathMsg, g_msgSetFOV, g_msgFlashlight, g_msgFlashBat, g_msgTeamInfo, g_msgDamage,
  754. g_msgHideWeapon, g_msgCrosshair, g_msgSayText, g_msgScreenShake, g_msgCurWeapon
  755.  
  756. // Some forward handlers
  757. new g_fwRoundStart, g_fwRoundEnd, g_fwUserInfected_pre, g_fwUserInfected_post,
  758. g_fwUserHumanized_pre, g_fwUserHumanized_post, g_fwUserInfect_attempt,
  759. g_fwUserHumanize_attempt, g_fwExtraItemSelected, g_fwUserUnfrozen,
  760. g_fwUserLastZombie, g_fwUserLastHuman, g_fwDummyResult
  761.  
  762. // Temporary Database vars (used to restore players stats in case they get disconnected)
  763. new db_name[MAX_STATS_SAVED][32] // player name
  764. new db_ammopacks[MAX_STATS_SAVED] // ammo pack count
  765. new db_zombieclass[MAX_STATS_SAVED] // zombie class
  766. new db_slot_i // additional saved slots counter (should start on maxplayers+1)
  767.  
  768. // Extra Items vars
  769. new Array:g_extraitem_name // caption
  770. new Array:g_extraitem_cost // cost
  771. new Array:g_extraitem_team // team
  772. new g_extraitem_i // loaded extra items counter
  773.  
  774. // For extra items file parsing
  775. new Array:g_extraitem2_realname, Array:g_extraitem2_name, Array:g_extraitem2_cost,
  776. Array:g_extraitem2_team, Array:g_extraitem_new
  777.  
  778. // Zombie Classes vars
  779. new Array:g_zclass_name // caption
  780. new Array:g_zclass_info // description
  781. new Array:g_zclass_modelsstart // start position in models array
  782. new Array:g_zclass_modelsend // end position in models array
  783. new Array:g_zclass_playermodel // player models array
  784. new Array:g_zclass_modelindex // model indices array
  785. new Array:g_zclass_clawmodel // claw model
  786. new Array:g_zclass_hp // health
  787. new Array:g_zclass_spd // speed
  788. new Array:g_zclass_grav // gravity
  789. new Array:g_zclass_kb // knockback
  790. new g_zclass_i // loaded zombie classes counter
  791.  
  792. // For zombie classes file parsing
  793. new Array:g_zclass2_realname, Array:g_zclass2_name, Array:g_zclass2_info,
  794. Array:g_zclass2_modelsstart, Array:g_zclass2_modelsend, Array:g_zclass2_playermodel,
  795. Array:g_zclass2_modelindex, Array:g_zclass2_clawmodel, Array:g_zclass2_hp,
  796. Array:g_zclass2_spd, Array:g_zclass2_grav, Array:g_zclass2_kb, Array:g_zclass_new
  797.  
  798. // Customization vars
  799. new g_access_flag[MAX_ACCESS_FLAGS], Array:model_nemesis, Array:model_survivor, Array:model_human,
  800. Array:model_admin_zombie, Array:model_admin_human, Array:g_modelindex_human,
  801. Array:g_modelindex_nemesis, Array:g_modelindex_survivor, g_same_models_for_all,
  802. Array:g_modelindex_admin_zombie, Array:g_modelindex_admin_human, model_vknife_human[64],
  803. model_vknife_nemesis[64], model_vm249_survivor[64], model_grenade_infect[64],
  804. model_grenade_fire[64], model_grenade_frost[64], model_grenade_flare[64],
  805. model_vknife_admin_human[64], model_vknife_admin_zombie[64],
  806. sprite_grenade_trail[64], sprite_grenade_ring[64], sprite_grenade_fire[64],
  807. sprite_grenade_smoke[64], sprite_grenade_glass[64], Array:sound_win_zombies,
  808. Array:sound_win_humans, Array:sound_win_no_one, Array:zombie_infect, Array:zombie_idle,
  809. Array:zombie_pain, Array:nemesis_pain, Array:zombie_die, Array:zombie_fall,
  810. Array:zombie_miss_wall, Array:zombie_hit_normal, Array:zombie_hit_stab, g_ambience_rain,
  811. Array:zombie_idle_last, Array:zombie_madness, Array:sound_nemesis, Array:sound_survivor,
  812. Array:sound_swarm, Array:sound_multi, Array:sound_plague, Array:grenade_infect,
  813. Array:grenade_infect_player, Array:grenade_fire, Array:grenade_fire_player,
  814. Array:grenade_frost, Array:grenade_frost_player, Array:grenade_frost_break,
  815. Array:grenade_flare, Array:sound_antidote, Array:sound_thunder, g_ambience_sounds[MAX_AMBIENCE_SOUNDS],
  816. Array:sound_ambience1, Array:sound_ambience2, Array:sound_ambience3, Array:sound_ambience4,
  817. Array:sound_ambience5, Array:sound_ambience1_duration, Array:sound_ambience2_duration,
  818. Array:sound_ambience3_duration, Array:sound_ambience4_duration,
  819. Array:sound_ambience5_duration, Array:sound_ambience1_ismp3, Array:sound_ambience2_ismp3,
  820. Array:sound_ambience3_ismp3, Array:sound_ambience4_ismp3, Array:sound_ambience5_ismp3,
  821. Array:g_primary_items, Array:g_secondary_items, Array:g_additional_items,
  822. Array:g_primary_weaponids, Array:g_secondary_weaponids, Array:g_extraweapon_names,
  823. Array:g_extraweapon_items, Array:g_extraweapon_costs, g_extra_costs2[EXTRA_WEAPONS_STARTID],
  824. g_ambience_snow, g_ambience_fog, g_fog_density[10], g_fog_color[12], g_sky_enable,
  825. Array:g_sky_names, Array:lights_thunder, Array:zombie_decals, Array:g_objective_ents,
  826. Float:g_modelchange_delay, g_set_modelindex_offset, g_handle_models_on_separate_ent,
  827. Float:kb_weapon_power[31] = { -1.0, ... }, Array:zombie_miss_slash, g_force_consistency
  828.  
  829. // CVAR pointers
  830. new cvar_lighting, cvar_zombiefov, cvar_plague, cvar_plaguechance, cvar_zombiefirsthp,
  831. cvar_removemoney, cvar_thunder, cvar_zombiebonushp, cvar_nemhp, cvar_nem, cvar_surv,
  832. cvar_nemchance, cvar_deathmatch, cvar_nemglow, cvar_customnvg, cvar_hitzones, cvar_humanhp,
  833. cvar_nemgravity, cvar_flashsize, cvar_ammodamage, cvar_zombiearmor, cvar_survpainfree,
  834. cvar_nempainfree, cvar_nemspd, cvar_survchance, cvar_survhp, cvar_survspd, cvar_humanspd,
  835. cvar_swarmchance, cvar_flashdrain, cvar_zombiebleeding, cvar_removedoors, cvar_customflash,
  836. cvar_randspawn, cvar_multi, cvar_multichance, cvar_infammo, cvar_swarm, cvar_ammoinfect,
  837. cvar_toggle, cvar_knockbackpower, cvar_freezeduration, cvar_triggered, cvar_flashcharge,
  838. cvar_firegrenades, cvar_frostgrenades, cvar_survgravity, cvar_logcommands, cvar_survglow,
  839. cvar_humangravity, cvar_spawnprotection, cvar_nvgsize, cvar_flareduration, cvar_zclasses,
  840. cvar_extraitems, cvar_showactivity, cvar_humanlasthp, cvar_nemignorefrags, cvar_warmup,
  841. cvar_flashdist, cvar_flarecolor, cvar_survignorefrags, cvar_fireduration, cvar_firedamage,
  842. cvar_flaregrenades, cvar_knockbackducking, cvar_knockbackdamage, cvar_knockbackzvel,
  843. cvar_multiratio, cvar_flaresize, cvar_spawndelay, cvar_extraantidote, cvar_extramadness,
  844. cvar_extraweapons, cvar_extranvision, cvar_nvggive, cvar_preventconsecutive, cvar_botquota,
  845. cvar_buycustom, cvar_zombiepainfree, cvar_fireslowdown, cvar_survbasehp, cvar_survaura,
  846. cvar_nemignoreammo, cvar_survignoreammo, cvar_nemaura, cvar_extrainfbomb, cvar_knockback,
  847. cvar_fragsinfect, cvar_fragskill, cvar_humanarmor, cvar_zombiesilent, cvar_removedropped,
  848. cvar_plagueratio, cvar_blocksuicide, cvar_knockbackdist, cvar_nemdamage, cvar_leapzombies,
  849. cvar_leapzombiesforce, cvar_leapzombiesheight, cvar_leapzombiescooldown, cvar_leapnemesis,
  850. cvar_leapnemesisforce, cvar_leapnemesisheight, cvar_leapnemesiscooldown, cvar_leapsurvivor,
  851. cvar_leapsurvivorforce, cvar_leapsurvivorheight, cvar_nemminplayers, cvar_survminplayers,
  852. cvar_respawnonsuicide, cvar_respawnafterlast, cvar_leapsurvivorcooldown, cvar_statssave,
  853. cvar_swarmminplayers, cvar_multiminplayers, cvar_plagueminplayers, cvar_adminmodelshuman,
  854. cvar_adminmodelszombie, cvar_nembasehp, cvar_blockpushables, cvar_respawnworldspawnkill,
  855. cvar_madnessduration, cvar_plaguenemnum, cvar_plaguenemhpmulti, cvar_plaguesurvhpmulti,
  856. cvar_survweapon, cvar_plaguesurvnum, cvar_infectionscreenfade, cvar_infectionscreenshake,
  857. cvar_infectionsparkle, cvar_infectiontracers, cvar_infectionparticles, cvar_infbomblimit,
  858. cvar_allowrespawnsurv, cvar_flashshowall, cvar_allowrespawninfection, cvar_allowrespawnnem,
  859. cvar_allowrespawnswarm, cvar_allowrespawnplague, cvar_survinfammo, cvar_nemknockback,
  860. cvar_nvgcolor[3], cvar_nemnvgcolor[3], cvar_humnvgcolor[3], cvar_flashcolor[3],
  861. cvar_hudicons, cvar_respawnzomb, cvar_respawnhum, cvar_respawnnem, cvar_respawnsurv,
  862. cvar_startammopacks, cvar_randweapons, cvar_antidotelimit, cvar_madnesslimit,
  863. cvar_adminknifemodelshuman, cvar_adminknifemodelszombie, cvar_keephealthondisconnect
  864.  
  865. // Cached stuff for players
  866. new g_isconnected[33] // whether player is connected
  867. new g_isalive[33] // whether player is alive
  868. new g_isbot[33] // whether player is a bot
  869. new g_currentweapon[33] // player's current weapon id
  870. new g_playername[33][32] // player's name
  871. new Float:g_zombie_spd[33] // zombie class speed
  872. new Float:g_zombie_knockback[33] // zombie class knockback
  873. new g_zombie_classname[33][32] // zombie class name
  874. #define is_user_valid_connected(%1) (1 <= %1 <= g_maxplayers && g_isconnected[%1])
  875. #define is_user_valid_alive(%1) (1 <= %1 <= g_maxplayers && g_isalive[%1])
  876.  
  877. // Cached CVARs
  878. new g_cached_customflash, g_cached_zombiesilent, Float:g_cached_humanspd, Float:g_cached_nemspd,
  879. Float:g_cached_survspd, g_cached_leapzombies, Float:g_cached_leapzombiescooldown, g_cached_leapnemesis,
  880. Float:g_cached_leapnemesiscooldown, g_cached_leapsurvivor, Float:g_cached_leapsurvivorcooldown
  881.  
  882. /*================================================================================
  883.  [Natives, Precache and Init]
  884. =================================================================================*/
  885.  
  886. public plugin_natives()
  887. {
  888.         // Player specific natives
  889.         register_native("zp_get_user_zombie", "native_get_user_zombie", 1)
  890.         register_native("zp_get_user_nemesis", "native_get_user_nemesis", 1)
  891.         register_native("zp_get_user_survivor", "native_get_user_survivor", 1)
  892.         register_native("zp_get_user_first_zombie", "native_get_user_first_zombie", 1)
  893.         register_native("zp_get_user_last_zombie", "native_get_user_last_zombie", 1)
  894.         register_native("zp_get_user_last_human", "native_get_user_last_human", 1)
  895.         register_native("zp_get_user_zombie_class", "native_get_user_zombie_class", 1)
  896.         register_native("zp_get_user_next_class", "native_get_user_next_class", 1)
  897.         register_native("zp_set_user_zombie_class", "native_set_user_zombie_class", 1)
  898.         register_native("zp_get_user_ammo_packs", "native_get_user_ammo_packs", 1)
  899.         register_native("zp_set_user_ammo_packs", "native_set_user_ammo_packs", 1)
  900.         register_native("zp_get_zombie_maxhealth", "native_get_zombie_maxhealth", 1)
  901.         register_native("zp_get_user_batteries", "native_get_user_batteries", 1)
  902.         register_native("zp_set_user_batteries", "native_set_user_batteries", 1)
  903.         register_native("zp_get_user_nightvision", "native_get_user_nightvision", 1)
  904.         register_native("zp_set_user_nightvision", "native_set_user_nightvision", 1)
  905.         register_native("zp_infect_user", "native_infect_user", 1)
  906.         register_native("zp_disinfect_user", "native_disinfect_user", 1)
  907.         register_native("zp_make_user_nemesis", "native_make_user_nemesis", 1)
  908.         register_native("zp_make_user_survivor", "native_make_user_survivor", 1)
  909.         register_native("zp_respawn_user", "native_respawn_user", 1)
  910.         register_native("zp_force_buy_extra_item", "native_force_buy_extra_item", 1)
  911.        
  912.         // Round natives
  913.         register_native("zp_has_round_started", "native_has_round_started", 1)
  914.         register_native("zp_is_nemesis_round", "native_is_nemesis_round", 1)
  915.         register_native("zp_is_survivor_round", "native_is_survivor_round", 1)
  916.         register_native("zp_is_swarm_round", "native_is_swarm_round", 1)
  917.         register_native("zp_is_plague_round", "native_is_plague_round", 1)
  918.         register_native("zp_get_zombie_count", "native_get_zombie_count", 1)
  919.         register_native("zp_get_human_count", "native_get_human_count", 1)
  920.         register_native("zp_get_nemesis_count", "native_get_nemesis_count", 1)
  921.         register_native("zp_get_survivor_count", "native_get_survivor_count", 1)
  922.        
  923.         // External additions natives
  924.         register_native("zp_register_extra_item", "native_register_extra_item", 1)
  925.         register_native("zp_register_zombie_class", "native_register_zombie_class", 1)
  926.         register_native("zp_get_extra_item_id", "native_get_extra_item_id", 1)
  927.         register_native("zp_get_zombie_class_id", "native_get_zombie_class_id", 1)
  928. }
  929.  
  930. public plugin_precache()
  931. {
  932.         // Register earlier to show up in plugins list properly after plugin disable/error at loading
  933.         register_plugin("Zombie Plague", PLUGIN_VERSION, "MeRcyLeZZ")
  934.        
  935.         // To switch plugin on/off
  936.         register_concmd("zp_toggle", "cmd_toggle", _, "<1/0> - Enable/Disable Zombie Plague (will restart the current map)", 0)
  937.         cvar_toggle = register_cvar("zp_on", "1")
  938.        
  939.         // Plugin disabled?
  940.         if (!get_pcvar_num(cvar_toggle)) return;
  941.         g_pluginenabled = true
  942.        
  943.         // Initialize a few dynamically sized arrays (alright, maybe more than just a few...)
  944.         model_human = ArrayCreate(32, 1)
  945.         model_nemesis = ArrayCreate(32, 1)
  946.         model_survivor = ArrayCreate(32, 1)
  947.         model_admin_human = ArrayCreate(32, 1)
  948.         model_admin_zombie = ArrayCreate(32, 1)
  949.         g_modelindex_human = ArrayCreate(1, 1)
  950.         g_modelindex_nemesis = ArrayCreate(1, 1)
  951.         g_modelindex_survivor = ArrayCreate(1, 1)
  952.         g_modelindex_admin_human = ArrayCreate(1, 1)
  953.         g_modelindex_admin_zombie = ArrayCreate(1, 1)
  954.         sound_win_zombies = ArrayCreate(64, 1)
  955.         sound_win_humans = ArrayCreate(64, 1)
  956.         sound_win_no_one = ArrayCreate(64, 1)
  957.         zombie_infect = ArrayCreate(64, 1)
  958.         zombie_pain = ArrayCreate(64, 1)
  959.         nemesis_pain = ArrayCreate(64, 1)
  960.         zombie_die = ArrayCreate(64, 1)
  961.         zombie_fall = ArrayCreate(64, 1)
  962.         zombie_miss_slash = ArrayCreate(64, 1)
  963.         zombie_miss_wall = ArrayCreate(64, 1)
  964.         zombie_hit_normal = ArrayCreate(64, 1)
  965.         zombie_hit_stab = ArrayCreate(64, 1)
  966.         zombie_idle = ArrayCreate(64, 1)
  967.         zombie_idle_last = ArrayCreate(64, 1)
  968.         zombie_madness = ArrayCreate(64, 1)
  969.         sound_nemesis = ArrayCreate(64, 1)
  970.         sound_survivor = ArrayCreate(64, 1)
  971.         sound_swarm = ArrayCreate(64, 1)
  972.         sound_multi = ArrayCreate(64, 1)
  973.         sound_plague = ArrayCreate(64, 1)
  974.         grenade_infect = ArrayCreate(64, 1)
  975.         grenade_infect_player = ArrayCreate(64, 1)
  976.         grenade_fire = ArrayCreate(64, 1)
  977.         grenade_fire_player = ArrayCreate(64, 1)
  978.         grenade_frost = ArrayCreate(64, 1)
  979.         grenade_frost_player = ArrayCreate(64, 1)
  980.         grenade_frost_break = ArrayCreate(64, 1)
  981.         grenade_flare = ArrayCreate(64, 1)
  982.         sound_antidote = ArrayCreate(64, 1)
  983.         sound_thunder = ArrayCreate(64, 1)
  984.         sound_ambience1 = ArrayCreate(64, 1)
  985.         sound_ambience2 = ArrayCreate(64, 1)
  986.         sound_ambience3 = ArrayCreate(64, 1)
  987.         sound_ambience4 = ArrayCreate(64, 1)
  988.         sound_ambience5 = ArrayCreate(64, 1)
  989.         sound_ambience1_duration = ArrayCreate(1, 1)
  990.         sound_ambience2_duration = ArrayCreate(1, 1)
  991.         sound_ambience3_duration = ArrayCreate(1, 1)
  992.         sound_ambience4_duration = ArrayCreate(1, 1)
  993.         sound_ambience5_duration = ArrayCreate(1, 1)
  994.         sound_ambience1_ismp3 = ArrayCreate(1, 1)
  995.         sound_ambience2_ismp3 = ArrayCreate(1, 1)
  996.         sound_ambience3_ismp3 = ArrayCreate(1, 1)
  997.         sound_ambience4_ismp3 = ArrayCreate(1, 1)
  998.         sound_ambience5_ismp3 = ArrayCreate(1, 1)
  999.         g_primary_items = ArrayCreate(32, 1)
  1000.         g_secondary_items = ArrayCreate(32, 1)
  1001.         g_additional_items = ArrayCreate(32, 1)
  1002.         g_primary_weaponids = ArrayCreate(1, 1)
  1003.         g_secondary_weaponids = ArrayCreate(1, 1)
  1004.         g_extraweapon_names = ArrayCreate(32, 1)
  1005.         g_extraweapon_items = ArrayCreate(32, 1)
  1006.         g_extraweapon_costs = ArrayCreate(1, 1)
  1007.         g_sky_names = ArrayCreate(32, 1)
  1008.         lights_thunder = ArrayCreate(32, 1)
  1009.         zombie_decals = ArrayCreate(1, 1)
  1010.         g_objective_ents = ArrayCreate(32, 1)
  1011.         g_extraitem_name = ArrayCreate(32, 1)
  1012.         g_extraitem_cost = ArrayCreate(1, 1)
  1013.         g_extraitem_team = ArrayCreate(1, 1)
  1014.         g_extraitem2_realname = ArrayCreate(32, 1)
  1015.         g_extraitem2_name = ArrayCreate(32, 1)
  1016.         g_extraitem2_cost = ArrayCreate(1, 1)
  1017.         g_extraitem2_team = ArrayCreate(1, 1)
  1018.         g_extraitem_new = ArrayCreate(1, 1)
  1019.         g_zclass_name = ArrayCreate(32, 1)
  1020.         g_zclass_info = ArrayCreate(32, 1)
  1021.         g_zclass_modelsstart = ArrayCreate(1, 1)
  1022.         g_zclass_modelsend = ArrayCreate(1, 1)
  1023.         g_zclass_playermodel = ArrayCreate(32, 1)
  1024.         g_zclass_modelindex = ArrayCreate(1, 1)
  1025.         g_zclass_clawmodel = ArrayCreate(32, 1)
  1026.         g_zclass_hp = ArrayCreate(1, 1)
  1027.         g_zclass_spd = ArrayCreate(1, 1)
  1028.         g_zclass_grav = ArrayCreate(1, 1)
  1029.         g_zclass_kb = ArrayCreate(1, 1)
  1030.         g_zclass2_realname = ArrayCreate(32, 1)
  1031.         g_zclass2_name = ArrayCreate(32, 1)
  1032.         g_zclass2_info = ArrayCreate(32, 1)
  1033.         g_zclass2_modelsstart = ArrayCreate(1, 1)
  1034.         g_zclass2_modelsend = ArrayCreate(1, 1)
  1035.         g_zclass2_playermodel = ArrayCreate(32, 1)
  1036.         g_zclass2_modelindex = ArrayCreate(1, 1)
  1037.         g_zclass2_clawmodel = ArrayCreate(32, 1)
  1038.         g_zclass2_hp = ArrayCreate(1, 1)
  1039.         g_zclass2_spd = ArrayCreate(1, 1)
  1040.         g_zclass2_grav = ArrayCreate(1, 1)
  1041.         g_zclass2_kb = ArrayCreate(1, 1)
  1042.         g_zclass_new = ArrayCreate(1, 1)
  1043.        
  1044.         // Allow registering stuff now
  1045.         g_arrays_created = true
  1046.        
  1047.         // Load customization data
  1048.         load_customization_from_files()
  1049.        
  1050.         new i, buffer[100]
  1051.        
  1052.         // Load up the hard coded extra items
  1053.         native_register_extra_item2("NightVision", g_extra_costs2[EXTRA_NVISION], ZP_TEAM_HUMAN)
  1054.         native_register_extra_item2("T-Virus Antidote", g_extra_costs2[EXTRA_ANTIDOTE], ZP_TEAM_ZOMBIE)
  1055.         native_register_extra_item2("Zombie Madness", g_extra_costs2[EXTRA_MADNESS], ZP_TEAM_ZOMBIE)
  1056.         native_register_extra_item2("Infection Bomb", g_extra_costs2[EXTRA_INFBOMB], ZP_TEAM_ZOMBIE)
  1057.        
  1058.         // Extra weapons
  1059.         for (i = 0; i < ArraySize(g_extraweapon_names); i++)
  1060.         {
  1061.                 ArrayGetString(g_extraweapon_names, i, buffer, charsmax(buffer))
  1062.                 native_register_extra_item2(buffer, ArrayGetCell(g_extraweapon_costs, i), ZP_TEAM_HUMAN)
  1063.         }
  1064.        
  1065.         // Custom player models
  1066.         for (i = 0; i < ArraySize(model_human); i++)
  1067.         {
  1068.                 ArrayGetString(model_human, i, buffer, charsmax(buffer))
  1069.                 format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1070.                 ArrayPushCell(g_modelindex_human, engfunc(EngFunc_PrecacheModel, buffer))
  1071.                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1072.                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1073.         }
  1074.         for (i = 0; i < ArraySize(model_nemesis); i++)
  1075.         {
  1076.                 ArrayGetString(model_nemesis, i, buffer, charsmax(buffer))
  1077.                 format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1078.                 ArrayPushCell(g_modelindex_nemesis, engfunc(EngFunc_PrecacheModel, buffer))
  1079.                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1080.                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1081.         }
  1082.         for (i = 0; i < ArraySize(model_survivor); i++)
  1083.         {
  1084.                 ArrayGetString(model_survivor, i, buffer, charsmax(buffer))
  1085.                 format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1086.                 ArrayPushCell(g_modelindex_survivor, engfunc(EngFunc_PrecacheModel, buffer))
  1087.                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1088.                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1089.         }
  1090.         for (i = 0; i < ArraySize(model_admin_zombie); i++)
  1091.         {
  1092.                 ArrayGetString(model_admin_zombie, i, buffer, charsmax(buffer))
  1093.                 format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1094.                 ArrayPushCell(g_modelindex_admin_zombie, engfunc(EngFunc_PrecacheModel, buffer))
  1095.                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1096.                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1097.         }
  1098.         for (i = 0; i < ArraySize(model_admin_human); i++)
  1099.         {
  1100.                 ArrayGetString(model_admin_human, i, buffer, charsmax(buffer))
  1101.                 format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1102.                 ArrayPushCell(g_modelindex_admin_human, engfunc(EngFunc_PrecacheModel, buffer))
  1103.                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1104.                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1105.         }
  1106.        
  1107.         // Custom weapon models
  1108.         engfunc(EngFunc_PrecacheModel, model_vknife_human)
  1109.         engfunc(EngFunc_PrecacheModel, model_vknife_nemesis)
  1110.         engfunc(EngFunc_PrecacheModel, model_vm249_survivor)
  1111.         engfunc(EngFunc_PrecacheModel, model_grenade_infect)
  1112.         engfunc(EngFunc_PrecacheModel, model_grenade_fire)
  1113.         engfunc(EngFunc_PrecacheModel, model_grenade_frost)
  1114.         engfunc(EngFunc_PrecacheModel, model_grenade_flare)
  1115.         engfunc(EngFunc_PrecacheModel, model_vknife_admin_human)
  1116.         engfunc(EngFunc_PrecacheModel, model_vknife_admin_zombie)
  1117.        
  1118.         // Custom sprites for grenades
  1119.         g_trailSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_trail)
  1120.         g_exploSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_ring)
  1121.         g_flameSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_fire)
  1122.         g_smokeSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_smoke)
  1123.         g_glassSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_glass)
  1124.        
  1125.         // Custom sounds
  1126.         for (i = 0; i < ArraySize(sound_win_zombies); i++)
  1127.         {
  1128.                 ArrayGetString(sound_win_zombies, i, buffer, charsmax(buffer))
  1129.                 engfunc(EngFunc_PrecacheSound, buffer)
  1130.         }
  1131.         for (i = 0; i < ArraySize(sound_win_humans); i++)
  1132.         {
  1133.                 ArrayGetString(sound_win_humans, i, buffer, charsmax(buffer))
  1134.                 engfunc(EngFunc_PrecacheSound, buffer)
  1135.         }
  1136.         for (i = 0; i < ArraySize(sound_win_no_one); i++)
  1137.         {
  1138.                 ArrayGetString(sound_win_no_one, i, buffer, charsmax(buffer))
  1139.                 engfunc(EngFunc_PrecacheSound, buffer)
  1140.         }
  1141.         for (i = 0; i < ArraySize(zombie_infect); i++)
  1142.         {
  1143.                 ArrayGetString(zombie_infect, i, buffer, charsmax(buffer))
  1144.                 engfunc(EngFunc_PrecacheSound, buffer)
  1145.         }
  1146.         for (i = 0; i < ArraySize(zombie_pain); i++)
  1147.         {
  1148.                 ArrayGetString(zombie_pain, i, buffer, charsmax(buffer))
  1149.                 engfunc(EngFunc_PrecacheSound, buffer)
  1150.         }
  1151.         for (i = 0; i < ArraySize(nemesis_pain); i++)
  1152.         {
  1153.                 ArrayGetString(nemesis_pain, i, buffer, charsmax(buffer))
  1154.                 engfunc(EngFunc_PrecacheSound, buffer)
  1155.         }
  1156.         for (i = 0; i < ArraySize(zombie_die); i++)
  1157.         {
  1158.                 ArrayGetString(zombie_die, i, buffer, charsmax(buffer))
  1159.                 engfunc(EngFunc_PrecacheSound, buffer)
  1160.         }
  1161.         for (i = 0; i < ArraySize(zombie_fall); i++)
  1162.         {
  1163.                 ArrayGetString(zombie_fall, i, buffer, charsmax(buffer))
  1164.                 engfunc(EngFunc_PrecacheSound, buffer)
  1165.         }
  1166.         for (i = 0; i < ArraySize(zombie_miss_slash); i++)
  1167.         {
  1168.                 ArrayGetString(zombie_miss_slash, i, buffer, charsmax(buffer))
  1169.                 engfunc(EngFunc_PrecacheSound, buffer)
  1170.         }
  1171.         for (i = 0; i < ArraySize(zombie_miss_wall); i++)
  1172.         {
  1173.                 ArrayGetString(zombie_miss_wall, i, buffer, charsmax(buffer))
  1174.                 engfunc(EngFunc_PrecacheSound, buffer)
  1175.         }
  1176.         for (i = 0; i < ArraySize(zombie_hit_normal); i++)
  1177.         {
  1178.                 ArrayGetString(zombie_hit_normal, i, buffer, charsmax(buffer))
  1179.                 engfunc(EngFunc_PrecacheSound, buffer)
  1180.         }
  1181.         for (i = 0; i < ArraySize(zombie_hit_stab); i++)
  1182.         {
  1183.                 ArrayGetString(zombie_hit_stab, i, buffer, charsmax(buffer))
  1184.                 engfunc(EngFunc_PrecacheSound, buffer)
  1185.         }
  1186.         for (i = 0; i < ArraySize(zombie_idle); i++)
  1187.         {
  1188.                 ArrayGetString(zombie_idle, i, buffer, charsmax(buffer))
  1189.                 engfunc(EngFunc_PrecacheSound, buffer)
  1190.         }
  1191.         for (i = 0; i < ArraySize(zombie_idle_last); i++)
  1192.         {
  1193.                 ArrayGetString(zombie_idle_last, i, buffer, charsmax(buffer))
  1194.                 engfunc(EngFunc_PrecacheSound, buffer)
  1195.         }
  1196.         for (i = 0; i < ArraySize(zombie_madness); i++)
  1197.         {
  1198.                 ArrayGetString(zombie_madness, i, buffer, charsmax(buffer))
  1199.                 engfunc(EngFunc_PrecacheSound, buffer)
  1200.         }
  1201.         for (i = 0; i < ArraySize(sound_nemesis); i++)
  1202.         {
  1203.                 ArrayGetString(sound_nemesis, i, buffer, charsmax(buffer))
  1204.                 engfunc(EngFunc_PrecacheSound, buffer)
  1205.         }
  1206.         for (i = 0; i < ArraySize(sound_survivor); i++)
  1207.         {
  1208.                 ArrayGetString(sound_survivor, i, buffer, charsmax(buffer))
  1209.                 engfunc(EngFunc_PrecacheSound, buffer)
  1210.         }
  1211.         for (i = 0; i < ArraySize(sound_swarm); i++)
  1212.         {
  1213.                 ArrayGetString(sound_swarm, i, buffer, charsmax(buffer))
  1214.                 engfunc(EngFunc_PrecacheSound, buffer)
  1215.         }
  1216.         for (i = 0; i < ArraySize(sound_multi); i++)
  1217.         {
  1218.                 ArrayGetString(sound_multi, i, buffer, charsmax(buffer))
  1219.                 engfunc(EngFunc_PrecacheSound, buffer)
  1220.         }
  1221.         for (i = 0; i < ArraySize(sound_plague); i++)
  1222.         {
  1223.                 ArrayGetString(sound_plague, i, buffer, charsmax(buffer))
  1224.                 engfunc(EngFunc_PrecacheSound, buffer)
  1225.         }
  1226.         for (i = 0; i < ArraySize(grenade_infect); i++)
  1227.         {
  1228.                 ArrayGetString(grenade_infect, i, buffer, charsmax(buffer))
  1229.                 engfunc(EngFunc_PrecacheSound, buffer)
  1230.         }
  1231.         for (i = 0; i < ArraySize(grenade_infect_player); i++)
  1232.         {
  1233.                 ArrayGetString(grenade_infect_player, i, buffer, charsmax(buffer))
  1234.                 engfunc(EngFunc_PrecacheSound, buffer)
  1235.         }
  1236.         for (i = 0; i < ArraySize(grenade_fire); i++)
  1237.         {
  1238.                 ArrayGetString(grenade_fire, i, buffer, charsmax(buffer))
  1239.                 engfunc(EngFunc_PrecacheSound, buffer)
  1240.         }
  1241.         for (i = 0; i < ArraySize(grenade_fire_player); i++)
  1242.         {
  1243.                 ArrayGetString(grenade_fire_player, i, buffer, charsmax(buffer))
  1244.                 engfunc(EngFunc_PrecacheSound, buffer)
  1245.         }
  1246.         for (i = 0; i < ArraySize(grenade_frost); i++)
  1247.         {
  1248.                 ArrayGetString(grenade_frost, i, buffer, charsmax(buffer))
  1249.                 engfunc(EngFunc_PrecacheSound, buffer)
  1250.         }
  1251.         for (i = 0; i < ArraySize(grenade_frost_player); i++)
  1252.         {
  1253.                 ArrayGetString(grenade_frost_player, i, buffer, charsmax(buffer))
  1254.                 engfunc(EngFunc_PrecacheSound, buffer)
  1255.         }
  1256.         for (i = 0; i < ArraySize(grenade_frost_break); i++)
  1257.         {
  1258.                 ArrayGetString(grenade_frost_break, i, buffer, charsmax(buffer))
  1259.                 engfunc(EngFunc_PrecacheSound, buffer)
  1260.         }
  1261.         for (i = 0; i < ArraySize(grenade_flare); i++)
  1262.         {
  1263.                 ArrayGetString(grenade_flare, i, buffer, charsmax(buffer))
  1264.                 engfunc(EngFunc_PrecacheSound, buffer)
  1265.         }
  1266.         for (i = 0; i < ArraySize(sound_antidote); i++)
  1267.         {
  1268.                 ArrayGetString(sound_antidote, i, buffer, charsmax(buffer))
  1269.                 engfunc(EngFunc_PrecacheSound, buffer)
  1270.         }
  1271.         for (i = 0; i < ArraySize(sound_thunder); i++)
  1272.         {
  1273.                 ArrayGetString(sound_thunder, i, buffer, charsmax(buffer))
  1274.                 engfunc(EngFunc_PrecacheSound, buffer)
  1275.         }
  1276.        
  1277.         // Ambience Sounds
  1278.         if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION])
  1279.         {
  1280.                 for (i = 0; i < ArraySize(sound_ambience1); i++)
  1281.                 {
  1282.                         ArrayGetString(sound_ambience1, i, buffer, charsmax(buffer))
  1283.                        
  1284.                         if (ArrayGetCell(sound_ambience1_ismp3, i))
  1285.                         {
  1286.                                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1287.                                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1288.                         }
  1289.                         else
  1290.                         {
  1291.                                 engfunc(EngFunc_PrecacheSound, buffer)
  1292.                         }
  1293.                 }
  1294.         }
  1295.         if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS])
  1296.         {
  1297.                 for (i = 0; i < ArraySize(sound_ambience2); i++)
  1298.                 {
  1299.                         ArrayGetString(sound_ambience2, i, buffer, charsmax(buffer))
  1300.                        
  1301.                         if (ArrayGetCell(sound_ambience2_ismp3, i))
  1302.                         {
  1303.                                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1304.                                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1305.                         }
  1306.                         else
  1307.                         {
  1308.                                 engfunc(EngFunc_PrecacheSound, buffer)
  1309.                         }
  1310.                 }
  1311.         }
  1312.         if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR])
  1313.         {
  1314.                 for (i = 0; i < ArraySize(sound_ambience3); i++)
  1315.                 {
  1316.                         ArrayGetString(sound_ambience3, i, buffer, charsmax(buffer))
  1317.                        
  1318.                         if (ArrayGetCell(sound_ambience3_ismp3, i))
  1319.                         {
  1320.                                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1321.                                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1322.                         }
  1323.                         else
  1324.                         {
  1325.                                 engfunc(EngFunc_PrecacheSound, buffer)
  1326.                         }
  1327.                 }
  1328.         }
  1329.         if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM])
  1330.         {
  1331.                 for (i = 0; i < ArraySize(sound_ambience4); i++)
  1332.                 {
  1333.                         ArrayGetString(sound_ambience4, i, buffer, charsmax(buffer))
  1334.                        
  1335.                         if (ArrayGetCell(sound_ambience4_ismp3, i))
  1336.                         {
  1337.                                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1338.                                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1339.                         }
  1340.                         else
  1341.                         {
  1342.                                 engfunc(EngFunc_PrecacheSound, buffer)
  1343.                         }
  1344.                 }
  1345.         }
  1346.         if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE])
  1347.         {
  1348.                 for (i = 0; i < ArraySize(sound_ambience5); i++)
  1349.                 {
  1350.                         ArrayGetString(sound_ambience5, i, buffer, charsmax(buffer))
  1351.                        
  1352.                         if (ArrayGetCell(sound_ambience5_ismp3, i))
  1353.                         {
  1354.                                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1355.                                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1356.                         }
  1357.                         else
  1358.                         {
  1359.                                 engfunc(EngFunc_PrecacheSound, buffer)
  1360.                         }
  1361.                 }
  1362.         }
  1363.        
  1364.         // CS sounds (just in case)
  1365.         engfunc(EngFunc_PrecacheSound, sound_flashlight)
  1366.         engfunc(EngFunc_PrecacheSound, sound_buyammo)
  1367.         engfunc(EngFunc_PrecacheSound, sound_armorhit)
  1368.        
  1369.         new ent
  1370.        
  1371.         // Fake Hostage (to force round ending)
  1372.         ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "hostage_entity"))
  1373.         if (pev_valid(ent))
  1374.         {
  1375.                 engfunc(EngFunc_SetOrigin, ent, Float:{8192.0,8192.0,8192.0})
  1376.                 dllfunc(DLLFunc_Spawn, ent)
  1377.         }
  1378.        
  1379.         // Weather/ambience effects
  1380.         if (g_ambience_fog)
  1381.         {
  1382.                 ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_fog"))
  1383.                 if (pev_valid(ent))
  1384.                 {
  1385.                         fm_set_kvd(ent, "density", g_fog_density, "env_fog")
  1386.                         fm_set_kvd(ent, "rendercolor", g_fog_color, "env_fog")
  1387.                 }
  1388.         }
  1389.         if (g_ambience_rain) engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_rain"))
  1390.         if (g_ambience_snow) engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_snow"))
  1391.        
  1392.         // Prevent some entities from spawning
  1393.         g_fwSpawn = register_forward(FM_Spawn, "fw_Spawn")
  1394.        
  1395.         // Prevent hostage sounds from being precached
  1396.         g_fwPrecacheSound = register_forward(FM_PrecacheSound, "fw_PrecacheSound")
  1397. }
  1398.  
  1399. public plugin_init()
  1400. {
  1401.         // Plugin disabled?
  1402.         if (!g_pluginenabled) return;
  1403.        
  1404.         // No zombie classes?
  1405.         if (!g_zclass_i) set_fail_state("No zombie classes loaded!")
  1406.        
  1407.         // Language files
  1408.         register_dictionary("zombie_plague.txt")
  1409.        
  1410.         // Events
  1411.         register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
  1412.         register_logevent("logevent_round_start",2, "1=Round_Start")
  1413.         register_logevent("logevent_round_end", 2, "1=Round_End")
  1414.         register_event("AmmoX", "event_ammo_x", "be")
  1415.         if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] || g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] || g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] || g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] || g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE])
  1416.                 register_event("30", "event_intermission", "a")
  1417.        
  1418.         // HAM Forwards
  1419.         RegisterHam(Ham_Spawn, "player", "fw_PlayerSpawn_Post", 1)
  1420.         RegisterHam(Ham_Killed, "player", "fw_PlayerKilled")
  1421.         RegisterHam(Ham_Killed, "player", "fw_PlayerKilled_Post", 1)
  1422.         RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
  1423.         RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage_Post", 1)
  1424.         RegisterHam(Ham_TraceAttack, "player", "fw_TraceAttack")
  1425.         RegisterHam(Ham_Use, "func_tank", "fw_UseStationary")
  1426.         RegisterHam(Ham_Use, "func_tankmortar", "fw_UseStationary")
  1427.         RegisterHam(Ham_Use, "func_tankrocket", "fw_UseStationary")
  1428.         RegisterHam(Ham_Use, "func_tanklaser", "fw_UseStationary")
  1429.         RegisterHam(Ham_Use, "func_tank", "fw_UseStationary_Post", 1)
  1430.         RegisterHam(Ham_Use, "func_tankmortar", "fw_UseStationary_Post", 1)
  1431.         RegisterHam(Ham_Use, "func_tankrocket", "fw_UseStationary_Post", 1)
  1432.         RegisterHam(Ham_Use, "func_tanklaser", "fw_UseStationary_Post", 1)
  1433.         RegisterHam(Ham_Use, "func_pushable", "fw_UsePushable")
  1434.         RegisterHam(Ham_Touch, "weaponbox", "fw_TouchWeapon")
  1435.         RegisterHam(Ham_Touch, "armoury_entity", "fw_TouchWeapon")
  1436.         RegisterHam(Ham_Touch, "weapon_shield", "fw_TouchWeapon")
  1437.         RegisterHam(Ham_AddPlayerItem, "player", "fw_AddPlayerItem")
  1438.         for (new i = 1; i < sizeof WEAPONENTNAMES; i++)
  1439.                 if (WEAPONENTNAMES[i][0]) RegisterHam(Ham_Item_Deploy, WEAPONENTNAMES[i], "fw_Item_Deploy_Post", 1)
  1440.        
  1441.         // FM Forwards
  1442.         register_forward(FM_ClientDisconnect, "fw_ClientDisconnect")
  1443.         register_forward(FM_ClientDisconnect, "fw_ClientDisconnect_Post", 1)
  1444.         register_forward(FM_ClientKill, "fw_ClientKill")
  1445.         register_forward(FM_EmitSound, "fw_EmitSound")
  1446.         if (!g_handle_models_on_separate_ent) register_forward(FM_SetClientKeyValue, "fw_SetClientKeyValue")
  1447.         register_forward(FM_ClientUserInfoChanged, "fw_ClientUserInfoChanged")
  1448.         register_forward(FM_GetGameDescription, "fw_GetGameDescription")
  1449.         register_forward(FM_SetModel, "fw_SetModel")
  1450.         RegisterHam(Ham_Think, "grenade", "fw_ThinkGrenade")
  1451.         register_forward(FM_CmdStart, "fw_CmdStart")
  1452.         register_forward(FM_PlayerPreThink, "fw_PlayerPreThink")
  1453.         unregister_forward(FM_Spawn, g_fwSpawn)
  1454.         unregister_forward(FM_PrecacheSound, g_fwPrecacheSound)
  1455.        
  1456.         // Client commands
  1457.         register_clcmd("say zpmenu", "clcmd_saymenu")
  1458.         register_clcmd("say /zpmenu", "clcmd_saymenu")
  1459.         register_clcmd("say unstuck", "clcmd_sayunstuck")
  1460.         register_clcmd("say /unstuck", "clcmd_sayunstuck")
  1461.         register_clcmd("nightvision", "clcmd_nightvision")
  1462.         register_clcmd("drop", "clcmd_drop")
  1463.         register_clcmd("buyammo1", "clcmd_buyammo")
  1464.         register_clcmd("buyammo2", "clcmd_buyammo")
  1465.         register_clcmd("chooseteam", "clcmd_changeteam")
  1466.         register_clcmd("jointeam", "clcmd_changeteam")
  1467.        
  1468.         // Menus
  1469.         register_menu("Game Menu", KEYSMENU, "menu_game")
  1470.         register_menu("Buy Menu 1", KEYSMENU, "menu_buy1")
  1471.         register_menu("Buy Menu 2", KEYSMENU, "menu_buy2")
  1472.         register_menu("Mod Info", KEYSMENU, "menu_info")
  1473.         register_menu("Admin Menu", KEYSMENU, "menu_admin")
  1474.        
  1475.         // Admin commands
  1476.         register_concmd("zp_zombie", "cmd_zombie", _, "<target> - Turn someone into a Zombie", 0)
  1477.         register_concmd("zp_human", "cmd_human", _, "<target> - Turn someone back to Human", 0)
  1478.         register_concmd("zp_nemesis", "cmd_nemesis", _, "<target> - Turn someone into a Nemesis", 0)
  1479.         register_concmd("zp_survivor", "cmd_survivor", _, "<target> - Turn someone into a Survivor", 0)
  1480.         register_concmd("zp_respawn", "cmd_respawn", _, "<target> - Respawn someone", 0)
  1481.         register_concmd("zp_swarm", "cmd_swarm", _, " - Start Swarm Mode", 0)
  1482.         register_concmd("zp_multi", "cmd_multi", _, " - Start Multi Infection", 0)
  1483.         register_concmd("zp_plague", "cmd_plague", _, " - Start Plague Mode", 0)
  1484.        
  1485.         // Message IDs
  1486.         g_msgScoreInfo = get_user_msgid("ScoreInfo")
  1487.         g_msgTeamInfo = get_user_msgid("TeamInfo")
  1488.         g_msgDeathMsg = get_user_msgid("DeathMsg")
  1489.         g_msgScoreAttrib = get_user_msgid("ScoreAttrib")
  1490.         g_msgSetFOV = get_user_msgid("SetFOV")
  1491.         g_msgScreenFade = get_user_msgid("ScreenFade")
  1492.         g_msgScreenShake = get_user_msgid("ScreenShake")
  1493.         g_msgNVGToggle = get_user_msgid("NVGToggle")
  1494.         g_msgFlashlight = get_user_msgid("Flashlight")
  1495.         g_msgFlashBat = get_user_msgid("FlashBat")
  1496.         g_msgAmmoPickup = get_user_msgid("AmmoPickup")
  1497.         g_msgDamage = get_user_msgid("Damage")
  1498.         g_msgHideWeapon = get_user_msgid("HideWeapon")
  1499.         g_msgCrosshair = get_user_msgid("Crosshair")
  1500.         g_msgSayText = get_user_msgid("SayText")
  1501.         g_msgCurWeapon = get_user_msgid("CurWeapon")
  1502.        
  1503.         // Message hooks
  1504.         register_message(g_msgCurWeapon, "message_cur_weapon")
  1505.         register_message(get_user_msgid("Money"), "message_money")
  1506.         register_message(get_user_msgid("Health"), "message_health")
  1507.         register_message(g_msgFlashBat, "message_flashbat")
  1508.         register_message(g_msgScreenFade, "message_screenfade")
  1509.         register_message(g_msgNVGToggle, "message_nvgtoggle")
  1510.         if (g_handle_models_on_separate_ent) register_message(get_user_msgid("ClCorpse"), "message_clcorpse")
  1511.         register_message(get_user_msgid("WeapPickup"), "message_weappickup")
  1512.         register_message(g_msgAmmoPickup, "message_ammopickup")
  1513.         register_message(get_user_msgid("Scenario"), "message_scenario")
  1514.         register_message(get_user_msgid("HostagePos"), "message_hostagepos")
  1515.         register_message(get_user_msgid("TextMsg"), "message_textmsg")
  1516.         register_message(get_user_msgid("SendAudio"), "message_sendaudio")
  1517.         register_message(get_user_msgid("TeamScore"), "message_teamscore")
  1518.         register_message(g_msgTeamInfo, "message_teaminfo")
  1519.        
  1520.         // CVARS - General Purpose
  1521.         cvar_warmup = register_cvar("zp_delay", "10")
  1522.         cvar_lighting = register_cvar("zp_lighting", "a")
  1523.         cvar_thunder = register_cvar("zp_thunderclap", "90")
  1524.         cvar_triggered = register_cvar("zp_triggered_lights", "1")
  1525.         cvar_removedoors = register_cvar("zp_remove_doors", "0")
  1526.         cvar_blockpushables = register_cvar("zp_blockuse_pushables", "1")
  1527.         cvar_blocksuicide = register_cvar("zp_block_suicide", "1")
  1528.         cvar_randspawn = register_cvar("zp_random_spawn", "1")
  1529.         cvar_respawnworldspawnkill = register_cvar("zp_respawn_on_worldspawn_kill", "1")
  1530.         cvar_removedropped = register_cvar("zp_remove_dropped", "0")
  1531.         cvar_removemoney = register_cvar("zp_remove_money", "1")
  1532.         cvar_buycustom = register_cvar("zp_buy_custom", "1")
  1533.         cvar_randweapons = register_cvar("zp_random_weapons", "0")
  1534.         cvar_adminmodelshuman = register_cvar("zp_admin_models_human", "1")
  1535.         cvar_adminknifemodelshuman = register_cvar("zp_admin_knife_models_human", "0")
  1536.         cvar_adminmodelszombie = register_cvar("zp_admin_models_zombie", "1")
  1537.         cvar_adminknifemodelszombie = register_cvar("zp_admin_knife_models_zombie", "0")
  1538.         cvar_zclasses = register_cvar("zp_zombie_classes", "1")
  1539.         cvar_statssave = register_cvar("zp_stats_save", "1")
  1540.         cvar_startammopacks = register_cvar("zp_starting_ammo_packs", "5")
  1541.         cvar_preventconsecutive = register_cvar("zp_prevent_consecutive_modes", "1")
  1542.         cvar_keephealthondisconnect = register_cvar("zp_keep_health_on_disconnect", "1")
  1543.        
  1544.         // CVARS - Deathmatch
  1545.         cvar_deathmatch = register_cvar("zp_deathmatch", "0")
  1546.         cvar_spawndelay = register_cvar("zp_spawn_delay", "5")
  1547.         cvar_spawnprotection = register_cvar("zp_spawn_protection", "5")
  1548.         cvar_respawnonsuicide = register_cvar("zp_respawn_on_suicide", "0")
  1549.         cvar_respawnafterlast = register_cvar("zp_respawn_after_last_human", "1")
  1550.         cvar_allowrespawninfection = register_cvar("zp_infection_allow_respawn", "1")
  1551.         cvar_allowrespawnnem = register_cvar("zp_nem_allow_respawn", "0")
  1552.         cvar_allowrespawnsurv = register_cvar("zp_surv_allow_respawn", "0")
  1553.         cvar_allowrespawnswarm = register_cvar("zp_swarm_allow_respawn", "0")
  1554.         cvar_allowrespawnplague = register_cvar("zp_plague_allow_respawn", "0")
  1555.         cvar_respawnzomb = register_cvar("zp_respawn_zombies", "1")
  1556.         cvar_respawnhum = register_cvar("zp_respawn_humans", "1")
  1557.         cvar_respawnnem = register_cvar("zp_respawn_nemesis", "1")
  1558.         cvar_respawnsurv = register_cvar("zp_respawn_survivors", "1")
  1559.        
  1560.         // CVARS - Extra Items
  1561.         cvar_extraitems = register_cvar("zp_extra_items", "1")
  1562.         cvar_extraweapons = register_cvar("zp_extra_weapons", "1")
  1563.         cvar_extranvision = register_cvar("zp_extra_nvision", "1")
  1564.         cvar_extraantidote = register_cvar("zp_extra_antidote", "1")
  1565.         cvar_antidotelimit = register_cvar("zp_extra_antidote_limit", "999")
  1566.         cvar_extramadness = register_cvar("zp_extra_madness", "1")
  1567.         cvar_madnesslimit = register_cvar("zp_extra_madness_limit", "999")
  1568.         cvar_madnessduration = register_cvar("zp_extra_madness_duration", "5.0")
  1569.         cvar_extrainfbomb = register_cvar("zp_extra_infbomb", "1")
  1570.         cvar_infbomblimit = register_cvar("zp_extra_infbomb_limit", "999")
  1571.        
  1572.         // CVARS - Flashlight and Nightvision
  1573.         cvar_nvggive = register_cvar("zp_nvg_give", "1")
  1574.         cvar_customnvg = register_cvar("zp_nvg_custom", "1")
  1575.         cvar_nvgsize = register_cvar("zp_nvg_size", "80")
  1576.         cvar_nvgcolor[0] = register_cvar("zp_nvg_color_R", "0")
  1577.         cvar_nvgcolor[1] = register_cvar("zp_nvg_color_G", "150")
  1578.         cvar_nvgcolor[2] = register_cvar("zp_nvg_color_B", "0")
  1579.         cvar_humnvgcolor[0] = register_cvar("zp_nvg_hum_color_R", "0")
  1580.         cvar_humnvgcolor[1] = register_cvar("zp_nvg_hum_color_G", "150")
  1581.         cvar_humnvgcolor[2] = register_cvar("zp_nvg_hum_color_B", "0")
  1582.         cvar_nemnvgcolor[0] = register_cvar("zp_nvg_nem_color_R", "150")
  1583.         cvar_nemnvgcolor[1] = register_cvar("zp_nvg_nem_color_G", "0")
  1584.         cvar_nemnvgcolor[2] = register_cvar("zp_nvg_nem_color_B", "0")
  1585.         cvar_customflash = register_cvar("zp_flash_custom", "0")
  1586.         cvar_flashsize = register_cvar("zp_flash_size", "10")
  1587.         cvar_flashdrain = register_cvar("zp_flash_drain", "1")
  1588.         cvar_flashcharge = register_cvar("zp_flash_charge", "5")
  1589.         cvar_flashdist = register_cvar("zp_flash_distance", "1000")
  1590.         cvar_flashcolor[0] = register_cvar("zp_flash_color_R", "100")
  1591.         cvar_flashcolor[1] = register_cvar("zp_flash_color_G", "100")
  1592.         cvar_flashcolor[2] = register_cvar("zp_flash_color_B", "100")
  1593.         cvar_flashshowall = register_cvar("zp_flash_show_all", "1")
  1594.        
  1595.         // CVARS - Knockback
  1596.         cvar_knockback = register_cvar("zp_knockback", "0")
  1597.         cvar_knockbackdamage = register_cvar("zp_knockback_damage", "1")
  1598.         cvar_knockbackpower = register_cvar("zp_knockback_power", "1")
  1599.         cvar_knockbackzvel = register_cvar("zp_knockback_zvel", "0")
  1600.         cvar_knockbackducking = register_cvar("zp_knockback_ducking", "0.25")
  1601.         cvar_knockbackdist = register_cvar("zp_knockback_distance", "500")
  1602.         cvar_nemknockback = register_cvar("zp_knockback_nemesis", "0.25")
  1603.        
  1604.         // CVARS - Leap
  1605.         cvar_leapzombies = register_cvar("zp_leap_zombies", "0")
  1606.         cvar_leapzombiesforce = register_cvar("zp_leap_zombies_force", "500")
  1607.         cvar_leapzombiesheight = register_cvar("zp_leap_zombies_height", "300")
  1608.         cvar_leapzombiescooldown = register_cvar("zp_leap_zombies_cooldown", "5.0")
  1609.         cvar_leapnemesis = register_cvar("zp_leap_nemesis", "1")
  1610.         cvar_leapnemesisforce = register_cvar("zp_leap_nemesis_force", "500")
  1611.         cvar_leapnemesisheight = register_cvar("zp_leap_nemesis_height", "300")
  1612.         cvar_leapnemesiscooldown = register_cvar("zp_leap_nemesis_cooldown", "5.0")
  1613.         cvar_leapsurvivor = register_cvar("zp_leap_survivor", "0")
  1614.         cvar_leapsurvivorforce = register_cvar("zp_leap_survivor_force", "500")
  1615.         cvar_leapsurvivorheight = register_cvar("zp_leap_survivor_height", "300")
  1616.         cvar_leapsurvivorcooldown = register_cvar("zp_leap_survivor_cooldown", "5.0")
  1617.        
  1618.         // CVARS - Humans
  1619.         cvar_humanhp = register_cvar("zp_human_health", "100")
  1620.         cvar_humanlasthp = register_cvar("zp_human_last_extrahp", "0")
  1621.         cvar_humanspd = register_cvar("zp_human_speed", "240")
  1622.         cvar_humangravity = register_cvar("zp_human_gravity", "1.0")
  1623.         cvar_humanarmor = register_cvar("zp_human_armor_protect", "1")
  1624.         cvar_infammo = register_cvar("zp_human_unlimited_ammo", "0")
  1625.         cvar_ammodamage = register_cvar("zp_human_damage_reward", "500")
  1626.         cvar_fragskill = register_cvar("zp_human_frags_for_kill", "1")
  1627.        
  1628.         // CVARS - Custom Grenades
  1629.         cvar_firegrenades = register_cvar("zp_fire_grenades", "1")
  1630.         cvar_fireduration = register_cvar("zp_fire_duration", "10")
  1631.         cvar_firedamage = register_cvar("zp_fire_damage", "5")
  1632.         cvar_fireslowdown = register_cvar("zp_fire_slowdown", "0.5")
  1633.         cvar_frostgrenades = register_cvar("zp_frost_grenades", "1")
  1634.         cvar_freezeduration = register_cvar("zp_frost_duration", "3")
  1635.         cvar_flaregrenades = register_cvar("zp_flare_grenades","1")
  1636.         cvar_flareduration = register_cvar("zp_flare_duration", "60")
  1637.         cvar_flaresize = register_cvar("zp_flare_size", "25")
  1638.         cvar_flarecolor = register_cvar("zp_flare_color", "0")
  1639.        
  1640.         // CVARS - Zombies
  1641.         cvar_zombiefirsthp = register_cvar("zp_zombie_first_hp", "2.0")
  1642.         cvar_zombiearmor = register_cvar("zp_zombie_armor", "0.75")
  1643.         cvar_hitzones = register_cvar("zp_zombie_hitzones", "0")
  1644.         cvar_zombiebonushp = register_cvar("zp_zombie_infect_health", "100")
  1645.         cvar_zombiefov = register_cvar("zp_zombie_fov", "110")
  1646.         cvar_zombiesilent = register_cvar("zp_zombie_silent", "1")
  1647.         cvar_zombiepainfree = register_cvar("zp_zombie_painfree", "2")
  1648.         cvar_zombiebleeding = register_cvar("zp_zombie_bleeding", "1")
  1649.         cvar_ammoinfect = register_cvar("zp_zombie_infect_reward", "1")
  1650.         cvar_fragsinfect = register_cvar("zp_zombie_frags_for_infect", "1")
  1651.        
  1652.         // CVARS - Special Effects
  1653.         cvar_infectionscreenfade = register_cvar("zp_infection_screenfade", "1")
  1654.         cvar_infectionscreenshake = register_cvar("zp_infection_screenshake", "1")
  1655.         cvar_infectionsparkle = register_cvar("zp_infection_sparkle", "1")
  1656.         cvar_infectiontracers = register_cvar("zp_infection_tracers", "1")
  1657.         cvar_infectionparticles = register_cvar("zp_infection_particles", "1")
  1658.         cvar_hudicons = register_cvar("zp_hud_icons", "1")
  1659.        
  1660.         // CVARS - Nemesis
  1661.         cvar_nem = register_cvar("zp_nem_enabled", "1")
  1662.         cvar_nemchance = register_cvar("zp_nem_chance", "20")
  1663.         cvar_nemminplayers = register_cvar("zp_nem_min_players", "0")
  1664.         cvar_nemhp = register_cvar("zp_nem_health", "0")
  1665.         cvar_nembasehp = register_cvar("zp_nem_base_health", "0")
  1666.         cvar_nemspd = register_cvar("zp_nem_speed", "250")
  1667.         cvar_nemgravity = register_cvar("zp_nem_gravity", "0.5")
  1668.         cvar_nemdamage = register_cvar("zp_nem_damage", "250")
  1669.         cvar_nemglow = register_cvar("zp_nem_glow", "1")
  1670.         cvar_nemaura = register_cvar("zp_nem_aura", "1")       
  1671.         cvar_nempainfree = register_cvar("zp_nem_painfree", "0")
  1672.         cvar_nemignorefrags = register_cvar("zp_nem_ignore_frags", "1")
  1673.         cvar_nemignoreammo = register_cvar("zp_nem_ignore_rewards", "1")
  1674.        
  1675.         // CVARS - Survivor
  1676.         cvar_surv = register_cvar("zp_surv_enabled", "1")
  1677.         cvar_survchance = register_cvar("zp_surv_chance", "20")
  1678.         cvar_survminplayers = register_cvar("zp_surv_min_players", "0")
  1679.         cvar_survhp = register_cvar("zp_surv_health", "0")
  1680.         cvar_survbasehp = register_cvar("zp_surv_base_health", "0")
  1681.         cvar_survspd = register_cvar("zp_surv_speed", "230")
  1682.         cvar_survgravity = register_cvar("zp_surv_gravity", "1.25")
  1683.         cvar_survglow = register_cvar("zp_surv_glow", "1")
  1684.         cvar_survaura = register_cvar("zp_surv_aura", "1")
  1685.         cvar_survpainfree = register_cvar("zp_surv_painfree", "1")
  1686.         cvar_survignorefrags = register_cvar("zp_surv_ignore_frags", "1")
  1687.         cvar_survignoreammo = register_cvar("zp_surv_ignore_rewards", "1")
  1688.         cvar_survweapon = register_cvar("zp_surv_weapon", "weapon_m249")
  1689.         cvar_survinfammo = register_cvar("zp_surv_unlimited_ammo", "2")
  1690.        
  1691.         // CVARS - Swarm Mode
  1692.         cvar_swarm = register_cvar("zp_swarm_enabled", "1")
  1693.         cvar_swarmchance = register_cvar("zp_swarm_chance", "20")
  1694.         cvar_swarmminplayers = register_cvar("zp_swarm_min_players", "0")
  1695.        
  1696.         // CVARS - Multi Infection
  1697.         cvar_multi = register_cvar("zp_multi_enabled", "1")
  1698.         cvar_multichance = register_cvar("zp_multi_chance", "20")
  1699.         cvar_multiminplayers = register_cvar("zp_multi_min_players", "0")
  1700.         cvar_multiratio = register_cvar("zp_multi_ratio", "0.15")
  1701.        
  1702.         // CVARS - Plague Mode
  1703.         cvar_plague = register_cvar("zp_plague_enabled", "1")
  1704.         cvar_plaguechance = register_cvar("zp_plague_chance", "30")
  1705.         cvar_plagueminplayers = register_cvar("zp_plague_min_players", "0")
  1706.         cvar_plagueratio = register_cvar("zp_plague_ratio", "0.5")
  1707.         cvar_plaguenemnum = register_cvar("zp_plague_nem_number", "1")
  1708.         cvar_plaguenemhpmulti = register_cvar("zp_plague_nem_hp_multi", "0.5")
  1709.         cvar_plaguesurvnum = register_cvar("zp_plague_surv_number", "1")
  1710.         cvar_plaguesurvhpmulti = register_cvar("zp_plague_surv_hp_multi", "0.5")
  1711.        
  1712.         // CVARS - Others
  1713.         cvar_logcommands = register_cvar("zp_logcommands", "1")
  1714.         cvar_showactivity = get_cvar_pointer("amx_show_activity")
  1715.         cvar_botquota = get_cvar_pointer("bot_quota")
  1716.         register_cvar("zp_version", PLUGIN_VERSION, FCVAR_SERVER|FCVAR_SPONLY)
  1717.         set_cvar_string("zp_version", PLUGIN_VERSION)
  1718.        
  1719.         // Custom Forwards
  1720.         g_fwRoundStart = CreateMultiForward("zp_round_started", ET_IGNORE, FP_CELL, FP_CELL)
  1721.         g_fwRoundEnd = CreateMultiForward("zp_round_ended", ET_IGNORE, FP_CELL)
  1722.         g_fwUserInfected_pre = CreateMultiForward("zp_user_infected_pre", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
  1723.         g_fwUserInfected_post = CreateMultiForward("zp_user_infected_post", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
  1724.         g_fwUserHumanized_pre = CreateMultiForward("zp_user_humanized_pre", ET_IGNORE, FP_CELL, FP_CELL)
  1725.         g_fwUserHumanized_post = CreateMultiForward("zp_user_humanized_post", ET_IGNORE, FP_CELL, FP_CELL)
  1726.         g_fwUserInfect_attempt = CreateMultiForward("zp_user_infect_attempt", ET_CONTINUE, FP_CELL, FP_CELL, FP_CELL)
  1727.         g_fwUserHumanize_attempt = CreateMultiForward("zp_user_humanize_attempt", ET_CONTINUE, FP_CELL, FP_CELL)
  1728.         g_fwExtraItemSelected = CreateMultiForward("zp_extra_item_selected", ET_CONTINUE, FP_CELL, FP_CELL)
  1729.         g_fwUserUnfrozen = CreateMultiForward("zp_user_unfrozen", ET_IGNORE, FP_CELL)
  1730.         g_fwUserLastZombie = CreateMultiForward("zp_user_last_zombie", ET_IGNORE, FP_CELL)
  1731.         g_fwUserLastHuman = CreateMultiForward("zp_user_last_human", ET_IGNORE, FP_CELL)
  1732.        
  1733.         // Collect random spawn points
  1734.         load_spawns()
  1735.        
  1736.         // Set a random skybox?
  1737.         if (g_sky_enable)
  1738.         {
  1739.                 new sky[32]
  1740.                 ArrayGetString(g_sky_names, random_num(0, ArraySize(g_sky_names) - 1), sky, charsmax(sky))
  1741.                 set_cvar_string("sv_skyname", sky)
  1742.         }
  1743.        
  1744.         // Disable sky lighting so it doesn't mess with our custom lighting
  1745.         set_cvar_num("sv_skycolor_r", 0)
  1746.         set_cvar_num("sv_skycolor_g", 0)
  1747.         set_cvar_num("sv_skycolor_b", 0)
  1748.        
  1749.         // Create the HUD Sync Objects
  1750.         g_MsgSync = CreateHudSyncObj()
  1751.         g_MsgSync2 = CreateHudSyncObj()
  1752.        
  1753.         // Format mod name
  1754.         formatex(g_modname, charsmax(g_modname), "Zombie Plague %s", PLUGIN_VERSION)
  1755.        
  1756.         // Get Max Players
  1757.         g_maxplayers = get_maxplayers()
  1758.        
  1759.         // Reserved saving slots starts on maxplayers+1
  1760.         db_slot_i = g_maxplayers+1
  1761.        
  1762.         // Check if it's a CZ server
  1763.         new mymod[6]
  1764.         get_modname(mymod, charsmax(mymod))
  1765.         if (equal(mymod, "czero")) g_czero = 1
  1766. }
  1767.  
  1768. public plugin_cfg()
  1769. {
  1770.         // Plugin disabled?
  1771.         if (!g_pluginenabled) return;
  1772.        
  1773.         // Get configs dir
  1774.         new cfgdir[32]
  1775.         get_configsdir(cfgdir, charsmax(cfgdir))
  1776.        
  1777.         // Execute config file (zombieplague.cfg)
  1778.         server_cmd("exec %s/zombieplague.cfg", cfgdir)
  1779.        
  1780.         // Prevent any more stuff from registering
  1781.         g_arrays_created = false
  1782.        
  1783.         // Save customization data
  1784.         save_customization()
  1785.        
  1786.         // Lighting task
  1787.         set_task(5.0, "lighting_effects", _, _, _, "b")
  1788.        
  1789.         // Cache CVARs after configs are loaded / call roundstart manually
  1790.         set_task(0.5, "cache_cvars")
  1791.         set_task(0.5, "event_round_start")
  1792.         set_task(0.5, "logevent_round_start")
  1793. }
  1794.  
  1795. /*================================================================================
  1796.  [Main Events]
  1797. =================================================================================*/
  1798.  
  1799. // Event Round Start
  1800. public event_round_start()
  1801. {
  1802.         // Remove doors/lights?
  1803.         set_task(0.1, "remove_stuff")
  1804.        
  1805.         // New round starting
  1806.         g_newround = true
  1807.         g_endround = false
  1808.         g_survround = false
  1809.         g_nemround = false
  1810.         g_swarmround = false
  1811.         g_plagueround = false
  1812.         g_modestarted = false
  1813.        
  1814.         // Reset bought infection bombs counter
  1815.         g_infbombcounter = 0
  1816.         g_antidotecounter = 0
  1817.         g_madnesscounter = 0
  1818.        
  1819.         // Freezetime begins
  1820.         g_freezetime = true
  1821.        
  1822.         // Show welcome message and T-Virus notice
  1823.         remove_task(TASK_WELCOMEMSG)
  1824.         set_task(2.0, "welcome_msg", TASK_WELCOMEMSG)
  1825.        
  1826.         // Set a new "Make Zombie Task"
  1827.         remove_task(TASK_MAKEZOMBIE)
  1828.         set_task(2.0 + get_pcvar_float(cvar_warmup), "make_zombie_task", TASK_MAKEZOMBIE)
  1829. }
  1830.  
  1831. // Log Event Round Start
  1832. public logevent_round_start()
  1833. {
  1834.         // Freezetime ends
  1835.         g_freezetime = false
  1836. }
  1837.  
  1838. // Log Event Round End
  1839. public logevent_round_end()
  1840. {
  1841.         // Prevent this from getting called twice when restarting (bugfix)
  1842.         static Float:lastendtime, Float:current_time
  1843.         current_time = get_gametime()
  1844.         if (current_time - lastendtime < 0.5) return;
  1845.         lastendtime = current_time
  1846.        
  1847.         // Temporarily save player stats?
  1848.         if (get_pcvar_num(cvar_statssave))
  1849.         {
  1850.                 static id, team
  1851.                 for (id = 1; id <= g_maxplayers; id++)
  1852.                 {
  1853.                         // Not connected
  1854.                         if (!g_isconnected[id])
  1855.                                 continue;
  1856.                        
  1857.                         team = fm_cs_get_user_team(id)
  1858.                        
  1859.                         // Not playing
  1860.                         if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  1861.                                 continue;
  1862.                        
  1863.                         save_stats(id)
  1864.                 }
  1865.         }
  1866.        
  1867.         // Round ended
  1868.         g_endround = true
  1869.        
  1870.         // Stop old tasks (if any)
  1871.         remove_task(TASK_WELCOMEMSG)
  1872.         remove_task(TASK_MAKEZOMBIE)
  1873.        
  1874.         // Stop ambience sounds
  1875.         if ((g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && g_nemround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && g_survround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && g_swarmround) || (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && g_plagueround) || (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && !g_nemround && !g_survround && !g_swarmround && !g_plagueround))
  1876.         {
  1877.                 remove_task(TASK_AMBIENCESOUNDS)
  1878.                 ambience_sound_stop()
  1879.         }
  1880.        
  1881.         // Show HUD notice, play win sound, update team scores...
  1882.         static sound[64]
  1883.         if (!fnGetZombies())
  1884.         {
  1885.                 // Human team wins
  1886.                 set_hudmessage(0, 0, 200, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  1887.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_HUMAN")
  1888.                
  1889.                 // Play win sound and increase score
  1890.                 ArrayGetString(sound_win_humans, random_num(0, ArraySize(sound_win_humans) - 1), sound, charsmax(sound))
  1891.                 PlaySound(sound)
  1892.                 g_scorehumans++
  1893.                
  1894.                 // Round end forward
  1895.                 ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_HUMAN);
  1896.         }
  1897.         else if (!fnGetHumans())
  1898.         {
  1899.                 // Zombie team wins
  1900.                 set_hudmessage(200, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  1901.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_ZOMBIE")
  1902.                
  1903.                 // Play win sound and increase score
  1904.                 ArrayGetString(sound_win_zombies, random_num(0, ArraySize(sound_win_zombies) - 1), sound, charsmax(sound))
  1905.                 PlaySound(sound)
  1906.                 g_scorezombies++
  1907.                
  1908.                 // Round end forward
  1909.                 ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_ZOMBIE);
  1910.         }
  1911.         else
  1912.         {
  1913.                 // No one wins
  1914.                 set_hudmessage(0, 200, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  1915.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_NO_ONE")
  1916.                
  1917.                 // Play win sound
  1918.                 ArrayGetString(sound_win_no_one, random_num(0, ArraySize(sound_win_no_one) - 1), sound, charsmax(sound))
  1919.                 PlaySound(sound)
  1920.                
  1921.                 // Round end forward
  1922.                 ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_NO_ONE);
  1923.         }
  1924.        
  1925.         // Balance the teams
  1926.         balance_teams()
  1927. }
  1928.  
  1929. // Event Map Ended
  1930. public event_intermission()
  1931. {
  1932.         // Remove ambience sounds task
  1933.         remove_task(TASK_AMBIENCESOUNDS)
  1934. }
  1935.  
  1936. // BP Ammo update
  1937. public event_ammo_x(id)
  1938. {
  1939.         // Humans only
  1940.         if (g_zombie[id])
  1941.                 return;
  1942.        
  1943.         // Get ammo type
  1944.         static type
  1945.         type = read_data(1)
  1946.        
  1947.         // Unknown ammo type
  1948.         if (type >= sizeof AMMOWEAPON)
  1949.                 return;
  1950.        
  1951.         // Get weapon's id
  1952.         static weapon
  1953.         weapon = AMMOWEAPON[type]
  1954.        
  1955.         // Primary and secondary only
  1956.         if (MAXBPAMMO[weapon] <= 2)
  1957.                 return;
  1958.        
  1959.         // Get ammo amount
  1960.         static amount
  1961.         amount = read_data(2)
  1962.        
  1963.         // Unlimited BP Ammo?
  1964.         if (g_survivor[id] ? get_pcvar_num(cvar_survinfammo) : get_pcvar_num(cvar_infammo))
  1965.         {
  1966.                 if (amount < MAXBPAMMO[weapon])
  1967.                 {
  1968.                         // The BP Ammo refill code causes the engine to send a message, but we
  1969.                         // can't have that in this forward or we risk getting some recursion bugs.
  1970.                         // For more info see: https://bugs.alliedmods.net/show_bug.cgi?id=3664
  1971.                         static args[1]
  1972.                         args[0] = weapon
  1973.                         set_task(0.1, "refill_bpammo", id, args, sizeof args)
  1974.                 }
  1975.         }
  1976.         // Bots automatically buy ammo when needed
  1977.         else if (g_isbot[id] && amount <= BUYAMMO[weapon])
  1978.         {
  1979.                 // Task needed for the same reason as above
  1980.                 set_task(0.1, "clcmd_buyammo", id)
  1981.         }
  1982. }
  1983.  
  1984. /*================================================================================
  1985.  [Main Forwards]
  1986. =================================================================================*/
  1987.  
  1988. // Entity Spawn Forward
  1989. public fw_Spawn(entity)
  1990. {
  1991.         // Invalid entity
  1992.         if (!pev_valid(entity)) return FMRES_IGNORED;
  1993.        
  1994.         // Get classname
  1995.         new classname[32], objective[32], size = ArraySize(g_objective_ents)
  1996.         pev(entity, pev_classname, classname, charsmax(classname))
  1997.        
  1998.         // Check whether it needs to be removed
  1999.         for (new i = 0; i < size; i++)
  2000.         {
  2001.                 ArrayGetString(g_objective_ents, i, objective, charsmax(objective))
  2002.                
  2003.                 if (equal(classname, objective))
  2004.                 {
  2005.                         engfunc(EngFunc_RemoveEntity, entity)
  2006.                         return FMRES_SUPERCEDE;
  2007.                 }
  2008.         }
  2009.        
  2010.         return FMRES_IGNORED;
  2011. }
  2012.  
  2013. // Sound Precache Forward
  2014. public fw_PrecacheSound(const sound[])
  2015. {
  2016.         // Block all those unneeeded hostage sounds
  2017.         if (equal(sound, "hostage", 7))
  2018.                 return FMRES_SUPERCEDE;
  2019.        
  2020.         return FMRES_IGNORED;
  2021. }
  2022.  
  2023. // Ham Player Spawn Post Forward
  2024. public fw_PlayerSpawn_Post(id)
  2025. {
  2026.         // Not alive or didn't join a team yet
  2027.         if (!is_user_alive(id) || !fm_cs_get_user_team(id))
  2028.                 return;
  2029.        
  2030.         // Player spawned
  2031.         g_isalive[id] = true
  2032.        
  2033.         // Remove previous tasks
  2034.         remove_task(id+TASK_SPAWN)
  2035.         remove_task(id+TASK_MODEL)
  2036.         remove_task(id+TASK_BLOOD)
  2037.         remove_task(id+TASK_AURA)
  2038.         remove_task(id+TASK_BURN)
  2039.         remove_task(id+TASK_CHARGE)
  2040.         remove_task(id+TASK_FLASH)
  2041.         remove_task(id+TASK_NVISION)
  2042.        
  2043.         // Spawn at a random location?
  2044.         if (get_pcvar_num(cvar_randspawn)) do_random_spawn(id)
  2045.        
  2046.         // Hide money?
  2047.         if (get_pcvar_num(cvar_removemoney))
  2048.                 set_task(0.4, "task_hide_money", id+TASK_SPAWN)
  2049.        
  2050.         // Respawn player if he dies because of a worldspawn kill?
  2051.         if (get_pcvar_num(cvar_respawnworldspawnkill))
  2052.                 set_task(2.0, "respawn_player_task", id+TASK_SPAWN)
  2053.        
  2054.         // Spawn as zombie?
  2055.         if (g_respawn_as_zombie[id] && !g_newround)
  2056.         {
  2057.                 reset_vars(id, 0) // reset player vars
  2058.                 zombieme(id, 0, 0, 0, 0) // make him zombie right away
  2059.                 return;
  2060.         }
  2061.        
  2062.         // Reset player vars
  2063.         reset_vars(id, 0)
  2064.        
  2065.         // Show custom buy menu?
  2066.         if (get_pcvar_num(cvar_buycustom))
  2067.                 set_task(0.2, "show_menu_buy1", id+TASK_SPAWN)
  2068.        
  2069.         // Set health and gravity
  2070.         fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
  2071.         set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
  2072.        
  2073.         // Switch to CT if spawning mid-round
  2074.         if (!g_newround && fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  2075.         {
  2076.                 remove_task(id+TASK_TEAM)
  2077.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  2078.                 fm_user_team_update(id)
  2079.         }
  2080.        
  2081.         // Custom models stuff
  2082.         static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  2083.         already_has_model = false
  2084.        
  2085.         if (g_handle_models_on_separate_ent)
  2086.         {
  2087.                 // Set the right model
  2088.                 if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  2089.                 {
  2090.                         iRand = random_num(0, ArraySize(model_admin_human) - 1)
  2091.                         ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2092.                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  2093.                 }
  2094.                 else
  2095.                 {
  2096.                         iRand = random_num(0, ArraySize(model_human) - 1)
  2097.                         ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2098.                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  2099.                 }
  2100.                
  2101.                 // Set model on player model entity
  2102.                 fm_set_playermodel_ent(id)
  2103.                
  2104.                 // Remove glow on player model entity
  2105.                 fm_set_rendering(g_ent_playermodel[id])
  2106.         }
  2107.         else
  2108.         {
  2109.                 // Get current model for comparing it with the current one
  2110.                 fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  2111.                
  2112.                 // Set the right model, after checking that we don't already have it
  2113.                 if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  2114.                 {
  2115.                         size = ArraySize(model_admin_human)
  2116.                         for (i = 0; i < size; i++)
  2117.                         {
  2118.                                 ArrayGetString(model_admin_human, i, tempmodel, charsmax(tempmodel))
  2119.                                 if (equal(currentmodel, tempmodel)) already_has_model = true
  2120.                         }
  2121.                        
  2122.                         if (!already_has_model)
  2123.                         {
  2124.                                 iRand = random_num(0, size - 1)
  2125.                                 ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2126.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  2127.                         }
  2128.                 }
  2129.                 else
  2130.                 {
  2131.                         size = ArraySize(model_human)
  2132.                         for (i = 0; i < size; i++)
  2133.                         {
  2134.                                 ArrayGetString(model_human, i, tempmodel, charsmax(tempmodel))
  2135.                                 if (equal(currentmodel, tempmodel)) already_has_model = true
  2136.                         }
  2137.                        
  2138.                         if (!already_has_model)
  2139.                         {
  2140.                                 iRand = random_num(0, size - 1)
  2141.                                 ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2142.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  2143.                         }
  2144.                 }
  2145.                
  2146.                 // Need to change the model?
  2147.                 if (!already_has_model)
  2148.                 {
  2149.                         // An additional delay is offset at round start
  2150.                         // since SVC_BAD is more likely to be triggered there
  2151.                         if (g_newround)
  2152.                                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  2153.                         else
  2154.                                 fm_user_model_update(id+TASK_MODEL)
  2155.                 }
  2156.                
  2157.                 // Remove glow
  2158.                 fm_set_rendering(id)
  2159.         }
  2160.        
  2161.         // Bots stuff
  2162.         if (g_isbot[id])
  2163.         {
  2164.                 // Turn off NVG for bots
  2165.                 cs_set_user_nvg(id, 0)
  2166.                
  2167.                 // Automatically buy extra items/weapons after first zombie is chosen
  2168.                 if (get_pcvar_num(cvar_extraitems))
  2169.                 {
  2170.                         if (g_newround) set_task(10.0 + get_pcvar_float(cvar_warmup), "bot_buy_extras", id+TASK_SPAWN)
  2171.                         else set_task(10.0, "bot_buy_extras", id+TASK_SPAWN)
  2172.                 }
  2173.         }
  2174.        
  2175.         // Enable spawn protection for humans spawning mid-round
  2176.         if (!g_newround && get_pcvar_float(cvar_spawnprotection) > 0.0)
  2177.         {
  2178.                 // Do not take damage
  2179.                 g_nodamage[id] = true
  2180.                
  2181.                 // Make temporarily invisible
  2182.                 set_pev(id, pev_effects, pev(id, pev_effects) | EF_NODRAW)
  2183.                
  2184.                 // Set task to remove it
  2185.                 set_task(get_pcvar_float(cvar_spawnprotection), "remove_spawn_protection", id+TASK_SPAWN)
  2186.         }
  2187.        
  2188.         // Set the flashlight charge task to update battery status
  2189.         if (g_cached_customflash)
  2190.                 set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
  2191.        
  2192.         // Replace weapon models (bugfix)
  2193.         static weapon_ent
  2194.         weapon_ent = fm_cs_get_current_weapon_ent(id)
  2195.         if (pev_valid(weapon_ent)) replace_weapon_models(id, cs_get_weapon_id(weapon_ent))
  2196.        
  2197.         // Last Zombie Check
  2198.         fnCheckLastZombie()
  2199. }
  2200.  
  2201. // Ham Player Killed Forward
  2202. public fw_PlayerKilled(victim, attacker, shouldgib)
  2203. {
  2204.         // Player killed
  2205.         g_isalive[victim] = false
  2206.        
  2207.         // Enable dead players nightvision
  2208.         set_task(0.1, "spec_nvision", victim)
  2209.        
  2210.         // Disable nightvision when killed (bugfix)
  2211.         if (get_pcvar_num(cvar_nvggive) == 0 && g_nvision[victim])
  2212.         {
  2213.                 if (get_pcvar_num(cvar_customnvg)) remove_task(victim+TASK_NVISION)
  2214.                 else if (g_nvisionenabled[victim]) set_user_gnvision(victim, 0)
  2215.                 g_nvision[victim] = false
  2216.                 g_nvisionenabled[victim] = false
  2217.         }
  2218.        
  2219.         // Turn off nightvision when killed (bugfix)
  2220.         if (get_pcvar_num(cvar_nvggive) == 2 && g_nvision[victim] && g_nvisionenabled[victim])
  2221.         {
  2222.                 if (get_pcvar_num(cvar_customnvg)) remove_task(victim+TASK_NVISION)
  2223.                 else set_user_gnvision(victim, 0)
  2224.                 g_nvisionenabled[victim] = false
  2225.         }
  2226.        
  2227.         // Turn off custom flashlight when killed
  2228.         if (g_cached_customflash)
  2229.         {
  2230.                 // Turn it off
  2231.                 g_flashlight[victim] = false
  2232.                 g_flashbattery[victim] = 100
  2233.                
  2234.                 // Remove previous tasks
  2235.                 remove_task(victim+TASK_CHARGE)
  2236.                 remove_task(victim+TASK_FLASH)
  2237.         }
  2238.        
  2239.         // Stop bleeding/burning/aura when killed
  2240.         if (g_zombie[victim])
  2241.         {
  2242.                 remove_task(victim+TASK_BLOOD)
  2243.                 remove_task(victim+TASK_AURA)
  2244.                 remove_task(victim+TASK_BURN)
  2245.         }
  2246.        
  2247.         // Nemesis explodes!
  2248.         if (g_nemesis[victim])
  2249.                 SetHamParamInteger(3, 2)
  2250.        
  2251.         // Get deathmatch mode status and whether the player killed himself
  2252.         static selfkill
  2253.         selfkill = (victim == attacker || !is_user_valid_connected(attacker)) ? true : false
  2254.        
  2255.         // Respawn if deathmatch is enabled
  2256.         if (get_pcvar_num(cvar_deathmatch))
  2257.         {
  2258.                 // Respawn on suicide?
  2259.                 if (selfkill && !get_pcvar_num(cvar_respawnonsuicide))
  2260.                         return;
  2261.                
  2262.                 // Respawn if only the last human is left?
  2263.                 if (!get_pcvar_num(cvar_respawnafterlast) && fnGetHumans() <= 1)
  2264.                         return;
  2265.                
  2266.                 // Respawn if human/zombie/nemesis/survivor?
  2267.                 if ((g_zombie[victim] && !g_nemesis[victim] && !get_pcvar_num(cvar_respawnzomb)) || (!g_zombie[victim] && !g_survivor[victim] && !get_pcvar_num(cvar_respawnhum)) || (g_nemesis[victim] && !get_pcvar_num(cvar_respawnnem)) || (g_survivor[victim] && !get_pcvar_num(cvar_respawnsurv)))
  2268.                         return;
  2269.                
  2270.                 // Respawn as zombie?
  2271.                 if (get_pcvar_num(cvar_deathmatch) == 2 || (get_pcvar_num(cvar_deathmatch) == 3 && random_num(0, 1)) || (get_pcvar_num(cvar_deathmatch) == 4 && fnGetZombies() < fnGetAlive()/2))
  2272.                         g_respawn_as_zombie[victim] = true
  2273.                
  2274.                 // Set the respawn task
  2275.                 set_task(get_pcvar_float(cvar_spawndelay), "respawn_player_task", victim+TASK_SPAWN)
  2276.         }
  2277.        
  2278.         // Killed by a non-player entity or self killed
  2279.         if (selfkill) return;
  2280.        
  2281.         // Ignore Nemesis/Survivor Frags?
  2282.         if ((g_nemesis[attacker] && get_pcvar_num(cvar_nemignorefrags)) || (g_survivor[attacker] && get_pcvar_num(cvar_survignorefrags)))
  2283.                 RemoveFrags(attacker, victim)
  2284.        
  2285.         // Zombie/nemesis killed human, reward ammo packs
  2286.         if (g_zombie[attacker] && (!g_nemesis[attacker] || !get_pcvar_num(cvar_nemignoreammo)))
  2287.                 g_ammopacks[attacker] += get_pcvar_num(cvar_ammoinfect)
  2288.        
  2289.         // Human killed zombie, add up the extra frags for kill
  2290.         if (!g_zombie[attacker] && get_pcvar_num(cvar_fragskill) > 1)
  2291.                 UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragskill) - 1, 0, 0)
  2292.        
  2293.         // Zombie killed human, add up the extra frags for kill
  2294.         if (g_zombie[attacker] && get_pcvar_num(cvar_fragsinfect) > 1)
  2295.                 UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragsinfect) - 1, 0, 0)
  2296. }
  2297.  
  2298. // Ham Player Killed Post Forward
  2299. public fw_PlayerKilled_Post()
  2300. {
  2301.         // Last Zombie Check
  2302.         fnCheckLastZombie()
  2303. }
  2304.  
  2305. // Ham Take Damage Forward
  2306. public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type)
  2307. {
  2308.         // Non-player damage or self damage
  2309.         if (victim == attacker || !is_user_valid_connected(attacker))
  2310.                 return HAM_IGNORED;
  2311.        
  2312.         // New round starting or round ended
  2313.         if (g_newround || g_endround)
  2314.                 return HAM_SUPERCEDE;
  2315.        
  2316.         // Victim shouldn't take damage or victim is frozen
  2317.         if (g_nodamage[victim] || g_frozen[victim])
  2318.                 return HAM_SUPERCEDE;
  2319.        
  2320.         // Prevent friendly fire
  2321.         if (g_zombie[attacker] == g_zombie[victim])
  2322.                 return HAM_SUPERCEDE;
  2323.        
  2324.         // Attacker is human...
  2325.         if (!g_zombie[attacker])
  2326.         {
  2327.                 // Armor multiplier for the final damage on normal zombies
  2328.                 if (!g_nemesis[victim])
  2329.                 {
  2330.                         damage *= get_pcvar_float(cvar_zombiearmor)
  2331.                         SetHamParamFloat(4, damage)
  2332.                 }
  2333.                
  2334.                 // Reward ammo packs
  2335.                 if (!g_survivor[attacker] || !get_pcvar_num(cvar_survignoreammo))
  2336.                 {
  2337.                         // Store damage dealt
  2338.                         g_damagedealt[attacker] += floatround(damage)
  2339.                        
  2340.                         // Reward ammo packs for every [ammo damage] dealt
  2341.                         while (g_damagedealt[attacker] > get_pcvar_num(cvar_ammodamage))
  2342.                         {
  2343.                                 g_ammopacks[attacker]++
  2344.                                 g_damagedealt[attacker] -= get_pcvar_num(cvar_ammodamage)
  2345.                         }
  2346.                 }
  2347.                
  2348.                 return HAM_IGNORED;
  2349.         }
  2350.        
  2351.         // Attacker is zombie...
  2352.        
  2353.         // Prevent infection/damage by HE grenade (bugfix)
  2354.         if (damage_type & DMG_HEGRENADE)
  2355.                 return HAM_SUPERCEDE;
  2356.        
  2357.         // Nemesis?
  2358.         if (g_nemesis[attacker])
  2359.         {
  2360.                 // Ignore nemesis damage override if damage comes from a 3rd party entity
  2361.                 // (to prevent this from affecting a sub-plugin's rockets e.g.)
  2362.                 if (inflictor == attacker)
  2363.                 {
  2364.                         // Set nemesis damage
  2365.                         SetHamParamFloat(4, get_pcvar_float(cvar_nemdamage))
  2366.                 }
  2367.                
  2368.                 return HAM_IGNORED;
  2369.         }
  2370.        
  2371.         // Last human or not an infection round
  2372.         if (g_survround || g_nemround || g_swarmround || g_plagueround || fnGetHumans() == 1)
  2373.                 return HAM_IGNORED; // human is killed
  2374.        
  2375.         // Does human armor need to be reduced before infecting?
  2376.         if (get_pcvar_num(cvar_humanarmor))
  2377.         {
  2378.                 // Get victim armor
  2379.                 static Float:armor
  2380.                 pev(victim, pev_armorvalue, armor)
  2381.                
  2382.                 // Block the attack if he has some
  2383.                 if (armor > 0.0)
  2384.                 {
  2385.                         emit_sound(victim, CHAN_BODY, sound_armorhit, 1.0, ATTN_NORM, 0, PITCH_NORM)
  2386.                         set_pev(victim, pev_armorvalue, floatmax(0.0, armor - damage))
  2387.                         return HAM_SUPERCEDE;
  2388.                 }
  2389.         }
  2390.        
  2391.         // Infection allowed
  2392.         zombieme(victim, attacker, 0, 0, 1) // turn into zombie
  2393.         return HAM_SUPERCEDE;
  2394. }
  2395.  
  2396. // Ham Take Damage Post Forward
  2397. public fw_TakeDamage_Post(victim)
  2398. {
  2399.         // --- Check if victim should be Pain Shock Free ---
  2400.        
  2401.         // Check if proper CVARs are enabled
  2402.         if (g_zombie[victim])
  2403.         {
  2404.                 if (g_nemesis[victim])
  2405.                 {
  2406.                         if (!get_pcvar_num(cvar_nempainfree)) return;
  2407.                 }
  2408.                 else
  2409.                 {
  2410.                         switch (get_pcvar_num(cvar_zombiepainfree))
  2411.                         {
  2412.                                 case 0: return;
  2413.                                 case 2: if (!g_lastzombie[victim]) return;
  2414.                         }
  2415.                 }
  2416.         }
  2417.         else
  2418.         {
  2419.                 if (g_survivor[victim])
  2420.                 {
  2421.                         if (!get_pcvar_num(cvar_survpainfree)) return;
  2422.                 }
  2423.                 else return;
  2424.         }
  2425.        
  2426.         // Set pain shock free offset
  2427.         set_pdata_float(victim, OFFSET_PAINSHOCK, 1.0, OFFSET_LINUX)
  2428. }
  2429.  
  2430. // Ham Trace Attack Forward
  2431. public fw_TraceAttack(victim, attacker, Float:damage, Float:direction[3], tracehandle, damage_type)
  2432. {
  2433.         // Non-player damage or self damage
  2434.         if (victim == attacker || !is_user_valid_connected(attacker))
  2435.                 return HAM_IGNORED;
  2436.        
  2437.         // New round starting or round ended
  2438.         if (g_newround || g_endround)
  2439.                 return HAM_SUPERCEDE;
  2440.        
  2441.         // Victim shouldn't take damage or victim is frozen
  2442.         if (g_nodamage[victim] || g_frozen[victim])
  2443.                 return HAM_SUPERCEDE;
  2444.        
  2445.         // Prevent friendly fire
  2446.         if (g_zombie[attacker] == g_zombie[victim])
  2447.                 return HAM_SUPERCEDE;
  2448.        
  2449.         // Victim isn't a zombie or not bullet damage, nothing else to do here
  2450.         if (!g_zombie[victim] || !(damage_type & DMG_BULLET))
  2451.                 return HAM_IGNORED;
  2452.        
  2453.         // If zombie hitzones are enabled, check whether we hit an allowed one
  2454.         if (get_pcvar_num(cvar_hitzones) && !g_nemesis[victim] && !(get_pcvar_num(cvar_hitzones) & (1<<get_tr2(tracehandle, TR_iHitgroup))))
  2455.                 return HAM_SUPERCEDE;
  2456.        
  2457.         // Knockback disabled, nothing else to do here
  2458.         if (!get_pcvar_num(cvar_knockback))
  2459.                 return HAM_IGNORED;
  2460.        
  2461.         // Nemesis knockback disabled, nothing else to do here
  2462.         if (g_nemesis[victim] && get_pcvar_float(cvar_nemknockback) == 0.0)
  2463.                 return HAM_IGNORED;
  2464.        
  2465.         // Get whether the victim is in a crouch state
  2466.         static ducking
  2467.         ducking = pev(victim, pev_flags) & (FL_DUCKING | FL_ONGROUND) == (FL_DUCKING | FL_ONGROUND)
  2468.        
  2469.         // Zombie knockback when ducking disabled
  2470.         if (ducking && get_pcvar_float(cvar_knockbackducking) == 0.0)
  2471.                 return HAM_IGNORED;
  2472.        
  2473.         // Get distance between players
  2474.         static origin1[3], origin2[3]
  2475.         get_user_origin(victim, origin1)
  2476.         get_user_origin(attacker, origin2)
  2477.        
  2478.         // Max distance exceeded
  2479.         if (get_distance(origin1, origin2) > get_pcvar_num(cvar_knockbackdist))
  2480.                 return HAM_IGNORED;
  2481.        
  2482.         // Get victim's velocity
  2483.         static Float:velocity[3]
  2484.         pev(victim, pev_velocity, velocity)
  2485.        
  2486.         // Use damage on knockback calculation
  2487.         if (get_pcvar_num(cvar_knockbackdamage))
  2488.                 xs_vec_mul_scalar(direction, damage, direction)
  2489.        
  2490.         // Use weapon power on knockback calculation
  2491.         if (get_pcvar_num(cvar_knockbackpower) && kb_weapon_power[g_currentweapon[attacker]] > 0.0)
  2492.                 xs_vec_mul_scalar(direction, kb_weapon_power[g_currentweapon[attacker]], direction)
  2493.        
  2494.         // Apply ducking knockback multiplier
  2495.         if (ducking)
  2496.                 xs_vec_mul_scalar(direction, get_pcvar_float(cvar_knockbackducking), direction)
  2497.        
  2498.         // Apply zombie class/nemesis knockback multiplier
  2499.         if (g_nemesis[victim])
  2500.                 xs_vec_mul_scalar(direction, get_pcvar_float(cvar_nemknockback), direction)
  2501.         else
  2502.                 xs_vec_mul_scalar(direction, g_zombie_knockback[victim], direction)
  2503.        
  2504.         // Add up the new vector
  2505.         xs_vec_add(velocity, direction, direction)
  2506.        
  2507.         // Should knockback also affect vertical velocity?
  2508.         if (!get_pcvar_num(cvar_knockbackzvel))
  2509.                 direction[2] = velocity[2]
  2510.        
  2511.         // Set the knockback'd victim's velocity
  2512.         set_pev(victim, pev_velocity, direction)
  2513.        
  2514.         return HAM_IGNORED;
  2515. }
  2516.  
  2517. // Ham Use Stationary Gun Forward
  2518. public fw_UseStationary(entity, caller, activator, use_type)
  2519. {
  2520.         // Prevent zombies from using stationary guns
  2521.         if (use_type == USE_USING && is_user_valid_connected(caller) && g_zombie[caller])
  2522.                 return HAM_SUPERCEDE;
  2523.        
  2524.         return HAM_IGNORED;
  2525. }
  2526.  
  2527. // Ham Use Stationary Gun Post Forward
  2528. public fw_UseStationary_Post(entity, caller, activator, use_type)
  2529. {
  2530.         // Someone stopped using a stationary gun
  2531.         if (use_type == USE_STOPPED && is_user_valid_connected(caller))
  2532.                 replace_weapon_models(caller, g_currentweapon[caller]) // replace weapon models (bugfix)
  2533. }
  2534.  
  2535. // Ham Use Pushable Forward
  2536. public fw_UsePushable()
  2537. {
  2538.         // Prevent speed bug with pushables?
  2539.         if (get_pcvar_num(cvar_blockpushables))
  2540.                 return HAM_SUPERCEDE;
  2541.        
  2542.         return HAM_IGNORED;
  2543. }
  2544.  
  2545. // Ham Weapon Touch Forward
  2546. public fw_TouchWeapon(weapon, id)
  2547. {
  2548.         // Not a player
  2549.         if (!is_user_valid_connected(id))
  2550.                 return HAM_IGNORED;
  2551.        
  2552.         // Dont pickup weapons if zombie or survivor (+PODBot MM fix)
  2553.         if (g_zombie[id] || (g_survivor[id] && !g_isbot[id]))
  2554.                 return HAM_SUPERCEDE;
  2555.        
  2556.         return HAM_IGNORED;
  2557. }
  2558.  
  2559. // Ham Weapon Pickup Forward
  2560. public fw_AddPlayerItem(id, weapon_ent)
  2561. {
  2562.         // HACK: Retrieve our custom extra ammo from the weapon
  2563.         static extra_ammo
  2564.         extra_ammo = pev(weapon_ent, PEV_ADDITIONAL_AMMO)
  2565.        
  2566.         // If present
  2567.         if (extra_ammo)
  2568.         {
  2569.                 // Get weapon's id
  2570.                 static weaponid
  2571.                 weaponid = cs_get_weapon_id(weapon_ent)
  2572.                
  2573.                 // Add to player's bpammo
  2574.                 ExecuteHamB(Ham_GiveAmmo, id, extra_ammo, AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  2575.                 set_pev(weapon_ent, PEV_ADDITIONAL_AMMO, 0)
  2576.         }
  2577. }
  2578.  
  2579. // Ham Weapon Deploy Forward
  2580. public fw_Item_Deploy_Post(weapon_ent)
  2581. {
  2582.         // Get weapon's owner
  2583.         static owner
  2584.         owner = fm_cs_get_weapon_ent_owner(weapon_ent)
  2585.        
  2586.         // Get weapon's id
  2587.         static weaponid
  2588.         weaponid = cs_get_weapon_id(weapon_ent)
  2589.        
  2590.         // Store current weapon's id for reference
  2591.         g_currentweapon[owner] = weaponid
  2592.        
  2593.         // Replace weapon models with custom ones
  2594.         replace_weapon_models(owner, weaponid)
  2595.        
  2596.         // Zombie not holding an allowed weapon for some reason
  2597.         if (g_zombie[owner] && !((1<<weaponid) & ZOMBIE_ALLOWED_WEAPONS_BITSUM))
  2598.         {
  2599.                 // Switch to knife
  2600.                 g_currentweapon[owner] = CSW_KNIFE
  2601.                 engclient_cmd(owner, "weapon_knife")
  2602.         }
  2603. }
  2604.  
  2605. // WeaponMod bugfix
  2606. //forward wpn_gi_reset_weapon(id);
  2607. public wpn_gi_reset_weapon(id)
  2608. {
  2609.         // Replace knife model
  2610.         replace_weapon_models(id, CSW_KNIFE)
  2611. }
  2612.  
  2613. // Client joins the game
  2614. public client_putinserver(id)
  2615. {
  2616.         // Plugin disabled?
  2617.         if (!g_pluginenabled) return;
  2618.        
  2619.         // Player joined
  2620.         g_isconnected[id] = true
  2621.        
  2622.         // Cache player's name
  2623.         get_user_name(id, g_playername[id], charsmax(g_playername[]))
  2624.        
  2625.         // Initialize player vars
  2626.         reset_vars(id, 1)
  2627.        
  2628.         // Load player stats?
  2629.         if (get_pcvar_num(cvar_statssave)) load_stats(id)
  2630.        
  2631.         set_task( 3.0 , "respawn_welcome", id)
  2632.  
  2633.         // Set some tasks for humans only
  2634.         if (!is_user_bot(id))
  2635.         {
  2636.                 // Set the custom HUD display task
  2637.                 set_task(1.0, "ShowHUD", id+TASK_SHOWHUD, _, _, "b")
  2638.                
  2639.                 // Disable minmodels for clients to see zombies properly
  2640.                 set_task(5.0, "disable_minmodels", id)
  2641.         }
  2642.         else
  2643.         {
  2644.                 // Set bot flag
  2645.                 g_isbot[id] = true
  2646.                
  2647.                 // CZ bots seem to use a different "classtype" for player entities
  2648.                 // (or something like that) which needs to be hooked separately
  2649.                 if (!g_hamczbots && cvar_botquota)
  2650.                 {
  2651.                         // Set a task to let the private data initialize
  2652.                         set_task(0.1, "register_ham_czbots", id)
  2653.                 }
  2654.         }
  2655. }
  2656. // Respawn check
  2657. public respawn_welcome(id)
  2658. {
  2659.         static team
  2660.         team = fm_cs_get_user_team(id)
  2661.  
  2662.         if( id )
  2663.         {
  2664.                 if( is_user_connected(id) && !is_user_connecting(id) )
  2665.                 {
  2666.                         if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  2667.                         {
  2668.                                 set_task( 1.0 , "respawn_welcome", id)
  2669.                         }
  2670.                         else
  2671.                         {
  2672.  
  2673.                                 set_task( 1.0 , "deadmau5_respawn_now", id)
  2674.  
  2675.                         }
  2676.                                        
  2677.                 }
  2678.                 else
  2679.                 {
  2680.                                 set_task( 1.0 , "respawn_welcome", id)
  2681.                 }
  2682.         }
  2683.         else
  2684.         {
  2685.                 new iPlayers[32], iNum
  2686.                 get_players(iPlayers, iNum, "c")
  2687.  
  2688.                 for(--iNum; iNum>=0; iNum--)
  2689.                 {
  2690.                         id = iPlayers[iNum]
  2691.  
  2692.                         if( !is_user_connecting(id) )
  2693.                         {
  2694.                                 if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  2695.                                 {
  2696.                                         set_task( 1.0 , "respawn_welcome", id)
  2697.                                 }
  2698.                                 else
  2699.                                 {
  2700.                                         set_task( 1.0 , "deadmau5_respawn_now", id)
  2701.  
  2702.                                 }
  2703.  
  2704.                         }
  2705.                         else
  2706.                         {
  2707.                                 set_task( 1.0 , "respawn_welcome", id)
  2708.                         }
  2709.                 }                
  2710.         }
  2711. }
  2712.  
  2713. // Respawn now!
  2714. public deadmau5_respawn_now(id)
  2715. {
  2716.  
  2717.         if (!is_user_alive(id))
  2718.         {
  2719.  
  2720.                 if(g_nemround)
  2721.                 {
  2722.                         set_task( 7.5 , "deadmau5_welcome_text", id)
  2723.                 }
  2724.                 else if(g_survround)
  2725.                 {
  2726.                         set_task( 7.5 , "deadmau5_welcome_text", id)
  2727.                 }
  2728.                 else if(g_plagueround)
  2729.                 {
  2730.                         set_task( 7.5 , "deadmau5_welcome_text", id)
  2731.                 }
  2732.                 else
  2733.                 {
  2734.                         set_task( 7.5 , "deadmau5_welcome_text", id)
  2735.  
  2736.                         set_task(5.0, "respawn_player_task", id+TASK_SPAWN)
  2737.                 }
  2738.         }
  2739. }
  2740.  
  2741. public deadmau5_welcome_text(id)
  2742. {
  2743.         set_hudmessage(0, 125, 0, -1.0, 0.17, 1, 2.0, 2.0, 4.0, 2.0, -1)
  2744.         ShowSyncHudMsg(id, g_MsgSync, "Sky Arena ZM vam zeli ugodnu igru!^n IP Servera: 193.192.59.74:27111")
  2745. }
  2746.  
  2747. // Client leaving
  2748. public fw_ClientDisconnect(id)
  2749. {
  2750.         // Check that we still have both humans and zombies to keep the round going
  2751.         if (g_isalive[id]) check_round(id)
  2752.        
  2753.         // Temporarily save player stats?
  2754.         if (get_pcvar_num(cvar_statssave)) save_stats(id)
  2755.        
  2756.         // Remove previous tasks
  2757.         remove_task(id+TASK_TEAM)
  2758.         remove_task(id+TASK_MODEL)
  2759.         remove_task(id+TASK_FLASH)
  2760.         remove_task(id+TASK_CHARGE)
  2761.         remove_task(id+TASK_SPAWN)
  2762.         remove_task(id+TASK_BLOOD)
  2763.         remove_task(id+TASK_AURA)
  2764.         remove_task(id+TASK_BURN)
  2765.         remove_task(id+TASK_NVISION)
  2766.         remove_task(id+TASK_SHOWHUD)
  2767.        
  2768.         if (g_handle_models_on_separate_ent)
  2769.         {
  2770.                 // Remove custom model entities
  2771.                 fm_remove_model_ents(id)
  2772.         }
  2773.        
  2774.         // Player left, clear cached flags
  2775.         g_isconnected[id] = false
  2776.         g_isbot[id] = false
  2777.         g_isalive[id] = false
  2778. }
  2779.  
  2780. // Client left
  2781. public fw_ClientDisconnect_Post()
  2782. {
  2783.         // Last Zombie Check
  2784.         fnCheckLastZombie()
  2785. }
  2786.  
  2787. // Client Kill Forward
  2788. public fw_ClientKill()
  2789. {
  2790.         // Prevent players from killing themselves?
  2791.         if (get_pcvar_num(cvar_blocksuicide))
  2792.                 return FMRES_SUPERCEDE;
  2793.        
  2794.         return FMRES_IGNORED;
  2795. }
  2796.  
  2797. // Emit Sound Forward
  2798. public fw_EmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch)
  2799. {
  2800.         // Block all those unneeeded hostage sounds
  2801.         if (sample[0] == 'h' && sample[1] == 'o' && sample[2] == 's' && sample[3] == 't' && sample[4] == 'a' && sample[5] == 'g' && sample[6] == 'e')
  2802.                 return FMRES_SUPERCEDE;
  2803.        
  2804.         // Replace these next sounds for zombies only
  2805.         if (!is_user_valid_connected(id) || !g_zombie[id])
  2806.                 return FMRES_IGNORED;
  2807.        
  2808.         static sound[64]
  2809.        
  2810.         // Zombie being hit
  2811.         if (sample[7] == 'b' && sample[8] == 'h' && sample[9] == 'i' && sample[10] == 't')
  2812.         {
  2813.                 if (g_nemesis[id])
  2814.                 {
  2815.                         ArrayGetString(nemesis_pain, random_num(0, ArraySize(nemesis_pain) - 1), sound, charsmax(sound))
  2816.                         emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2817.                 }
  2818.                 else
  2819.                 {
  2820.                         ArrayGetString(zombie_pain, random_num(0, ArraySize(zombie_pain) - 1), sound, charsmax(sound))
  2821.                         emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2822.                 }
  2823.                 return FMRES_SUPERCEDE;
  2824.         }
  2825.        
  2826.         // Zombie attacks with knife
  2827.         if (sample[8] == 'k' && sample[9] == 'n' && sample[10] == 'i')
  2828.         {
  2829.                 if (sample[14] == 's' && sample[15] == 'l' && sample[16] == 'a') // slash
  2830.                 {
  2831.                         ArrayGetString(zombie_miss_slash, random_num(0, ArraySize(zombie_miss_slash) - 1), sound, charsmax(sound))
  2832.                         emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2833.                         return FMRES_SUPERCEDE;
  2834.                 }
  2835.                 if (sample[14] == 'h' && sample[15] == 'i' && sample[16] == 't') // hit
  2836.                 {
  2837.                         if (sample[17] == 'w') // wall
  2838.                         {
  2839.                                 ArrayGetString(zombie_miss_wall, random_num(0, ArraySize(zombie_miss_wall) - 1), sound, charsmax(sound))
  2840.                                 emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2841.                                 return FMRES_SUPERCEDE;
  2842.                         }
  2843.                         else
  2844.                         {
  2845.                                 ArrayGetString(zombie_hit_normal, random_num(0, ArraySize(zombie_hit_normal) - 1), sound, charsmax(sound))
  2846.                                 emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2847.                                 return FMRES_SUPERCEDE;
  2848.                         }
  2849.                 }
  2850.                 if (sample[14] == 's' && sample[15] == 't' && sample[16] == 'a') // stab
  2851.                 {
  2852.                         ArrayGetString(zombie_hit_stab, random_num(0, ArraySize(zombie_hit_stab) - 1), sound, charsmax(sound))
  2853.                         emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2854.                         return FMRES_SUPERCEDE;
  2855.                 }
  2856.         }
  2857.        
  2858.         // Zombie dies
  2859.         if (sample[7] == 'd' && ((sample[8] == 'i' && sample[9] == 'e') || (sample[8] == 'e' && sample[9] == 'a')))
  2860.         {
  2861.                 ArrayGetString(zombie_die, random_num(0, ArraySize(zombie_die) - 1), sound, charsmax(sound))
  2862.                 emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2863.                 return FMRES_SUPERCEDE;
  2864.         }
  2865.        
  2866.         // Zombie falls off
  2867.         if (sample[10] == 'f' && sample[11] == 'a' && sample[12] == 'l' && sample[13] == 'l')
  2868.         {
  2869.                 ArrayGetString(zombie_fall, random_num(0, ArraySize(zombie_fall) - 1), sound, charsmax(sound))
  2870.                 emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2871.                 return FMRES_SUPERCEDE;
  2872.         }
  2873.        
  2874.         return FMRES_IGNORED;
  2875. }
  2876.  
  2877. // Forward Set ClientKey Value -prevent CS from changing player models-
  2878. public fw_SetClientKeyValue(id, const infobuffer[], const key[])
  2879. {
  2880.         // Block CS model changes
  2881.         if (key[0] == 'm' && key[1] == 'o' && key[2] == 'd' && key[3] == 'e' && key[4] == 'l')
  2882.                 return FMRES_SUPERCEDE;
  2883.        
  2884.         return FMRES_IGNORED;
  2885. }
  2886.  
  2887. // Forward Client User Info Changed -prevent players from changing models-
  2888. public fw_ClientUserInfoChanged(id)
  2889. {
  2890.         // Cache player's name
  2891.         get_user_name(id, g_playername[id], charsmax(g_playername[]))
  2892.        
  2893.         if (!g_handle_models_on_separate_ent)
  2894.         {
  2895.                 // Get current model
  2896.                 static currentmodel[32]
  2897.                 fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  2898.                
  2899.                 // If they're different, set model again
  2900.                 if (!equal(currentmodel, g_playermodel[id]) && !task_exists(id+TASK_MODEL))
  2901.                         fm_cs_set_user_model(id+TASK_MODEL)
  2902.         }
  2903. }
  2904.  
  2905. // Forward Get Game Description
  2906. public fw_GetGameDescription()
  2907. {
  2908.         // Return the mod name so it can be easily identified
  2909.         forward_return(FMV_STRING, g_modname)
  2910.        
  2911.         return FMRES_SUPERCEDE;
  2912. }
  2913.  
  2914. // Forward Set Model
  2915. public fw_SetModel(entity, const model[])
  2916. {
  2917.         // We don't care
  2918.         if (strlen(model) < 8)
  2919.                 return;
  2920.        
  2921.         // Remove weapons?
  2922.         if (get_pcvar_float(cvar_removedropped) > 0.0)
  2923.         {
  2924.                 // Get entity's classname
  2925.                 static classname[10]
  2926.                 pev(entity, pev_classname, classname, charsmax(classname))
  2927.                
  2928.                 // Check if it's a weapon box
  2929.                 if (equal(classname, "weaponbox"))
  2930.                 {
  2931.                         // They get automatically removed when thinking
  2932.                         set_pev(entity, pev_nextthink, get_gametime() + get_pcvar_float(cvar_removedropped))
  2933.                         return;
  2934.                 }
  2935.         }
  2936.        
  2937.         // Narrow down our matches a bit
  2938.         if (model[7] != 'w' || model[8] != '_')
  2939.                 return;
  2940.        
  2941.         // Get damage time of grenade
  2942.         static Float:dmgtime
  2943.         pev(entity, pev_dmgtime, dmgtime)
  2944.        
  2945.         // Grenade not yet thrown
  2946.         if (dmgtime == 0.0)
  2947.                 return;
  2948.        
  2949.         // Get whether grenade's owner is a zombie
  2950.         if (g_zombie[pev(entity, pev_owner)])
  2951.         {
  2952.                 if (model[9] == 'h' && model[10] == 'e' && get_pcvar_num(cvar_extrainfbomb)) // Infection Bomb
  2953.                 {
  2954.                         // Give it a glow
  2955.                         fm_set_rendering(entity, kRenderFxGlowShell, 0, 200, 0, kRenderNormal, 16);
  2956.                        
  2957.                         // And a colored trail
  2958.                         message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  2959.                         write_byte(TE_BEAMFOLLOW) // TE id
  2960.                         write_short(entity) // entity
  2961.                         write_short(g_trailSpr) // sprite
  2962.                         write_byte(10) // life
  2963.                         write_byte(10) // width
  2964.                         write_byte(0) // r
  2965.                         write_byte(200) // g
  2966.                         write_byte(0) // b
  2967.                         write_byte(200) // brightness
  2968.                         message_end()
  2969.                        
  2970.                         // Set grenade type on the thrown grenade entity
  2971.                         set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_INFECTION)
  2972.                 }
  2973.         }
  2974.         else if (model[9] == 'h' && model[10] == 'e' && get_pcvar_num(cvar_firegrenades)) // Napalm Grenade
  2975.         {
  2976.                 // Give it a glow
  2977.                 fm_set_rendering(entity, kRenderFxGlowShell, 200, 0, 0, kRenderNormal, 16);
  2978.                
  2979.                 // And a colored trail
  2980.                 message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  2981.                 write_byte(TE_BEAMFOLLOW) // TE id
  2982.                 write_short(entity) // entity
  2983.                 write_short(g_trailSpr) // sprite
  2984.                 write_byte(10) // life
  2985.                 write_byte(10) // width
  2986.                 write_byte(200) // r
  2987.                 write_byte(0) // g
  2988.                 write_byte(0) // b
  2989.                 write_byte(200) // brightness
  2990.                 message_end()
  2991.                
  2992.                 // Set grenade type on the thrown grenade entity
  2993.                 set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_NAPALM)
  2994.         }
  2995.         else if (model[9] == 'f' && model[10] == 'l' && get_pcvar_num(cvar_frostgrenades)) // Frost Grenade
  2996.         {
  2997.                 // Give it a glow
  2998.                 fm_set_rendering(entity, kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 16);
  2999.                
  3000.                 // And a colored trail
  3001.                 message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  3002.                 write_byte(TE_BEAMFOLLOW) // TE id
  3003.                 write_short(entity) // entity
  3004.                 write_short(g_trailSpr) // sprite
  3005.                 write_byte(10) // life
  3006.                 write_byte(10) // width
  3007.                 write_byte(0) // r
  3008.                 write_byte(100) // g
  3009.                 write_byte(200) // b
  3010.                 write_byte(200) // brightness
  3011.                 message_end()
  3012.                
  3013.                 // Set grenade type on the thrown grenade entity
  3014.                 set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FROST)
  3015.         }
  3016.         else if (model[9] == 's' && model[10] == 'm' && get_pcvar_num(cvar_flaregrenades)) // Flare
  3017.         {
  3018.                 // Build flare's color
  3019.                 static rgb[3]
  3020.                 switch (get_pcvar_num(cvar_flarecolor))
  3021.                 {
  3022.                         case 0: // white
  3023.                         {
  3024.                                 rgb[0] = 255 // r
  3025.                                 rgb[1] = 255 // g
  3026.                                 rgb[2] = 255 // b
  3027.                         }
  3028.                         case 1: // red
  3029.                         {
  3030.                                 rgb[0] = random_num(50,255) // r
  3031.                                 rgb[1] = 0 // g
  3032.                                 rgb[2] = 0 // b
  3033.                         }
  3034.                         case 2: // green
  3035.                         {
  3036.                                 rgb[0] = 0 // r
  3037.                                 rgb[1] = random_num(50,255) // g
  3038.                                 rgb[2] = 0 // b
  3039.                         }
  3040.                         case 3: // blue
  3041.                         {
  3042.                                 rgb[0] = 0 // r
  3043.                                 rgb[1] = 0 // g
  3044.                                 rgb[2] = random_num(50,255) // b
  3045.                         }
  3046.                         case 4: // random (all colors)
  3047.                         {
  3048.                                 rgb[0] = random_num(50,200) // r
  3049.                                 rgb[1] = random_num(50,200) // g
  3050.                                 rgb[2] = random_num(50,200) // b
  3051.                         }
  3052.                         case 5: // random (r,g,b)
  3053.                         {
  3054.                                 switch (random_num(1, 3))
  3055.                                 {
  3056.                                         case 1: // red
  3057.                                         {
  3058.                                                 rgb[0] = random_num(50,255) // r
  3059.                                                 rgb[1] = 0 // g
  3060.                                                 rgb[2] = 0 // b
  3061.                                         }
  3062.                                         case 2: // green
  3063.                                         {
  3064.                                                 rgb[0] = 0 // r
  3065.                                                 rgb[1] = random_num(50,255) // g
  3066.                                                 rgb[2] = 0 // b
  3067.                                         }
  3068.                                         case 3: // blue
  3069.                                         {
  3070.                                                 rgb[0] = 0 // r
  3071.                                                 rgb[1] = 0 // g
  3072.                                                 rgb[2] = random_num(50,255) // b
  3073.                                         }
  3074.                                 }
  3075.                         }
  3076.                 }
  3077.                
  3078.                 // Give it a glow
  3079.                 fm_set_rendering(entity, kRenderFxGlowShell, rgb[0], rgb[1], rgb[2], kRenderNormal, 16);
  3080.                
  3081.                 // And a colored trail
  3082.                 message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  3083.                 write_byte(TE_BEAMFOLLOW) // TE id
  3084.                 write_short(entity) // entity
  3085.                 write_short(g_trailSpr) // sprite
  3086.                 write_byte(10) // life
  3087.                 write_byte(10) // width
  3088.                 write_byte(rgb[0]) // r
  3089.                 write_byte(rgb[1]) // g
  3090.                 write_byte(rgb[2]) // b
  3091.                 write_byte(200) // brightness
  3092.                 message_end()
  3093.                
  3094.                 // Set grenade type on the thrown grenade entity
  3095.                 set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FLARE)
  3096.                
  3097.                 // Set flare color on the thrown grenade entity
  3098.                 set_pev(entity, PEV_FLARE_COLOR, rgb)
  3099.         }
  3100. }
  3101.  
  3102. // Ham Grenade Think Forward
  3103. public fw_ThinkGrenade(entity)
  3104. {
  3105.         // Invalid entity
  3106.         if (!pev_valid(entity)) return HAM_IGNORED;
  3107.        
  3108.         // Get damage time of grenade
  3109.         static Float:dmgtime, Float:current_time
  3110.         pev(entity, pev_dmgtime, dmgtime)
  3111.         current_time = get_gametime()
  3112.        
  3113.         // Check if it's time to go off
  3114.         if (dmgtime > current_time)
  3115.                 return HAM_IGNORED;
  3116.        
  3117.         // Check if it's one of our custom nades
  3118.         switch (pev(entity, PEV_NADE_TYPE))
  3119.         {
  3120.                 case NADE_TYPE_INFECTION: // Infection Bomb
  3121.                 {
  3122.                         infection_explode(entity)
  3123.                         return HAM_SUPERCEDE;
  3124.                 }
  3125.                 case NADE_TYPE_NAPALM: // Napalm Grenade
  3126.                 {
  3127.                         fire_explode(entity)
  3128.                         return HAM_SUPERCEDE;
  3129.                 }
  3130.                 case NADE_TYPE_FROST: // Frost Grenade
  3131.                 {
  3132.                         frost_explode(entity)
  3133.                         return HAM_SUPERCEDE;
  3134.                 }
  3135.                 case NADE_TYPE_FLARE: // Flare
  3136.                 {
  3137.                         // Get its duration
  3138.                         static duration
  3139.                         duration = pev(entity, PEV_FLARE_DURATION)
  3140.                        
  3141.                         // Already went off, do lighting loop for the duration of PEV_FLARE_DURATION
  3142.                         if (duration > 0)
  3143.                         {
  3144.                                 // Check whether this is the last loop
  3145.                                 if (duration == 1)
  3146.                                 {
  3147.                                         // Get rid of the flare entity
  3148.                                         engfunc(EngFunc_RemoveEntity, entity)
  3149.                                         return HAM_SUPERCEDE;
  3150.                                 }
  3151.                                
  3152.                                 // Light it up!
  3153.                                 flare_lighting(entity, duration)
  3154.                                
  3155.                                 // Set time for next loop
  3156.                                 set_pev(entity, PEV_FLARE_DURATION, --duration)
  3157.                                 set_pev(entity, pev_dmgtime, current_time + 5.0)
  3158.                         }
  3159.                         // Light up when it's stopped on ground
  3160.                         else if ((pev(entity, pev_flags) & FL_ONGROUND) && fm_get_speed(entity) < 10)
  3161.                         {
  3162.                                 // Flare sound
  3163.                                 static sound[64]
  3164.                                 ArrayGetString(grenade_flare, random_num(0, ArraySize(grenade_flare) - 1), sound, charsmax(sound))
  3165.                                 emit_sound(entity, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  3166.                                
  3167.                                 // Set duration and start lightning loop on next think
  3168.                                 set_pev(entity, PEV_FLARE_DURATION, 1 + get_pcvar_num(cvar_flareduration)/5)
  3169.                                 set_pev(entity, pev_dmgtime, current_time + 0.1)
  3170.                         }
  3171.                         else
  3172.                         {
  3173.                                 // Delay explosion until we hit ground
  3174.                                 set_pev(entity, pev_dmgtime, current_time + 0.5)
  3175.                         }
  3176.                 }
  3177.         }
  3178.        
  3179.         return HAM_IGNORED;
  3180. }
  3181.  
  3182. // Forward CmdStart
  3183. public fw_CmdStart(id, handle)
  3184. {
  3185.         // Not alive
  3186.         if (!g_isalive[id])
  3187.                 return;
  3188.        
  3189.         // This logic looks kinda weird, but it should work in theory...
  3190.         // p = g_zombie[id], q = g_survivor[id], r = g_cached_customflash
  3191.         // ¬(p v q v (¬p ^ r)) <==> ¬p ^ ¬q ^ (p v ¬r)
  3192.         if (!g_zombie[id] && !g_survivor[id] && (g_zombie[id] || !g_cached_customflash))
  3193.                 return;
  3194.        
  3195.         // Check if it's a flashlight impulse
  3196.         if (get_uc(handle, UC_Impulse) != IMPULSE_FLASHLIGHT)
  3197.                 return;
  3198.        
  3199.         // Block it I say!
  3200.         set_uc(handle, UC_Impulse, 0)
  3201.        
  3202.         // Should human's custom flashlight be turned on?
  3203.         if (!g_zombie[id] && !g_survivor[id] && g_flashbattery[id] > 2 && get_gametime() - g_lastflashtime[id] > 1.2)
  3204.         {
  3205.                 // Prevent calling flashlight too quickly (bugfix)
  3206.                 g_lastflashtime[id] = get_gametime()
  3207.                
  3208.                 // Toggle custom flashlight
  3209.                 g_flashlight[id] = !(g_flashlight[id])
  3210.                
  3211.                 // Play flashlight toggle sound
  3212.                 emit_sound(id, CHAN_ITEM, sound_flashlight, 1.0, ATTN_NORM, 0, PITCH_NORM)
  3213.                
  3214.                 // Update flashlight status on the HUD
  3215.                 message_begin(MSG_ONE, g_msgFlashlight, _, id)
  3216.                 write_byte(g_flashlight[id]) // toggle
  3217.                 write_byte(g_flashbattery[id]) // battery
  3218.                 message_end()
  3219.                
  3220.                 // Remove previous tasks
  3221.                 remove_task(id+TASK_CHARGE)
  3222.                 remove_task(id+TASK_FLASH)
  3223.                
  3224.                 // Set the flashlight charge task
  3225.                 set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
  3226.                
  3227.                 // Call our custom flashlight task if enabled
  3228.                 if (g_flashlight[id]) set_task(0.1, "set_user_flashlight", id+TASK_FLASH, _, _, "b")
  3229.         }
  3230. }
  3231.  
  3232. // Forward Player PreThink
  3233. public fw_PlayerPreThink(id)
  3234. {
  3235.         // Not alive
  3236.         if (!g_isalive[id])
  3237.                 return;
  3238.        
  3239.         // Silent footsteps for zombies?
  3240.         if (g_cached_zombiesilent && g_zombie[id] && !g_nemesis[id])
  3241.                 set_pev(id, pev_flTimeStepSound, STEPTIME_SILENT)
  3242.        
  3243.         // Set Player MaxSpeed
  3244.         if (g_frozen[id])
  3245.         {
  3246.                 set_pev(id, pev_velocity, Float:{0.0,0.0,0.0}) // stop motion
  3247.                 set_pev(id, pev_maxspeed, 1.0) // prevent from moving
  3248.                 return; // shouldn't leap while frozen
  3249.         }
  3250.         else if (g_freezetime)
  3251.         {
  3252.                 return; // shouldn't leap while in freezetime
  3253.         }
  3254.         else
  3255.         {
  3256.                 if (g_zombie[id])
  3257.                 {
  3258.                         if (g_nemesis[id])
  3259.                                 set_pev(id, pev_maxspeed, g_cached_nemspd)
  3260.                         else
  3261.                                 set_pev(id, pev_maxspeed, g_zombie_spd[id])
  3262.                 }
  3263.                 else
  3264.                 {
  3265.                         if (g_survivor[id])
  3266.                                 set_pev(id, pev_maxspeed, g_cached_survspd)
  3267.                         else
  3268.                                 set_pev(id, pev_maxspeed, g_cached_humanspd)
  3269.                 }
  3270.         }
  3271.        
  3272.         // --- Check if player should leap ---
  3273.        
  3274.         // Check if proper CVARs are enabled and retrieve leap settings
  3275.         static Float:cooldown, Float:current_time
  3276.         if (g_zombie[id])
  3277.         {
  3278.                 if (g_nemesis[id])
  3279.                 {
  3280.                         if (!g_cached_leapnemesis) return;
  3281.                         cooldown = g_cached_leapnemesiscooldown
  3282.                 }
  3283.                 else
  3284.                 {
  3285.                         switch (g_cached_leapzombies)
  3286.                         {
  3287.                                 case 0: return;
  3288.                                 case 2: if (!g_firstzombie[id]) return;
  3289.                                 case 3: if (!g_lastzombie[id]) return;
  3290.                         }
  3291.                         cooldown = g_cached_leapzombiescooldown
  3292.                 }
  3293.         }
  3294.         else
  3295.         {
  3296.                 if (g_survivor[id])
  3297.                 {
  3298.                         if (!g_cached_leapsurvivor) return;
  3299.                         cooldown = g_cached_leapsurvivorcooldown
  3300.                 }
  3301.                 else return;
  3302.         }
  3303.        
  3304.         current_time = get_gametime()
  3305.        
  3306.         // Cooldown not over yet
  3307.         if (current_time - g_lastleaptime[id] < cooldown)
  3308.                 return;
  3309.        
  3310.         // Not doing a longjump (don't perform check for bots, they leap automatically)
  3311.         if (!g_isbot[id] && !(pev(id, pev_button) & (IN_JUMP | IN_DUCK) == (IN_JUMP | IN_DUCK)))
  3312.                 return;
  3313.        
  3314.         // Not on ground or not enough speed
  3315.         if (!(pev(id, pev_flags) & FL_ONGROUND) || fm_get_speed(id) < 80)
  3316.                 return;
  3317.        
  3318.         static Float:velocity[3]
  3319.        
  3320.         // Make velocity vector
  3321.         velocity_by_aim(id, g_survivor[id] ? get_pcvar_num(cvar_leapsurvivorforce) : g_nemesis[id] ? get_pcvar_num(cvar_leapnemesisforce) : get_pcvar_num(cvar_leapzombiesforce), velocity)
  3322.        
  3323.         // Set custom height
  3324.         velocity[2] = g_survivor[id] ? get_pcvar_float(cvar_leapsurvivorheight) : g_nemesis[id] ? get_pcvar_float(cvar_leapnemesisheight) : get_pcvar_float(cvar_leapzombiesheight)
  3325.        
  3326.         // Apply the new velocity
  3327.         set_pev(id, pev_velocity, velocity)
  3328.        
  3329.         // Update last leap time
  3330.         g_lastleaptime[id] = current_time
  3331. }
  3332.  
  3333. /*================================================================================
  3334.  [Client Commands]
  3335. =================================================================================*/
  3336.  
  3337. // Say "/zpmenu"
  3338. public clcmd_saymenu(id)
  3339. {
  3340.         show_menu_game(id) // show game menu
  3341. }
  3342.  
  3343. // Say "/unstuck"
  3344. public clcmd_sayunstuck(id)
  3345. {
  3346.         menu_game(id, 3) // try to get unstuck
  3347. }
  3348.  
  3349. // Nightvision toggle
  3350. public clcmd_nightvision(id)
  3351. {
  3352.         if (g_nvision[id])
  3353.         {
  3354.                 // Enable-disable
  3355.                 g_nvisionenabled[id] = !(g_nvisionenabled[id])
  3356.                
  3357.                 // Custom nvg?
  3358.                 if (get_pcvar_num(cvar_customnvg))
  3359.                 {
  3360.                         remove_task(id+TASK_NVISION)
  3361.                         if (g_nvisionenabled[id]) set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  3362.                 }
  3363.                 else
  3364.                         set_user_gnvision(id, g_nvisionenabled[id])
  3365.         }
  3366.        
  3367.         return PLUGIN_HANDLED;
  3368. }
  3369.  
  3370. // Weapon Drop
  3371. public clcmd_drop(id)
  3372. {
  3373.         // Survivor should stick with its weapon
  3374.         if (g_survivor[id])
  3375.                 return PLUGIN_HANDLED;
  3376.        
  3377.         return PLUGIN_CONTINUE;
  3378. }
  3379.  
  3380. // Buy BP Ammo
  3381. public clcmd_buyammo(id)
  3382. {
  3383.         // Not alive or infinite ammo setting enabled
  3384.         if (!g_isalive[id] || get_pcvar_num(cvar_infammo))
  3385.                 return PLUGIN_HANDLED;
  3386.        
  3387.         // Not human
  3388.         if (g_zombie[id])
  3389.         {
  3390.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_HUMAN_ONLY")
  3391.                 return PLUGIN_HANDLED;
  3392.         }
  3393.        
  3394.         // Not enough ammo packs
  3395.         if (g_ammopacks[id] < 1)
  3396.         {
  3397.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "NOT_ENOUGH_AMMO")
  3398.                 return PLUGIN_HANDLED;
  3399.         }
  3400.        
  3401.         // Get user weapons
  3402.         static weapons[32], num, i, currentammo, weaponid, refilled
  3403.         num = 0 // reset passed weapons count (bugfix)
  3404.         refilled = false
  3405.         get_user_weapons(id, weapons, num)
  3406.        
  3407.         // Loop through them and give the right ammo type
  3408.         for (i = 0; i < num; i++)
  3409.         {
  3410.                 // Prevents re-indexing the array
  3411.                 weaponid = weapons[i]
  3412.                
  3413.                 // Primary and secondary only
  3414.                 if (MAXBPAMMO[weaponid] > 2)
  3415.                 {
  3416.                         // Get current ammo of the weapon
  3417.                         currentammo = cs_get_user_bpammo(id, weaponid)
  3418.                        
  3419.                         // Give additional ammo
  3420.                         ExecuteHamB(Ham_GiveAmmo, id, BUYAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  3421.                        
  3422.                         // Check whether we actually refilled the weapon's ammo
  3423.                         if (cs_get_user_bpammo(id, weaponid) - currentammo > 0) refilled = true
  3424.                 }
  3425.         }
  3426.        
  3427.         // Weapons already have full ammo
  3428.         if (!refilled) return PLUGIN_HANDLED;
  3429.        
  3430.         // Deduce ammo packs, play clip purchase sound, and notify player
  3431.         g_ammopacks[id]--
  3432.         emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  3433.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "AMMO_BOUGHT")
  3434.        
  3435.         return PLUGIN_HANDLED;
  3436. }
  3437.  
  3438. // Block Team Change
  3439. public clcmd_changeteam(id)
  3440. {
  3441.         static team
  3442.         team = fm_cs_get_user_team(id)
  3443.        
  3444.         // Unless it's a spectator joining the game
  3445.         if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  3446.                 return PLUGIN_CONTINUE;
  3447.        
  3448.         // Pressing 'M' (chooseteam) ingame should show the main menu instead
  3449.         show_menu_game(id)
  3450.         return PLUGIN_HANDLED;
  3451. }
  3452.  
  3453. /*================================================================================
  3454.  [Menus]
  3455. =================================================================================*/
  3456.  
  3457. // Game Menu
  3458. show_menu_game(id)
  3459. {
  3460.         static menu[250], len, userflags
  3461.         len = 0
  3462.         userflags = get_user_flags(id)
  3463.        
  3464.         // Title
  3465.         len += formatex(menu[len], charsmax(menu) - len, "\r%s^n^n", g_modname)
  3466.        
  3467.         // 1. Buy weapons
  3468.         if (get_pcvar_num(cvar_buycustom))
  3469.                 len += formatex(menu[len], charsmax(menu) - len, "\r1.\y %L^n", id, "MENU_BUY")
  3470.         else
  3471.                 len += formatex(menu[len], charsmax(menu) - len, "\d1. %L^n", id, "MENU_BUY")
  3472.        
  3473.         // 2. Extra items
  3474.         if (get_pcvar_num(cvar_extraitems) && g_isalive[id])
  3475.                 len += formatex(menu[len], charsmax(menu) - len, "\r2.\w %L^n", id, "MENU_EXTRABUY")
  3476.         else
  3477.                 len += formatex(menu[len], charsmax(menu) - len, "\d2. %L^n", id, "MENU_EXTRABUY")
  3478.        
  3479.         // 3. Zombie class
  3480.         if (get_pcvar_num(cvar_zclasses))
  3481.                 len += formatex(menu[len], charsmax(menu) - len, "\r3.\r %L^n", id,"MENU_ZCLASS")
  3482.         else
  3483.                 len += formatex(menu[len], charsmax(menu) - len, "\d3. %L^n", id,"MENU_ZCLASS")
  3484.        
  3485.         // 4. Unstuck
  3486.         if (g_isalive[id])
  3487.                 len += formatex(menu[len], charsmax(menu) - len, "\r4.\w %L^n", id, "MENU_UNSTUCK")
  3488.         else
  3489.                 len += formatex(menu[len], charsmax(menu) - len, "\d4. %L^n", id, "MENU_UNSTUCK")
  3490.        
  3491.         // 5. Help
  3492.         len += formatex(menu[len], charsmax(menu) - len, "\r5.\y %L^n^n", id, "MENU_INFO")
  3493.        
  3494.         // 6. Join spec
  3495.         if (!g_isalive[id] || !get_pcvar_num(cvar_blocksuicide) || (userflags & g_access_flag[ACCESS_ADMIN_MENU]))
  3496.                 len += formatex(menu[len], charsmax(menu) - len, "\r6.\w %L^n^n", id, "MENU_SPECTATOR")
  3497.         else
  3498.                 len += formatex(menu[len], charsmax(menu) - len, "\d6. %L^n^n", id, "MENU_SPECTATOR")
  3499.                
  3500.         //7. Vip menu
  3501.         if (g_isalive[id])
  3502.                  len += formatex(menu[len], charsmax(menu) - len, "\y7.\r VIP Menu^n^n")
  3503.         else
  3504.                  len += formatex(menu[len], charsmax(menu) - len, "\r7.\d VIP Menu^n^n")        
  3505.        
  3506.         // 9. Admin menu
  3507.         if (userflags & g_access_flag[ACCESS_ADMIN_MENU])
  3508.                 len += formatex(menu[len], charsmax(menu) - len, "\r9.\r %L", id, "MENU_ADMIN")
  3509.         else
  3510.                 len += formatex(menu[len], charsmax(menu) - len, "\d9. %L", id, "MENU_ADMIN")
  3511.        
  3512.         // 0. Exit
  3513.         len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
  3514.        
  3515.         show_menu(id, KEYSMENU, menu, -1, "Game Menu")
  3516. }
  3517.  
  3518. // Buy Menu 1
  3519. public show_menu_buy1(taskid)
  3520. {
  3521.         // Get player's id
  3522.         static id
  3523.         (taskid > g_maxplayers) ? (id = ID_SPAWN) : (id = taskid);
  3524.        
  3525.         // Zombies or survivors get no guns
  3526.         if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  3527.                 return;
  3528.        
  3529.         // Bots pick their weapons randomly / Random weapons setting enabled
  3530.         if (get_pcvar_num(cvar_randweapons) || g_isbot[id])
  3531.         {
  3532.                 buy_primary_weapon(id, random_num(0, ArraySize(g_primary_items) - 1))
  3533.                 menu_buy2(id, random_num(0, ArraySize(g_secondary_items) - 1))
  3534.                 return;
  3535.         }
  3536.        
  3537.         // Automatic selection enabled for player and menu called on spawn event
  3538.         if (WPN_AUTO_ON && taskid > g_maxplayers)
  3539.         {
  3540.                 buy_primary_weapon(id, WPN_AUTO_PRI)
  3541.                 menu_buy2(id, WPN_AUTO_SEC)
  3542.                 return;
  3543.         }
  3544.        
  3545.         static menu[300], len, weap, maxloops
  3546.         len = 0
  3547.         maxloops = min(WPN_STARTID+7, WPN_MAXIDS)
  3548.        
  3549.         // Title
  3550.         len += formatex(menu[len], charsmax(menu) - len, "\y%L \r[%d-%d]^n^n", id, "MENU_BUY1_TITLE", WPN_STARTID+1, min(WPN_STARTID+7, WPN_MAXIDS))
  3551.        
  3552.         // 1-7. Weapon List
  3553.         for (weap = WPN_STARTID; weap < maxloops; weap++)
  3554.                 len += formatex(menu[len], charsmax(menu) - len, "\r%d.\w %s^n", weap-WPN_STARTID+1, WEAPONNAMES[ArrayGetCell(g_primary_weaponids, weap)])
  3555.        
  3556.         // 8. Auto Select
  3557.         len += formatex(menu[len], charsmax(menu) - len, "^n\r8.\w %L \y[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  3558.        
  3559.         // 9. Next/Back - 0. Exit
  3560.         len += formatex(menu[len], charsmax(menu) - len, "^n^n\r9.\w %L/%L^n^n\r0.\w %L", id, "MENU_NEXT", id, "MENU_BACK", id, "MENU_EXIT")
  3561.        
  3562.         show_menu(id, KEYSMENU, menu, -1, "Buy Menu 1")
  3563. }
  3564.  
  3565. // Buy Menu 2
  3566. show_menu_buy2(id)
  3567. {
  3568.         static menu[250], len, weap, maxloops
  3569.         len = 0
  3570.         maxloops = ArraySize(g_secondary_items)
  3571.        
  3572.         // Title
  3573.         len += formatex(menu[len], charsmax(menu) - len, "\y%L^n", id, "MENU_BUY2_TITLE")
  3574.        
  3575.         // 1-6. Weapon List
  3576.         for (weap = 0; weap < maxloops; weap++)
  3577.                 len += formatex(menu[len], charsmax(menu) - len, "^n\r%d.\w %s", weap+1, WEAPONNAMES[ArrayGetCell(g_secondary_weaponids, weap)])
  3578.        
  3579.         // 8. Auto Select
  3580.         len += formatex(menu[len], charsmax(menu) - len, "^n^n\r8.\w %L \y[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  3581.        
  3582.         // 0. Exit
  3583.         len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
  3584.        
  3585.         show_menu(id, KEYSMENU, menu, -1, "Buy Menu 2")
  3586. }
  3587.  
  3588. // Extra Items Menu
  3589. show_menu_extras(id)
  3590. {
  3591.         static menuid, menu[128], item, team, buffer[32]
  3592.        
  3593.         // Title
  3594.         formatex(menu, charsmax(menu), "%L [%L]\r", id, "MENU_EXTRA_TITLE", id, g_zombie[id] ? g_nemesis[id] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE" : g_survivor[id] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3595.         menuid = menu_create(menu, "menu_extras")
  3596.        
  3597.         // Item List
  3598.         for (item = 0; item < g_extraitem_i; item++)
  3599.         {
  3600.                 // Retrieve item's team
  3601.                 team = ArrayGetCell(g_extraitem_team, item)
  3602.                
  3603.                 // Item not available to player's team/class
  3604.                 if ((g_zombie[id] && !g_nemesis[id] && !(team & ZP_TEAM_ZOMBIE)) || (!g_zombie[id] && !g_survivor[id] && !(team & ZP_TEAM_HUMAN)) || (g_nemesis[id] && !(team & ZP_TEAM_NEMESIS)) || (g_survivor[id] && !(team & ZP_TEAM_SURVIVOR)))
  3605.                         continue;
  3606.                
  3607.                 // Check if it's one of the hardcoded items, check availability, set translated caption
  3608.                 switch (item)
  3609.                 {
  3610.                         case EXTRA_NVISION:
  3611.                         {
  3612.                                 if (!get_pcvar_num(cvar_extranvision)) continue;
  3613.                                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA1")
  3614.                         }
  3615.                         case EXTRA_ANTIDOTE:
  3616.                         {
  3617.                                 if (!get_pcvar_num(cvar_extraantidote) || g_antidotecounter >= get_pcvar_num(cvar_antidotelimit)) continue;
  3618.                                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA2")
  3619.                         }
  3620.                         case EXTRA_MADNESS:
  3621.                         {
  3622.                                 if (!get_pcvar_num(cvar_extramadness) || g_madnesscounter >= get_pcvar_num(cvar_madnesslimit)) continue;
  3623.                                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA3")
  3624.                         }
  3625.                         case EXTRA_INFBOMB:
  3626.                         {
  3627.                                 if (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit)) continue;
  3628.                                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA4")
  3629.                         }
  3630.                         default:
  3631.                         {
  3632.                                 if (item >= EXTRA_WEAPONS_STARTID && item <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)) continue;
  3633.                                 ArrayGetString(g_extraitem_name, item, buffer, charsmax(buffer))
  3634.                         }
  3635.                 }
  3636.                
  3637.                 // Add Item Name and Cost
  3638.                 formatex(menu, charsmax(menu), "%s \y%d %L", buffer, ArrayGetCell(g_extraitem_cost, item), id, "AMMO_PACKS2")
  3639.                 buffer[0] = item
  3640.                 buffer[1] = 0
  3641.                 menu_additem(menuid, menu, buffer)
  3642.         }
  3643.        
  3644.         // No items to display?
  3645.         if (menu_items(menuid) <= 0)
  3646.         {
  3647.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id ,"CMD_NOT_EXTRAS")
  3648.                 menu_destroy(menuid)
  3649.                 return;
  3650.         }
  3651.        
  3652.         // Back - Next - Exit
  3653.         formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3654.         menu_setprop(menuid, MPROP_BACKNAME, menu)
  3655.         formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3656.         menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3657.         formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3658.         menu_setprop(menuid, MPROP_EXITNAME, menu)
  3659.        
  3660.         menu_display(id, menuid)
  3661. }
  3662.  
  3663. // Zombie Class Menu
  3664. public show_menu_zclass(id)
  3665. {
  3666.         // Player disconnected
  3667.         if (!g_isconnected[id])
  3668.                 return;
  3669.        
  3670.         // Bots pick their zombie class randomly
  3671.         if (g_isbot[id])
  3672.         {
  3673.                 g_zombieclassnext[id] = random_num(0, g_zclass_i - 1)
  3674.                 return;
  3675.         }
  3676.        
  3677.         static menuid, menu[128], class, buffer[32], buffer2[32]
  3678.        
  3679.         // Title
  3680.         formatex(menu, charsmax(menu), "%L\r", id, "MENU_ZCLASS_TITLE")
  3681.         menuid = menu_create(menu, "menu_zclass")
  3682.        
  3683.         // Class List
  3684.         for (class = 0; class < g_zclass_i; class++)
  3685.         {
  3686.                 // Retrieve name and info
  3687.                 ArrayGetString(g_zclass_name, class, buffer, charsmax(buffer))
  3688.                 ArrayGetString(g_zclass_info, class, buffer2, charsmax(buffer2))
  3689.                
  3690.                 // Add to menu
  3691.                 if (class == g_zombieclassnext[id])
  3692.                         formatex(menu, charsmax(menu), "\d%s %s", buffer, buffer2)
  3693.                 else
  3694.                         formatex(menu, charsmax(menu), "%s \y%s", buffer, buffer2)
  3695.                
  3696.                 buffer[0] = class
  3697.                 buffer[1] = 0
  3698.                 menu_additem(menuid, menu, buffer)
  3699.         }
  3700.        
  3701.         // Back - Next - Exit
  3702.         formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3703.         menu_setprop(menuid, MPROP_BACKNAME, menu)
  3704.         formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3705.         menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3706.         formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3707.         menu_setprop(menuid, MPROP_EXITNAME, menu)
  3708.        
  3709.         menu_display(id, menuid)
  3710. }
  3711.  
  3712. // Help Menu
  3713. show_menu_info(id)
  3714. {
  3715.         static menu[150]
  3716.        
  3717.         formatex(menu, charsmax(menu), "\y%L^n^n\r1.\w %L^n\r2.\w %L^n\r3.\w %L^n\r4.\w %L^n^n\r0.\w %L", id, "MENU_INFO_TITLE", id, "MENU_INFO1", id,"MENU_INFO2", id,"MENU_INFO3", id,"MENU_INFO4", id, "MENU_EXIT")
  3718.         show_menu(id, KEYSMENU, menu, -1, "Mod Info")
  3719. }
  3720.  
  3721. // Admin Menu
  3722. show_menu_admin(id)
  3723. {
  3724.         static menu[250], len, userflags
  3725.         len = 0
  3726.         userflags = get_user_flags(id)
  3727.        
  3728.         // Title
  3729.         len += formatex(menu[len], charsmax(menu) - len, "\y%L^n^n", id, "MENU_ADMIN_TITLE")
  3730.        
  3731.         // 1. Zombiefy/Humanize command
  3732.         if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
  3733.                 len += formatex(menu[len], charsmax(menu) - len, "\r1.\w %L^n", id, "MENU_ADMIN1")
  3734.         else
  3735.                 len += formatex(menu[len], charsmax(menu) - len, "\d1. %L^n", id, "MENU_ADMIN1")
  3736.        
  3737.         // 2. Nemesis command
  3738.         if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
  3739.                 len += formatex(menu[len], charsmax(menu) - len, "\r2.\w %L^n", id, "MENU_ADMIN2")
  3740.         else
  3741.                 len += formatex(menu[len], charsmax(menu) - len, "\d2. %L^n", id, "MENU_ADMIN2")
  3742.        
  3743.         // 3. Survivor command
  3744.         if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
  3745.                 len += formatex(menu[len], charsmax(menu) - len, "\r3.\w %L^n", id, "MENU_ADMIN3")
  3746.         else
  3747.                 len += formatex(menu[len], charsmax(menu) - len, "\d3. %L^n", id, "MENU_ADMIN3")
  3748.        
  3749.         // 4. Respawn command
  3750.         if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  3751.                 len += formatex(menu[len], charsmax(menu) - len, "\r4.\w %L^n", id, "MENU_ADMIN4")
  3752.         else
  3753.                 len += formatex(menu[len], charsmax(menu) - len, "\d4. %L^n", id, "MENU_ADMIN4")
  3754.        
  3755.         // 5. Swarm mode command
  3756.         if ((userflags & g_access_flag[ACCESS_MODE_SWARM]) && allowed_swarm())
  3757.                 len += formatex(menu[len], charsmax(menu) - len, "\r5.\w %L^n", id, "MENU_ADMIN5")
  3758.         else
  3759.                 len += formatex(menu[len], charsmax(menu) - len, "\d5. %L^n", id, "MENU_ADMIN5")
  3760.        
  3761.         // 6. Multi infection command
  3762.         if ((userflags & g_access_flag[ACCESS_MODE_MULTI]) && allowed_multi())
  3763.                 len += formatex(menu[len], charsmax(menu) - len, "\r6.\w %L^n", id, "MENU_ADMIN6")
  3764.         else
  3765.                 len += formatex(menu[len], charsmax(menu) - len, "\d6. %L^n", id, "MENU_ADMIN6")
  3766.        
  3767.         // 7. Plague mode command
  3768.         if ((userflags & g_access_flag[ACCESS_MODE_PLAGUE]) && allowed_plague())
  3769.                 len += formatex(menu[len], charsmax(menu) - len, "\r7.\w %L^n", id, "MENU_ADMIN7")
  3770.         else
  3771.                 len += formatex(menu[len], charsmax(menu) - len, "\d7. %L^n", id, "MENU_ADMIN7")
  3772.        
  3773.         // 0. Exit
  3774.         len += formatex(menu[len], charsmax(menu) - len, "^n\r0.\w %L", id, "MENU_EXIT")
  3775.        
  3776.         show_menu(id, KEYSMENU, menu, -1, "Admin Menu")
  3777. }
  3778.  
  3779. // Player List Menu
  3780. show_menu_player_list(id)
  3781. {
  3782.         static menuid, menu[128], player, userflags, buffer[2]
  3783.         userflags = get_user_flags(id)
  3784.        
  3785.         // Title
  3786.         switch (PL_ACTION)
  3787.         {
  3788.                 case ACTION_ZOMBIEFY_HUMANIZE: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN1")
  3789.                 case ACTION_MAKE_NEMESIS: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN2")
  3790.                 case ACTION_MAKE_SURVIVOR: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN3")
  3791.                 case ACTION_RESPAWN_PLAYER: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN4")
  3792.         }
  3793.         menuid = menu_create(menu, "menu_player_list")
  3794.        
  3795.         // Player List
  3796.         for (player = 0; player <= g_maxplayers; player++)
  3797.         {
  3798.                 // Skip if not connected
  3799.                 if (!g_isconnected[player])
  3800.                         continue;
  3801.                
  3802.                 // Format text depending on the action to take
  3803.                 switch (PL_ACTION)
  3804.                 {
  3805.                         case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  3806.                         {
  3807.                                 if (g_zombie[player])
  3808.                                 {
  3809.                                         if (allowed_human(player) && (userflags & g_access_flag[ACCESS_MAKE_HUMAN]))
  3810.                                                 formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3811.                                         else
  3812.                                                 formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3813.                                 }
  3814.                                 else
  3815.                                 {
  3816.                                         if (allowed_zombie(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE])))
  3817.                                                 formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3818.                                         else
  3819.                                                 formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3820.                                 }
  3821.                         }
  3822.                         case ACTION_MAKE_NEMESIS: // Nemesis command
  3823.                         {
  3824.                                 if (allowed_nemesis(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS])))
  3825.                                 {
  3826.                                         if (g_zombie[player])
  3827.                                                 formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3828.                                         else
  3829.                                                 formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3830.                                 }
  3831.                                 else
  3832.                                         formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_zombie[player] ? g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE" : g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3833.                         }
  3834.                         case ACTION_MAKE_SURVIVOR: // Survivor command
  3835.                         {
  3836.                                 if (allowed_survivor(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR])))
  3837.                                 {
  3838.                                         if (g_zombie[player])
  3839.                                                 formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3840.                                         else
  3841.                                                 formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3842.                                 }
  3843.                                 else
  3844.                                         formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_zombie[player] ? g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE" : g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3845.                         }
  3846.                         case ACTION_RESPAWN_PLAYER: // Respawn command
  3847.                         {
  3848.                                 if (allowed_respawn(player) && (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS]))
  3849.                                         formatex(menu, charsmax(menu), "%s", g_playername[player])
  3850.                                 else
  3851.                                         formatex(menu, charsmax(menu), "\d%s", g_playername[player])
  3852.                         }
  3853.                 }
  3854.                
  3855.                 // Add player
  3856.                 buffer[0] = player
  3857.                 buffer[1] = 0
  3858.                 menu_additem(menuid, menu, buffer)
  3859.         }
  3860.        
  3861.         // Back - Next - Exit
  3862.         formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3863.         menu_setprop(menuid, MPROP_BACKNAME, menu)
  3864.         formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3865.         menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3866.         formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3867.         menu_setprop(menuid, MPROP_EXITNAME, menu)
  3868.        
  3869.         menu_display(id, menuid)
  3870. }
  3871.  
  3872. /*================================================================================
  3873.  [Menu Handlers]
  3874. =================================================================================*/
  3875.  
  3876. // Game Menu
  3877. public menu_game(id, key)
  3878. {
  3879.         switch (key)
  3880.         {
  3881.                 case 0: // Buy Weapons
  3882.                 {
  3883.                         // Custom buy menus enabled?
  3884.                         if (get_pcvar_num(cvar_buycustom))
  3885.                         {
  3886.                                 // Disable the remember selection setting
  3887.                                 WPN_AUTO_ON = 0
  3888.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "BUY_ENABLED")
  3889.                                
  3890.                                 // Show menu if player hasn't yet bought anything
  3891.                                 if (g_canbuy[id]) show_menu_buy1(id)
  3892.                         }
  3893.                         else
  3894.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  3895.                 }
  3896.                 case 1: // Extra Items
  3897.                 {
  3898.                         // Extra items enabled?
  3899.                         if (get_pcvar_num(cvar_extraitems))
  3900.                         {
  3901.                                 // Check whether the player is able to buy anything
  3902.                                 if (g_isalive[id])
  3903.                                         show_menu_extras(id)
  3904.                                 else
  3905.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  3906.                         }
  3907.                         else
  3908.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_EXTRAS")
  3909.                 }
  3910.                 case 2: // Zombie Classes
  3911.                 {
  3912.                         // Zombie classes enabled?
  3913.                         if (get_pcvar_num(cvar_zclasses))
  3914.                                 show_menu_zclass(id)
  3915.                         else
  3916.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ZCLASSES")
  3917.                 }
  3918.                 case 3: // Unstuck
  3919.                 {
  3920.                         // Check if player is stuck
  3921.                         if (g_isalive[id])
  3922.                         {
  3923.                                 if (is_player_stuck(id))
  3924.                                 {
  3925.                                         // Move to an initial spawn
  3926.                                         if (get_pcvar_num(cvar_randspawn))
  3927.                                                 do_random_spawn(id) // random spawn (including CSDM)
  3928.                                         else
  3929.                                                 do_random_spawn(id, 1) // regular spawn
  3930.                                 }
  3931.                                 else
  3932.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_STUCK")
  3933.                         }
  3934.                         else
  3935.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  3936.                 }
  3937.                 case 4: // Help Menu
  3938.                 {
  3939.                         show_menu_info(id)
  3940.                 }
  3941.                 case 5: // Join Spectator
  3942.                 {
  3943.                         // Player alive?
  3944.                         if (g_isalive[id])
  3945.                         {
  3946.                                 // Prevent abuse by non-admins if block suicide setting is enabled
  3947.                                 if (get_pcvar_num(cvar_blocksuicide) && !(get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU]))
  3948.                                 {
  3949.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  3950.                                         return PLUGIN_HANDLED;
  3951.                                 }
  3952.                                
  3953.                                 // Check that we still have both humans and zombies to keep the round going
  3954.                                 check_round(id)
  3955.                                
  3956.                                 // Kill him before he switches team
  3957.                                 dllfunc(DLLFunc_ClientKill, id)
  3958.                         }
  3959.                        
  3960.                         // Temporarily save player stats?
  3961.                         if (get_pcvar_num(cvar_statssave)) save_stats(id)
  3962.                        
  3963.                         // Remove previous tasks
  3964.                         remove_task(id+TASK_TEAM)
  3965.                         remove_task(id+TASK_MODEL)
  3966.                         remove_task(id+TASK_FLASH)
  3967.                         remove_task(id+TASK_CHARGE)
  3968.                         remove_task(id+TASK_SPAWN)
  3969.                         remove_task(id+TASK_BLOOD)
  3970.                         remove_task(id+TASK_AURA)
  3971.                         remove_task(id+TASK_BURN)
  3972.                        
  3973.                         // Then move him to the spectator team
  3974.                         fm_cs_set_user_team(id, FM_CS_TEAM_SPECTATOR)
  3975.                         fm_user_team_update(id)
  3976.                
  3977.                     }
  3978.                   case 6: {
  3979.                 if (g_isalive[id])
  3980.                 client_cmd(id, "say /vm"); // VIP menu
  3981.                 else
  3982.                         zp_colored_print(id, "^x03[VIP Menu]^x01 %L", id, "CMD_NOT")
  3983.                 }
  3984.                 case 8: // Admin Menu
  3985.                 {
  3986.                         // Check if player has the required access
  3987.                         if (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU])
  3988.                                 show_menu_admin(id)
  3989.                         else
  3990.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  3991.                 }
  3992.         }
  3993.        
  3994.         return PLUGIN_HANDLED;
  3995. }
  3996.  
  3997. // Buy Menu 1
  3998. public menu_buy1(id, key)
  3999. {
  4000.         // Zombies or survivors get no guns
  4001.         if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  4002.                 return PLUGIN_HANDLED;
  4003.        
  4004.         // Special keys / weapon list exceeded
  4005.         if (key >= MENU_KEY_AUTOSELECT || WPN_SELECTION >= WPN_MAXIDS)
  4006.         {
  4007.                 switch (key)
  4008.                 {
  4009.                         case MENU_KEY_AUTOSELECT: // toggle auto select
  4010.                         {
  4011.                                 WPN_AUTO_ON = 1 - WPN_AUTO_ON
  4012.                         }
  4013.                         case MENU_KEY_NEXT: // next/back
  4014.                         {
  4015.                                 if (WPN_STARTID+7 < WPN_MAXIDS)
  4016.                                         WPN_STARTID += 7
  4017.                                 else
  4018.                                         WPN_STARTID = 0
  4019.                         }
  4020.                         case MENU_KEY_EXIT: // exit
  4021.                         {
  4022.                                 return PLUGIN_HANDLED;
  4023.                         }
  4024.                 }
  4025.                
  4026.                 // Show buy menu again
  4027.                 show_menu_buy1(id)
  4028.                 return PLUGIN_HANDLED;
  4029.         }
  4030.        
  4031.         // Store selected weapon id
  4032.         WPN_AUTO_PRI = WPN_SELECTION
  4033.        
  4034.         // Buy primary weapon
  4035.         buy_primary_weapon(id, WPN_AUTO_PRI)
  4036.        
  4037.         // Show pistols menu
  4038.         show_menu_buy2(id)
  4039.        
  4040.         return PLUGIN_HANDLED;
  4041. }
  4042.  
  4043. // Buy Primary Weapon
  4044. buy_primary_weapon(id, selection)
  4045. {
  4046.         // Drop previous weapons
  4047.         drop_weapons(id, 1)
  4048.         drop_weapons(id, 2)
  4049.        
  4050.         // Strip off from weapons
  4051.         fm_strip_user_weapons(id)
  4052.         fm_give_item(id, "weapon_knife")
  4053.        
  4054.         // Get weapon's id and name
  4055.         static weaponid, wname[32]
  4056.         weaponid = ArrayGetCell(g_primary_weaponids, selection)
  4057.         ArrayGetString(g_primary_items, selection, wname, charsmax(wname))
  4058.        
  4059.         // Give the new weapon and full ammo
  4060.         fm_give_item(id, wname)
  4061.         ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4062.        
  4063.         // Weapons bought
  4064.         g_canbuy[id] = false
  4065.        
  4066.         // Give additional items
  4067.         static i
  4068.         for (i = 0; i < ArraySize(g_additional_items); i++)
  4069.         {
  4070.                 ArrayGetString(g_additional_items, i, wname, charsmax(wname))
  4071.                 fm_give_item(id, wname)
  4072.         }
  4073. }
  4074.  
  4075. // Buy Menu 2
  4076. public menu_buy2(id, key)
  4077. {      
  4078.         // Zombies or survivors get no guns
  4079.         if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  4080.                 return PLUGIN_HANDLED;
  4081.        
  4082.         // Special keys / weapon list exceeded
  4083.         if (key >= ArraySize(g_secondary_items))
  4084.         {
  4085.                 // Toggle autoselect
  4086.                 if (key == MENU_KEY_AUTOSELECT)
  4087.                         WPN_AUTO_ON = 1 - WPN_AUTO_ON
  4088.                
  4089.                 // Reshow menu unless user exited
  4090.                 if (key != MENU_KEY_EXIT)
  4091.                         show_menu_buy2(id)
  4092.                
  4093.                 return PLUGIN_HANDLED;
  4094.         }
  4095.        
  4096.         // Store selected weapon
  4097.         WPN_AUTO_SEC = key
  4098.        
  4099.         // Drop secondary gun again, in case we picked another (bugfix)
  4100.         drop_weapons(id, 2)
  4101.        
  4102.         // Get weapon's id
  4103.         static weaponid, wname[32]
  4104.         weaponid = ArrayGetCell(g_secondary_weaponids, key)
  4105.         ArrayGetString(g_secondary_items, key, wname, charsmax(wname))
  4106.        
  4107.         // Give the new weapon and full ammo
  4108.         fm_give_item(id, wname)
  4109.         ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4110.        
  4111.         return PLUGIN_HANDLED;
  4112. }
  4113.  
  4114. // Extra Items Menu
  4115. public menu_extras(id, menuid, item)
  4116. {
  4117.         // Menu was closed
  4118.         if (item == MENU_EXIT)
  4119.         {
  4120.                 menu_destroy(menuid)
  4121.                 return PLUGIN_HANDLED;
  4122.         }
  4123.        
  4124.         // Dead players are not allowed to buy items
  4125.         if (!g_isalive[id])
  4126.         {
  4127.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4128.                 menu_destroy(menuid)
  4129.                 return PLUGIN_HANDLED;
  4130.         }
  4131.        
  4132.         // Retrieve extra item id
  4133.         static buffer[2], dummy, itemid
  4134.         menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4135.         itemid = buffer[0]
  4136.        
  4137.         // Attempt to buy the item
  4138.         buy_extra_item(id, itemid)
  4139.         menu_destroy(menuid)
  4140.         return PLUGIN_HANDLED;
  4141. }
  4142.  
  4143. // Buy Extra Item
  4144. buy_extra_item(id, itemid, ignorecost = 0)
  4145. {
  4146.         // Retrieve item's team
  4147.         static team
  4148.         team = ArrayGetCell(g_extraitem_team, itemid)
  4149.        
  4150.         // Check for team/class specific items
  4151.         if ((g_zombie[id] && !g_nemesis[id] && !(team & ZP_TEAM_ZOMBIE)) || (!g_zombie[id] && !g_survivor[id] && !(team & ZP_TEAM_HUMAN)) || (g_nemesis[id] && !(team & ZP_TEAM_NEMESIS)) || (g_survivor[id] && !(team & ZP_TEAM_SURVIVOR)))
  4152.         {
  4153.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4154.                 return;
  4155.         }
  4156.        
  4157.         // Check for unavailable items
  4158.         if ((itemid == EXTRA_NVISION && !get_pcvar_num(cvar_extranvision))
  4159.         || (itemid == EXTRA_ANTIDOTE && (!get_pcvar_num(cvar_extraantidote) || g_antidotecounter >= get_pcvar_num(cvar_antidotelimit)))
  4160.         || (itemid == EXTRA_MADNESS && (!get_pcvar_num(cvar_extramadness) || g_madnesscounter >= get_pcvar_num(cvar_madnesslimit)))
  4161.         || (itemid == EXTRA_INFBOMB && (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit)))
  4162.         || (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)))
  4163.         {
  4164.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4165.                 return;
  4166.         }
  4167.        
  4168.         // Check for hard coded items with special conditions
  4169.         if ((itemid == EXTRA_ANTIDOTE && (g_endround || g_swarmround || g_nemround || g_survround || g_plagueround || fnGetZombies() <= 1 || (get_pcvar_num(cvar_deathmatch) && !get_pcvar_num(cvar_respawnafterlast) && fnGetHumans() == 1)))
  4170.         || (itemid == EXTRA_MADNESS && g_nodamage[id]) || (itemid == EXTRA_INFBOMB && (g_endround || g_swarmround || g_nemround || g_survround || g_plagueround)))
  4171.         {
  4172.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_CANTUSE")
  4173.                 return;
  4174.         }
  4175.        
  4176.         // Ignore item's cost?
  4177.         if (!ignorecost)
  4178.         {
  4179.                 // Check that we have enough ammo packs
  4180.                 if (g_ammopacks[id] < ArrayGetCell(g_extraitem_cost, itemid))
  4181.                 {
  4182.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "NOT_ENOUGH_AMMO")
  4183.                         return;
  4184.                 }
  4185.                
  4186.                 // Deduce item cost
  4187.                 g_ammopacks[id] -= ArrayGetCell(g_extraitem_cost, itemid)
  4188.         }
  4189.        
  4190.         // Check which kind of item we're buying
  4191.         switch (itemid)
  4192.         {
  4193.                 case EXTRA_NVISION: // Night Vision
  4194.                 {
  4195.                         g_nvision[id] = true
  4196.                        
  4197.                         if (!g_isbot[id])
  4198.                         {
  4199.                                 g_nvisionenabled[id] = true
  4200.                                
  4201.                                 // Custom nvg?
  4202.                                 if (get_pcvar_num(cvar_customnvg))
  4203.                                 {
  4204.                                         remove_task(id+TASK_NVISION)
  4205.                                         set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  4206.                                 }
  4207.                                 else
  4208.                                         set_user_gnvision(id, 1)
  4209.                         }
  4210.                         else
  4211.                                 cs_set_user_nvg(id, 1)
  4212.                 }
  4213.                 case EXTRA_ANTIDOTE: // Antidote
  4214.                 {
  4215.                         // Increase antidote purchase count for this round
  4216.                         g_antidotecounter++
  4217.                        
  4218.                         humanme(id, 0, 0)
  4219.                 }
  4220.                 case EXTRA_MADNESS: // Zombie Madness
  4221.                 {
  4222.                         // Increase madness purchase count for this round
  4223.                         g_madnesscounter++
  4224.                        
  4225.                         g_nodamage[id] = true
  4226.                         set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
  4227.                         set_task(get_pcvar_float(cvar_madnessduration), "madness_over", id+TASK_BLOOD)
  4228.                        
  4229.                         static sound[64]
  4230.                         ArrayGetString(zombie_madness, random_num(0, ArraySize(zombie_madness) - 1), sound, charsmax(sound))
  4231.                         emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4232.                 }
  4233.                 case EXTRA_INFBOMB: // Infection Bomb
  4234.                 {
  4235.                         // Increase infection bomb purchase count for this round
  4236.                         g_infbombcounter++
  4237.                        
  4238.                         // Already own one
  4239.                         if (user_has_weapon(id, CSW_HEGRENADE))
  4240.                         {
  4241.                                 // Increase BP ammo on it instead
  4242.                                 cs_set_user_bpammo(id, CSW_HEGRENADE, cs_get_user_bpammo(id, CSW_HEGRENADE) + 1)
  4243.                                
  4244.                                 // Flash ammo in hud
  4245.                                 message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
  4246.                                 write_byte(AMMOID[CSW_HEGRENADE]) // ammo id
  4247.                                 write_byte(1) // ammo amount
  4248.                                 message_end()
  4249.                                
  4250.                                 // Play clip purchase sound
  4251.                                 emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4252.                                
  4253.                                 return; // stop here
  4254.                         }
  4255.                        
  4256.                         // Give weapon to the player
  4257.                         fm_give_item(id, "weapon_hegrenade")
  4258.                 }
  4259.                 default:
  4260.                 {
  4261.                         if (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1) // Weapons
  4262.                         {
  4263.                                 // Get weapon's id and name
  4264.                                 static weaponid, wname[32]
  4265.                                 ArrayGetString(g_extraweapon_items, itemid - EXTRA_WEAPONS_STARTID, wname, charsmax(wname))
  4266.                                 weaponid = cs_weapon_name_to_id(wname)
  4267.                                
  4268.                                 // If we are giving a primary/secondary weapon
  4269.                                 if (MAXBPAMMO[weaponid] > 2)
  4270.                                 {
  4271.                                         // Make user drop the previous one
  4272.                                         if ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)
  4273.                                                 drop_weapons(id, 1)
  4274.                                         else
  4275.                                                 drop_weapons(id, 2)
  4276.                                        
  4277.                                         // Give full BP ammo for the new one
  4278.                                         ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4279.                                 }
  4280.                                 // If we are giving a grenade which the user already owns
  4281.                                 else if (user_has_weapon(id, weaponid))
  4282.                                 {
  4283.                                         // Increase BP ammo on it instead
  4284.                                         cs_set_user_bpammo(id, weaponid, cs_get_user_bpammo(id, weaponid) + 1)
  4285.                                        
  4286.                                         // Flash ammo in hud
  4287.                                         message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
  4288.                                         write_byte(AMMOID[weaponid]) // ammo id
  4289.                                         write_byte(1) // ammo amount
  4290.                                         message_end()
  4291.                                        
  4292.                                         // Play clip purchase sound
  4293.                                         emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4294.                                        
  4295.                                         return; // stop here
  4296.                                 }
  4297.                                
  4298.                                 // Give weapon to the player
  4299.                                 fm_give_item(id, wname)
  4300.                         }
  4301.                         else // Custom additions
  4302.                         {
  4303.                                 // Item selected forward
  4304.                                 ExecuteForward(g_fwExtraItemSelected, g_fwDummyResult, id, itemid);
  4305.                                
  4306.                                 // Item purchase blocked, restore buyer's ammo packs
  4307.                                 if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && !ignorecost)
  4308.                                         g_ammopacks[id] += ArrayGetCell(g_extraitem_cost, itemid)
  4309.                         }
  4310.                 }
  4311.         }
  4312. }
  4313.  
  4314. // Zombie Class Menu
  4315. public menu_zclass(id, menuid, item)
  4316. {
  4317.         // Menu was closed
  4318.         if (item == MENU_EXIT)
  4319.         {
  4320.                 menu_destroy(menuid)
  4321.                 return PLUGIN_HANDLED;
  4322.         }
  4323.        
  4324.         // Retrieve zombie class id
  4325.         static buffer[2], dummy, classid
  4326.         menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4327.         classid = buffer[0]
  4328.        
  4329.         // Store selection for the next infection
  4330.         g_zombieclassnext[id] = classid
  4331.        
  4332.         static name[32]
  4333.         ArrayGetString(g_zclass_name, g_zombieclassnext[id], name, charsmax(name))
  4334.        
  4335.         // Show selected zombie class info and stats
  4336.         zp_colored_print(id, "^x04[ZP]^x01 %L: %s", id, "ZOMBIE_SELECT", name)
  4337.         zp_colored_print(id, "^x04[ZP]^x01 %L: %d %L: %d %L: %d %L: %d%%", id, "ZOMBIE_ATTRIB1", ArrayGetCell(g_zclass_hp, g_zombieclassnext[id]), id, "ZOMBIE_ATTRIB2", ArrayGetCell(g_zclass_spd, g_zombieclassnext[id]),
  4338.         id, "ZOMBIE_ATTRIB3", floatround(Float:ArrayGetCell(g_zclass_grav, g_zombieclassnext[id]) * 800.0), id, "ZOMBIE_ATTRIB4", floatround(Float:ArrayGetCell(g_zclass_kb, g_zombieclassnext[id]) * 100.0))
  4339.        
  4340.         menu_destroy(menuid)
  4341.         return PLUGIN_HANDLED;
  4342. }
  4343.  
  4344. // Info Menu
  4345. public menu_info(id, key)
  4346. {
  4347.         static motd[1500], len
  4348.         len = 0
  4349.        
  4350.         switch (key)
  4351.         {
  4352.                 case 0: // General
  4353.                 {
  4354.                         static weather, lighting[2]
  4355.                         weather = 0
  4356.                         get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
  4357.                         strtolower(lighting)
  4358.                        
  4359.                         len += formatex(motd[len], charsmax(motd) - len, "%L ", id, "MOTD_INFO11", "Zombie Plague", PLUGIN_VERSION, "MeRcyLeZZ")
  4360.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO12")
  4361.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_A")
  4362.                        
  4363.                         if (g_ambience_fog)
  4364.                         {
  4365.                                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_FOG")
  4366.                                 weather++
  4367.                         }
  4368.                         if (g_ambience_rain)
  4369.                         {
  4370.                                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_RAIN")
  4371.                                 weather++
  4372.                         }
  4373.                         if (g_ambience_snow)
  4374.                         {
  4375.                                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_SNOW")
  4376.                                 weather++
  4377.                         }
  4378.                         if (weather < 1) len += formatex(motd[len], charsmax(motd) - len, " %L", id, "MOTD_DISABLED")
  4379.                        
  4380.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_B", lighting)
  4381.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_C", id, get_pcvar_num(cvar_triggered) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4382.                         if (lighting[0] >= 'a' && lighting[0] <= 'd' && get_pcvar_float(cvar_thunder) > 0.0) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_D", floatround(get_pcvar_float(cvar_thunder)))
  4383.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_E", id, get_pcvar_num(cvar_removedoors) > 0 ? get_pcvar_num(cvar_removedoors) > 1 ? "MOTD_DOORS" : "MOTD_ROTATING" : "MOTD_ENABLED")
  4384.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_F", id, get_pcvar_num(cvar_deathmatch) > 0 ? get_pcvar_num(cvar_deathmatch) > 1 ? get_pcvar_num(cvar_deathmatch) > 2 ? "MOTD_ENABLED" : "MOTD_DM_ZOMBIE" : "MOTD_DM_HUMAN" : "MOTD_DISABLED")
  4385.                         if (get_pcvar_num(cvar_deathmatch)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_G", floatround(get_pcvar_float(cvar_spawnprotection)))
  4386.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_H", id, get_pcvar_num(cvar_randspawn) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4387.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_I", id, get_pcvar_num(cvar_extraitems) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4388.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_J", id, get_pcvar_num(cvar_zclasses) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4389.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_K", id, get_pcvar_num(cvar_customnvg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4390.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_L", id, g_cached_customflash ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4391.                        
  4392.                         show_motd(id, motd)
  4393.                 }
  4394.                 case 1: // Humans
  4395.                 {
  4396.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2")
  4397.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_A", get_pcvar_num(cvar_humanhp))
  4398.                         if (get_pcvar_num(cvar_humanlasthp) > 0) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_B", get_pcvar_num(cvar_humanlasthp))
  4399.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_C", floatround(g_cached_humanspd))
  4400.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_D", floatround(get_pcvar_float(cvar_humangravity) * 800.0))
  4401.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_E", id, get_pcvar_num(cvar_infammo) > 0 ? get_pcvar_num(cvar_infammo) > 1 ? "MOTD_AMMO_CLIP" : "MOTD_AMMO_BP" : "MOTD_LIMITED")
  4402.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_F", get_pcvar_num(cvar_ammodamage))
  4403.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_G", id, get_pcvar_num(cvar_firegrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4404.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_H", id, get_pcvar_num(cvar_frostgrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4405.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_I", id, get_pcvar_num(cvar_flaregrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4406.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_J", id, get_pcvar_num(cvar_knockback) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4407.                        
  4408.                         show_motd(id, motd)
  4409.                 }
  4410.                 case 2: // Zombies
  4411.                 {
  4412.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3")
  4413.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_A", ArrayGetCell(g_zclass_hp, 0))
  4414.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_B", floatround(float(ArrayGetCell(g_zclass_hp, 0)) * get_pcvar_float(cvar_zombiefirsthp)))
  4415.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_C", floatround(get_pcvar_float(cvar_zombiearmor) * 100.0))
  4416.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_D", ArrayGetCell(g_zclass_spd, 0))
  4417.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_E", floatround(Float:ArrayGetCell(g_zclass_grav, 0) * 800.0))
  4418.                         if (get_pcvar_num(cvar_zombiebonushp)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_F", get_pcvar_num(cvar_zombiebonushp))
  4419.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_G", id, get_pcvar_num(cvar_zombiepainfree) > 0 ? get_pcvar_num(cvar_zombiepainfree) > 1 ? "MOTD_LASTZOMBIE" : "MOTD_ENABLED" : "MOTD_DISABLED")
  4420.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_H", id, get_pcvar_num(cvar_zombiebleeding) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4421.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_I", get_pcvar_num(cvar_ammoinfect))
  4422.                        
  4423.                         show_motd(id, motd)
  4424.                 }
  4425.                 case 3: // Gameplay Modes
  4426.                 {
  4427.                         static nemhp[5], survhp[5]
  4428.                        
  4429.                         // Get nemesis and survivor health
  4430.                         num_to_str(get_pcvar_num(cvar_nemhp), nemhp, charsmax(nemhp))
  4431.                         num_to_str(get_pcvar_num(cvar_survhp), survhp, charsmax(survhp))
  4432.                        
  4433.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4")
  4434.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_A", id, get_pcvar_num(cvar_nem) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4435.                         if (get_pcvar_num(cvar_nem))
  4436.                         {
  4437.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_B", get_pcvar_num(cvar_nemchance))
  4438.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_C", get_pcvar_num(cvar_nemhp) > 0 ? nemhp : "[Auto]")
  4439.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_D", floatround(g_cached_nemspd))
  4440.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_E", floatround(get_pcvar_float(cvar_nemgravity) * 800.0))
  4441.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_F", id, g_cached_leapnemesis ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4442.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_G", id, get_pcvar_num(cvar_nempainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4443.                         }
  4444.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_H", id, get_pcvar_num(cvar_surv) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4445.                         if (get_pcvar_num(cvar_surv))
  4446.                         {
  4447.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_I", get_pcvar_num(cvar_survchance))
  4448.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_J", get_pcvar_num(cvar_survhp) > 0 ? survhp : "[Auto]")
  4449.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_K", floatround(g_cached_survspd))
  4450.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_L", floatround(get_pcvar_float(cvar_survgravity) * 800.0))
  4451.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_M", id, g_cached_leapsurvivor ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4452.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_N", id, get_pcvar_num(cvar_survpainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4453.                         }
  4454.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_O", id, get_pcvar_num(cvar_swarm) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4455.                         if (get_pcvar_num(cvar_swarm)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_P", get_pcvar_num(cvar_swarmchance))
  4456.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_Q", id, get_pcvar_num(cvar_multi) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4457.                         if (get_pcvar_num(cvar_multi))
  4458.                         {
  4459.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_R", get_pcvar_num(cvar_multichance))
  4460.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_S", floatround(get_pcvar_float(cvar_multiratio) * 100.0))
  4461.                         }
  4462.                         len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_T", id, get_pcvar_num(cvar_plague) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4463.                         if (get_pcvar_num(cvar_plague))
  4464.                         {
  4465.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_U", get_pcvar_num(cvar_plaguechance))
  4466.                                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_V", floatround(get_pcvar_float(cvar_plagueratio) * 100.0))
  4467.                         }
  4468.                        
  4469.                         show_motd(id, motd)
  4470.                 }
  4471.                 default: return PLUGIN_HANDLED;
  4472.         }
  4473.        
  4474.         // Show help menu again if user wishes to read another topic
  4475.         show_menu_info(id)
  4476.        
  4477.         return PLUGIN_HANDLED;
  4478. }
  4479.  
  4480. // Admin Menu
  4481. public menu_admin(id, key)
  4482. {
  4483.         static userflags
  4484.         userflags = get_user_flags(id)
  4485.        
  4486.         switch (key)
  4487.         {
  4488.                 case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  4489.                 {
  4490.                         if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
  4491.                         {
  4492.                                 // Show player list for admin to pick a target
  4493.                                 PL_ACTION = ACTION_ZOMBIEFY_HUMANIZE
  4494.                                 show_menu_player_list(id)
  4495.                         }
  4496.                         else
  4497.                         {
  4498.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4499.                                 show_menu_admin(id)
  4500.                         }
  4501.                 }
  4502.                 case ACTION_MAKE_NEMESIS: // Nemesis command
  4503.                 {
  4504.                         if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
  4505.                         {
  4506.                                 // Show player list for admin to pick a target
  4507.                                 PL_ACTION = ACTION_MAKE_NEMESIS
  4508.                                 show_menu_player_list(id)
  4509.                         }
  4510.                         else
  4511.                         {
  4512.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4513.                                 show_menu_admin(id)
  4514.                         }
  4515.                 }
  4516.                 case ACTION_MAKE_SURVIVOR: // Survivor command
  4517.                 {
  4518.                         if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
  4519.                         {
  4520.                                 // Show player list for admin to pick a target
  4521.                                 PL_ACTION = ACTION_MAKE_SURVIVOR
  4522.                                 show_menu_player_list(id)
  4523.                         }
  4524.                         else
  4525.                         {
  4526.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4527.                                 show_menu_admin(id)
  4528.                         }
  4529.                 }
  4530.                 case ACTION_RESPAWN_PLAYER: // Respawn command
  4531.                 {
  4532.                         if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  4533.                         {
  4534.                                 // Show player list for admin to pick a target
  4535.                                 PL_ACTION = ACTION_RESPAWN_PLAYER
  4536.                                 show_menu_player_list(id)
  4537.                         }
  4538.                         else
  4539.                         {
  4540.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4541.                                 show_menu_admin(id)
  4542.                         }
  4543.                 }
  4544.                 case ACTION_MODE_SWARM: // Swarm Mode command
  4545.                 {
  4546.                         if (userflags & g_access_flag[ACCESS_MODE_SWARM])
  4547.                         {
  4548.                                 if (allowed_swarm())
  4549.                                         command_swarm(id)
  4550.                                 else
  4551.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4552.                         }
  4553.                         else
  4554.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4555.                        
  4556.                         show_menu_admin(id)
  4557.                 }
  4558.                 case ACTION_MODE_MULTI: // Multiple Infection command
  4559.                 {
  4560.                         if (userflags & g_access_flag[ACCESS_MODE_MULTI])
  4561.                         {
  4562.                                 if (allowed_multi())
  4563.                                         command_multi(id)
  4564.                                 else
  4565.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4566.                         }
  4567.                         else
  4568.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4569.                        
  4570.                         show_menu_admin(id)
  4571.                 }
  4572.                 case ACTION_MODE_PLAGUE: // Plague Mode command
  4573.                 {
  4574.                         if (userflags & g_access_flag[ACCESS_MODE_PLAGUE])
  4575.                         {
  4576.                                 if (allowed_plague())
  4577.                                         command_plague(id)
  4578.                                 else
  4579.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4580.                         }
  4581.                         else
  4582.                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4583.                        
  4584.                         show_menu_admin(id)
  4585.                 }
  4586.         }
  4587.        
  4588.         return PLUGIN_HANDLED;
  4589. }
  4590.  
  4591. // Player List Menu
  4592. public menu_player_list(id, menuid, item)
  4593. {
  4594.         // Menu was closed
  4595.         if (item == MENU_EXIT)
  4596.         {
  4597.                 menu_destroy(menuid)
  4598.                 show_menu_admin(id)
  4599.                 return PLUGIN_HANDLED;
  4600.         }
  4601.        
  4602.         // Retrieve player id
  4603.         static buffer[2], dummy, playerid
  4604.         menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4605.         playerid = buffer[0]
  4606.        
  4607.         // Perform action on player
  4608.        
  4609.         // Get admin flags
  4610.         static userflags
  4611.         userflags = get_user_flags(id)
  4612.        
  4613.         // Make sure it's still connected
  4614.         if (g_isconnected[playerid])
  4615.         {
  4616.                 // Perform the right action if allowed
  4617.                 switch (PL_ACTION)
  4618.                 {
  4619.                         case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  4620.                         {
  4621.                                 if (g_zombie[playerid])
  4622.                                 {
  4623.                                         if (userflags & g_access_flag[ACCESS_MAKE_HUMAN])
  4624.                                         {
  4625.                                                 if (allowed_human(playerid))
  4626.                                                         command_human(id, playerid)
  4627.                                                 else
  4628.                                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4629.                                         }
  4630.                                         else
  4631.                                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4632.                                 }
  4633.                                 else
  4634.                                 {
  4635.                                         if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE]))
  4636.                                         {
  4637.                                                 if (allowed_zombie(playerid))
  4638.                                                         command_zombie(id, playerid)
  4639.                                                 else
  4640.                                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4641.                                         }
  4642.                                         else
  4643.                                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4644.                                 }
  4645.                         }
  4646.                         case ACTION_MAKE_NEMESIS: // Nemesis command
  4647.                         {
  4648.                                 if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS]))
  4649.                                 {
  4650.                                         if (allowed_nemesis(playerid))
  4651.                                                 command_nemesis(id, playerid)
  4652.                                         else
  4653.                                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4654.                                 }
  4655.                                 else
  4656.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4657.                         }
  4658.                         case ACTION_MAKE_SURVIVOR: // Survivor command
  4659.                         {
  4660.                                 if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR]))
  4661.                                 {
  4662.                                         if (allowed_survivor(playerid))
  4663.                                                 command_survivor(id, playerid)
  4664.                                         else
  4665.                                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4666.                                 }
  4667.                                 else
  4668.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4669.                         }
  4670.                         case ACTION_RESPAWN_PLAYER: // Respawn command
  4671.                         {
  4672.                                 if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  4673.                                 {
  4674.                                         if (allowed_respawn(playerid))
  4675.                                                 command_respawn(id, playerid)
  4676.                                         else
  4677.                                                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4678.                                 }
  4679.                                 else
  4680.                                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4681.                         }
  4682.                 }
  4683.         }
  4684.         else
  4685.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4686.        
  4687.         menu_destroy(menuid)
  4688.         show_menu_player_list(id)
  4689.         return PLUGIN_HANDLED;
  4690. }
  4691.  
  4692. /*================================================================================
  4693.  [Admin Commands]
  4694. =================================================================================*/
  4695.  
  4696. // zp_toggle [1/0]
  4697. public cmd_toggle(id, level, cid)
  4698. {
  4699.         // Check for access flag - Enable/Disable Mod
  4700.         if (!cmd_access(id, g_access_flag[ACCESS_ENABLE_MOD], cid, 2))
  4701.                 return PLUGIN_HANDLED;
  4702.        
  4703.         // Retrieve arguments
  4704.         new arg[2]
  4705.         read_argv(1, arg, charsmax(arg))
  4706.        
  4707.         // Mod already enabled/disabled
  4708.         if (str_to_num(arg) == g_pluginenabled)
  4709.                 return PLUGIN_HANDLED;
  4710.        
  4711.         // Set toggle cvar
  4712.         set_pcvar_num(cvar_toggle, str_to_num(arg))
  4713.         client_print(id, print_console, "Zombie Plague %L.", id, str_to_num(arg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4714.        
  4715.         // Retrieve map name
  4716.         new mapname[32]
  4717.         get_mapname(mapname, charsmax(mapname))
  4718.        
  4719.         // Restart current map
  4720.         server_cmd("changelevel %s", mapname)
  4721.        
  4722.         return PLUGIN_HANDLED;
  4723. }
  4724.  
  4725. // zp_zombie [target]
  4726. public cmd_zombie(id, level, cid)
  4727. {
  4728.         // Check for access flag depending on the resulting action
  4729.         if (g_newround)
  4730.         {
  4731.                 // Start Mode Infection
  4732.                 if (!cmd_access(id, g_access_flag[ACCESS_MODE_INFECTION], cid, 2))
  4733.                         return PLUGIN_HANDLED;
  4734.         }
  4735.         else
  4736.         {
  4737.                 // Make Zombie
  4738.                 if (!cmd_access(id, g_access_flag[ACCESS_MAKE_ZOMBIE], cid, 2))
  4739.                         return PLUGIN_HANDLED;
  4740.         }
  4741.        
  4742.         // Retrieve arguments
  4743.         static arg[32], player
  4744.         read_argv(1, arg, charsmax(arg))
  4745.         player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4746.        
  4747.         // Invalid target
  4748.         if (!player) return PLUGIN_HANDLED;
  4749.        
  4750.         // Target not allowed to be zombie
  4751.         if (!allowed_zombie(player))
  4752.         {
  4753.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4754.                 return PLUGIN_HANDLED
  4755.         }
  4756.        
  4757.         command_zombie(id, player)
  4758.        
  4759.         return PLUGIN_HANDLED;
  4760. }
  4761.  
  4762. // zp_human [target]
  4763. public cmd_human(id, level, cid)
  4764. {
  4765.         // Check for access flag - Make Human
  4766.         if (!cmd_access(id, g_access_flag[ACCESS_MAKE_HUMAN], cid, 2))
  4767.                 return PLUGIN_HANDLED;
  4768.        
  4769.         // Retrieve arguments
  4770.         static arg[32], player
  4771.         read_argv(1, arg, charsmax(arg))
  4772.         player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4773.        
  4774.         // Invalid target
  4775.         if (!player) return PLUGIN_HANDLED;
  4776.        
  4777.         // Target not allowed to be human
  4778.         if (!allowed_human(player))
  4779.         {
  4780.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4781.                 return PLUGIN_HANDLED;
  4782.         }
  4783.        
  4784.         command_human(id, player)
  4785.        
  4786.         return PLUGIN_HANDLED;
  4787. }
  4788.  
  4789. // zp_survivor [target]
  4790. public cmd_survivor(id, level, cid)
  4791. {
  4792.         // Check for access flag depending on the resulting action
  4793.         if (g_newround)
  4794.         {
  4795.                 // Start Mode Survivor
  4796.                 if (!cmd_access(id, g_access_flag[ACCESS_MODE_SURVIVOR], cid, 2))
  4797.                         return PLUGIN_HANDLED;
  4798.         }
  4799.         else
  4800.         {
  4801.                 // Make Survivor
  4802.                 if (!cmd_access(id, g_access_flag[ACCESS_MAKE_SURVIVOR], cid, 2))
  4803.                         return PLUGIN_HANDLED;
  4804.         }
  4805.        
  4806.         // Retrieve arguments
  4807.         static arg[32], player
  4808.         read_argv(1, arg, charsmax(arg))
  4809.         player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4810.        
  4811.         // Invalid target
  4812.         if (!player) return PLUGIN_HANDLED;
  4813.        
  4814.         // Target not allowed to be survivor
  4815.         if (!allowed_survivor(player))
  4816.         {
  4817.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4818.                 return PLUGIN_HANDLED;
  4819.         }
  4820.        
  4821.         command_survivor(id, player)
  4822.        
  4823.         return PLUGIN_HANDLED;
  4824. }
  4825.  
  4826. // zp_nemesis [target]
  4827. public cmd_nemesis(id, level, cid)
  4828. {
  4829.         // Check for access flag depending on the resulting action
  4830.         if (g_newround)
  4831.         {
  4832.                 // Start Mode Nemesis
  4833.                 if (!cmd_access(id, g_access_flag[ACCESS_MODE_NEMESIS], cid, 2))
  4834.                         return PLUGIN_HANDLED;
  4835.         }
  4836.         else
  4837.         {
  4838.                 // Make Nemesis
  4839.                 if (!cmd_access(id, g_access_flag[ACCESS_MAKE_NEMESIS], cid, 2))
  4840.                         return PLUGIN_HANDLED;
  4841.         }
  4842.        
  4843.         // Retrieve arguments
  4844.         static arg[32], player
  4845.         read_argv(1, arg, charsmax(arg))
  4846.         player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4847.        
  4848.         // Invalid target
  4849.         if (!player) return PLUGIN_HANDLED;
  4850.        
  4851.         // Target not allowed to be nemesis
  4852.         if (!allowed_nemesis(player))
  4853.         {
  4854.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4855.                 return PLUGIN_HANDLED;
  4856.         }
  4857.        
  4858.         command_nemesis(id, player)
  4859.        
  4860.         return PLUGIN_HANDLED;
  4861. }
  4862.  
  4863. // zp_respawn [target]
  4864. public cmd_respawn(id, level, cid)
  4865. {
  4866.         // Check for access flag - Respawn
  4867.         if (!cmd_access(id, g_access_flag[ACCESS_RESPAWN_PLAYERS], cid, 2))
  4868.                 return PLUGIN_HANDLED;
  4869.        
  4870.         // Retrieve arguments
  4871.         static arg[32], player
  4872.         read_argv(1, arg, charsmax(arg))
  4873.         player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
  4874.        
  4875.         // Invalid target
  4876.         if (!player) return PLUGIN_HANDLED;
  4877.        
  4878.         // Target not allowed to be respawned
  4879.         if (!allowed_respawn(player))
  4880.         {
  4881.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4882.                 return PLUGIN_HANDLED;
  4883.         }
  4884.        
  4885.         command_respawn(id, player)
  4886.        
  4887.         return PLUGIN_HANDLED;
  4888. }
  4889.  
  4890. // zp_swarm
  4891. public cmd_swarm(id, level, cid)
  4892. {
  4893.         // Check for access flag - Mode Swarm
  4894.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_SWARM], cid, 2))
  4895.                 return PLUGIN_HANDLED;
  4896.        
  4897.         // Swarm mode not allowed
  4898.         if (!allowed_swarm())
  4899.         {
  4900.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4901.                 return PLUGIN_HANDLED;
  4902.         }
  4903.        
  4904.         command_swarm(id)
  4905.        
  4906.         return PLUGIN_HANDLED;
  4907. }
  4908.  
  4909. // zp_multi
  4910. public cmd_multi(id, level, cid)
  4911. {
  4912.         // Check for access flag - Mode Multi
  4913.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_MULTI], cid, 2))
  4914.                 return PLUGIN_HANDLED;
  4915.        
  4916.         // Multi infection mode not allowed
  4917.         if (!allowed_multi())
  4918.         {
  4919.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4920.                 return PLUGIN_HANDLED;
  4921.         }
  4922.        
  4923.         command_multi(id)
  4924.        
  4925.         return PLUGIN_HANDLED;
  4926. }
  4927.  
  4928. // zp_plague
  4929. public cmd_plague(id, level, cid)
  4930. {
  4931.         // Check for access flag - Mode Plague
  4932.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_PLAGUE], cid, 2))
  4933.                 return PLUGIN_HANDLED;
  4934.        
  4935.         // Plague mode not allowed
  4936.         if (!allowed_plague())
  4937.         {
  4938.                 client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4939.                 return PLUGIN_HANDLED;
  4940.         }
  4941.        
  4942.         command_plague(id)
  4943.        
  4944.         return PLUGIN_HANDLED;
  4945. }
  4946.  
  4947. /*================================================================================
  4948.  [Message Hooks]
  4949. =================================================================================*/
  4950.  
  4951. // Current Weapon info
  4952. public message_cur_weapon(msg_id, msg_dest, msg_entity)
  4953. {
  4954.         // Not alive or zombie
  4955.         if (!g_isalive[msg_entity] || g_zombie[msg_entity])
  4956.                 return;
  4957.        
  4958.         // Not an active weapon
  4959.         if (get_msg_arg_int(1) != 1)
  4960.                 return;
  4961.        
  4962.         // Unlimited clip disabled for class
  4963.         if (g_survivor[msg_entity] ? get_pcvar_num(cvar_survinfammo) <= 1 : get_pcvar_num(cvar_infammo) <= 1)
  4964.                 return;
  4965.        
  4966.         // Get weapon's id
  4967.         static weapon
  4968.         weapon = get_msg_arg_int(2)
  4969.        
  4970.         // Unlimited Clip Ammo for this weapon?
  4971.         if (MAXBPAMMO[weapon] > 2)
  4972.         {
  4973.                 // Max out clip ammo
  4974.                 cs_set_weapon_ammo(fm_cs_get_current_weapon_ent(msg_entity), MAXCLIP[weapon])
  4975.                
  4976.                 // HUD should show full clip all the time
  4977.                 set_msg_arg_int(3, get_msg_argtype(3), MAXCLIP[weapon])
  4978.         }
  4979. }
  4980.  
  4981. // Take off player's money
  4982. public message_money(msg_id, msg_dest, msg_entity)
  4983. {
  4984.         // Remove money setting enabled?
  4985.         if (!get_pcvar_num(cvar_removemoney))
  4986.                 return PLUGIN_CONTINUE;
  4987.        
  4988.         fm_cs_set_user_money(msg_entity, 0)
  4989.         return PLUGIN_HANDLED;
  4990. }
  4991.  
  4992. // Fix for the HL engine bug when HP is multiples of 256
  4993. public message_health(msg_id, msg_dest, msg_entity)
  4994. {
  4995.         // Get player's health
  4996.         static health
  4997.         health = get_msg_arg_int(1)
  4998.        
  4999.         // Don't bother
  5000.         if (health < 256) return;
  5001.        
  5002.         // Check if we need to fix it
  5003.         if (health % 256 == 0)
  5004.                 fm_set_user_health(msg_entity, pev(msg_entity, pev_health) + 1)
  5005.        
  5006.         // HUD can only show as much as 255 hp
  5007.         set_msg_arg_int(1, get_msg_argtype(1), 255)
  5008. }
  5009.  
  5010. // Block flashlight battery messages if custom flashlight is enabled instead
  5011. public message_flashbat()
  5012. {
  5013.         if (g_cached_customflash)
  5014.                 return PLUGIN_HANDLED;
  5015.        
  5016.         return PLUGIN_CONTINUE;
  5017. }
  5018.  
  5019. // Flashbangs should only affect zombies
  5020. public message_screenfade(msg_id, msg_dest, msg_entity)
  5021. {
  5022.         if (get_msg_arg_int(4) != 255 || get_msg_arg_int(5) != 255 || get_msg_arg_int(6) != 255 || get_msg_arg_int(7) < 200)
  5023.                 return PLUGIN_CONTINUE;
  5024.        
  5025.         // Nemesis shouldn't be FBed
  5026.         if (g_zombie[msg_entity] && !g_nemesis[msg_entity])
  5027.         {
  5028.                 // Set flash color to nighvision's
  5029.                 set_msg_arg_int(4, get_msg_argtype(4), get_pcvar_num(cvar_nvgcolor[0]))
  5030.                 set_msg_arg_int(5, get_msg_argtype(5), get_pcvar_num(cvar_nvgcolor[1]))
  5031.                 set_msg_arg_int(6, get_msg_argtype(6), get_pcvar_num(cvar_nvgcolor[2]))
  5032.                 return PLUGIN_CONTINUE;
  5033.         }
  5034.        
  5035.         return PLUGIN_HANDLED;
  5036. }
  5037.  
  5038. // Prevent spectators' nightvision from being turned off when switching targets, etc.
  5039. public message_nvgtoggle()
  5040. {
  5041.         return PLUGIN_HANDLED;
  5042. }
  5043.  
  5044. // Set correct model on player corpses
  5045. public message_clcorpse()
  5046. {
  5047.         set_msg_arg_string(1, g_playermodel[get_msg_arg_int(12)])
  5048. }
  5049.  
  5050. // Prevent zombies from seeing any weapon pickup icon
  5051. public message_weappickup(msg_id, msg_dest, msg_entity)
  5052. {
  5053.         if (g_zombie[msg_entity])
  5054.                 return PLUGIN_HANDLED;
  5055.        
  5056.         return PLUGIN_CONTINUE;
  5057. }
  5058.  
  5059. // Prevent zombies from seeing any ammo pickup icon
  5060. public message_ammopickup(msg_id, msg_dest, msg_entity)
  5061. {
  5062.         if (g_zombie[msg_entity])
  5063.                 return PLUGIN_HANDLED;
  5064.        
  5065.         return PLUGIN_CONTINUE;
  5066. }
  5067.  
  5068. // Block hostage HUD display
  5069. public message_scenario()
  5070. {
  5071.         if (get_msg_args() > 1)
  5072.         {
  5073.                 static sprite[8]
  5074.                 get_msg_arg_string(2, sprite, charsmax(sprite))
  5075.                
  5076.                 if (equal(sprite, "hostage"))
  5077.                         return PLUGIN_HANDLED;
  5078.         }
  5079.        
  5080.         return PLUGIN_CONTINUE;
  5081. }
  5082.  
  5083. // Block hostages from appearing on radar
  5084. public message_hostagepos()
  5085. {
  5086.         return PLUGIN_HANDLED;
  5087. }
  5088.  
  5089. // Block some text messages
  5090. public message_textmsg()
  5091. {
  5092.         static textmsg[22]
  5093.         get_msg_arg_string(2, textmsg, charsmax(textmsg))
  5094.        
  5095.         // Game restarting, reset scores and call round end to balance the teams
  5096.         if (equal(textmsg, "#Game_will_restart_in"))
  5097.         {
  5098.                 g_scorehumans = 0
  5099.                 g_scorezombies = 0
  5100.                 logevent_round_end()
  5101.         }
  5102.         // Block round end related messages
  5103.         else if (equal(textmsg, "#Hostages_Not_Rescued") || equal(textmsg, "#Round_Draw") || equal(textmsg, "#Terrorists_Win") || equal(textmsg, "#CTs_Win"))
  5104.         {
  5105.                 return PLUGIN_HANDLED;
  5106.         }
  5107.        
  5108.         return PLUGIN_CONTINUE;
  5109. }
  5110.  
  5111. // Block CS round win audio messages, since we're playing our own instead
  5112. public message_sendaudio()
  5113. {
  5114.         static audio[17]
  5115.         get_msg_arg_string(2, audio, charsmax(audio))
  5116.        
  5117.         if(equal(audio[7], "terwin") || equal(audio[7], "ctwin") || equal(audio[7], "rounddraw"))
  5118.                 return PLUGIN_HANDLED;
  5119.        
  5120.         return PLUGIN_CONTINUE;
  5121. }
  5122.  
  5123. // Send actual team scores (T = zombies // CT = humans)
  5124. public message_teamscore()
  5125. {
  5126.         static team[2]
  5127.         get_msg_arg_string(1, team, charsmax(team))
  5128.        
  5129.         switch (team[0])
  5130.         {
  5131.                 // CT
  5132.                 case 'C': set_msg_arg_int(2, get_msg_argtype(2), g_scorehumans)
  5133.                 // Terrorist
  5134.                 case 'T': set_msg_arg_int(2, get_msg_argtype(2), g_scorezombies)
  5135.         }
  5136. }
  5137.  
  5138. // Team Switch (or player joining a team for first time)
  5139. public message_teaminfo(msg_id, msg_dest)
  5140. {
  5141.         // Only hook global messages
  5142.         if (msg_dest != MSG_ALL && msg_dest != MSG_BROADCAST) return;
  5143.        
  5144.         // Don't pick up our own TeamInfo messages for this player (bugfix)
  5145.         if (g_switchingteam) return;
  5146.        
  5147.         // Get player's id
  5148.         static id
  5149.         id = get_msg_arg_int(1)
  5150.        
  5151.         // Enable spectators' nightvision if not spawning right away
  5152.         set_task(0.2, "spec_nvision", id)
  5153.        
  5154.         // Round didn't start yet, nothing to worry about
  5155.         if (g_newround) return;
  5156.        
  5157.         // Get his new team
  5158.         static team[2]
  5159.         get_msg_arg_string(2, team, charsmax(team))
  5160.        
  5161.         // Perform some checks to see if they should join a different team instead
  5162.         switch (team[0])
  5163.         {
  5164.                 case 'C': // CT
  5165.                 {
  5166.                         if (g_survround && fnGetHumans()) // survivor alive --> switch to T and spawn as zombie
  5167.                         {
  5168.                                 g_respawn_as_zombie[id] = true;
  5169.                                 remove_task(id+TASK_TEAM)
  5170.                                 fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5171.                                 set_msg_arg_string(2, "TERRORIST")
  5172.                         }
  5173.                         else if (!fnGetZombies()) // no zombies alive --> switch to T and spawn as zombie
  5174.                         {
  5175.                                 g_respawn_as_zombie[id] = true;
  5176.                                 remove_task(id+TASK_TEAM)
  5177.                                 fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5178.                                 set_msg_arg_string(2, "TERRORIST")
  5179.                         }
  5180.                 }
  5181.                 case 'T': // Terrorist
  5182.                 {
  5183.                         if ((g_swarmround || g_survround) && fnGetHumans()) // survivor alive or swarm round w/ humans --> spawn as zombie
  5184.                         {
  5185.                                 g_respawn_as_zombie[id] = true;
  5186.                         }
  5187.                         else if (fnGetZombies()) // zombies alive --> switch to CT
  5188.                         {
  5189.                                 remove_task(id+TASK_TEAM)
  5190.                                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5191.                                 set_msg_arg_string(2, "CT")
  5192.                         }
  5193.                 }
  5194.         }
  5195. }
  5196.  
  5197. /*================================================================================
  5198.  [Main Functions]
  5199. =================================================================================*/
  5200.  
  5201. // Make Zombie Task
  5202. public make_zombie_task()
  5203. {
  5204.         // Call make a zombie with no specific mode
  5205.         make_a_zombie(MODE_NONE, 0)
  5206. }
  5207.  
  5208. // Make a Zombie Function
  5209. make_a_zombie(mode, id)
  5210. {
  5211.         // Get alive players count
  5212.         static iPlayersnum
  5213.         iPlayersnum = fnGetAlive()
  5214.        
  5215.         // Not enough players, come back later!
  5216.         if (iPlayersnum < 1)
  5217.         {
  5218.                 set_task(2.0, "make_zombie_task", TASK_MAKEZOMBIE)
  5219.                 return;
  5220.         }
  5221.        
  5222.         // Round started!
  5223.         g_newround = false
  5224.        
  5225.         // Set up some common vars
  5226.         static forward_id, sound[64], iZombies, iMaxZombies
  5227.        
  5228.         if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_SURVIVOR) && random_num(1, get_pcvar_num(cvar_survchance)) == get_pcvar_num(cvar_surv) && iPlayersnum >= get_pcvar_num(cvar_survminplayers)) || mode == MODE_SURVIVOR)
  5229.         {
  5230.                 // Survivor Mode
  5231.                 g_survround = true
  5232.                 g_lastmode = MODE_SURVIVOR
  5233.                
  5234.                 // Choose player randomly?
  5235.                 if (mode == MODE_NONE)
  5236.                         id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5237.                
  5238.                 // Remember id for calling our forward later
  5239.                 forward_id = id
  5240.                
  5241.                 // Turn player into a survivor
  5242.                 humanme(id, 1, 0)
  5243.                
  5244.                 // Turn the remaining players into zombies
  5245.                 for (id = 1; id <= g_maxplayers; id++)
  5246.                 {
  5247.                         // Not alive
  5248.                         if (!g_isalive[id])
  5249.                                 continue;
  5250.                        
  5251.                         // Survivor or already a zombie
  5252.                         if (g_survivor[id] || g_zombie[id])
  5253.                                 continue;
  5254.                        
  5255.                         // Turn into a zombie
  5256.                         zombieme(id, 0, 0, 1, 0)
  5257.                 }
  5258.                
  5259.                 // Play survivor sound
  5260.                 ArrayGetString(sound_survivor, random_num(0, ArraySize(sound_survivor) - 1), sound, charsmax(sound))
  5261.                 PlaySound(sound);
  5262.                
  5263.                 // Show Survivor HUD notice
  5264.                 set_hudmessage(20, 20, 255, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5265.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SURVIVOR", g_playername[forward_id])
  5266.                
  5267.                 // Mode fully started!
  5268.                 g_modestarted = true
  5269.                
  5270.                 // Round start forward
  5271.                 ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SURVIVOR, forward_id);
  5272.         }
  5273.         else if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_SWARM) && random_num(1, get_pcvar_num(cvar_swarmchance)) == get_pcvar_num(cvar_swarm) && iPlayersnum >= get_pcvar_num(cvar_swarmminplayers)) || mode == MODE_SWARM)
  5274.         {              
  5275.                 // Swarm Mode
  5276.                 g_swarmround = true
  5277.                 g_lastmode = MODE_SWARM
  5278.                
  5279.                 // Make sure there are alive players on both teams (BUGFIX)
  5280.                 if (!fnGetAliveTs())
  5281.                 {
  5282.                         // Move random player to T team
  5283.                         id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5284.                         remove_task(id+TASK_TEAM)
  5285.                         fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5286.                         fm_user_team_update(id)
  5287.                 }
  5288.                 else if (!fnGetAliveCTs())
  5289.                 {
  5290.                         // Move random player to CT team
  5291.                         id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5292.                         remove_task(id+TASK_TEAM)
  5293.                         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5294.                         fm_user_team_update(id)
  5295.                 }
  5296.                
  5297.                 // Turn every T into a zombie
  5298.                 for (id = 1; id <= g_maxplayers; id++)
  5299.                 {
  5300.                         // Not alive
  5301.                         if (!g_isalive[id])
  5302.                                 continue;
  5303.                        
  5304.                         // Not a Terrorist
  5305.                         if (fm_cs_get_user_team(id) != FM_CS_TEAM_T)
  5306.                                 continue;
  5307.                        
  5308.                         // Turn into a zombie
  5309.                         zombieme(id, 0, 0, 1, 0)
  5310.                 }
  5311.                
  5312.                 // Play swarm sound
  5313.                 ArrayGetString(sound_swarm, random_num(0, ArraySize(sound_swarm) - 1), sound, charsmax(sound))
  5314.                 PlaySound(sound);
  5315.                
  5316.                 // Show Swarm HUD notice
  5317.                 set_hudmessage(20, 255, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5318.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SWARM")
  5319.                
  5320.                 // Mode fully started!
  5321.                 g_modestarted = true
  5322.                
  5323.                 // Round start forward
  5324.                 ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SWARM, 0);
  5325.         }
  5326.         else if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_MULTI) && random_num(1, get_pcvar_num(cvar_multichance)) == get_pcvar_num(cvar_multi) && floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil) >= 2 && floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil) < iPlayersnum && iPlayersnum >= get_pcvar_num(cvar_multiminplayers)) || mode == MODE_MULTI)
  5327.         {
  5328.                 // Multi Infection Mode
  5329.                 g_lastmode = MODE_MULTI
  5330.                
  5331.                 // iMaxZombies is rounded up, in case there aren't enough players
  5332.                 iMaxZombies = floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil)
  5333.                 iZombies = 0
  5334.                
  5335.                 // Randomly turn iMaxZombies players into zombies
  5336.                 while (iZombies < iMaxZombies)
  5337.                 {
  5338.                         // Keep looping through all players
  5339.                         if (++id > g_maxplayers) id = 1
  5340.                        
  5341.                         // Dead or already a zombie
  5342.                         if (!g_isalive[id] || g_zombie[id])
  5343.                                 continue;
  5344.                        
  5345.                         // Random chance
  5346.                         if (random_num(0, 1))
  5347.                         {
  5348.                                 // Turn into a zombie
  5349.                                 zombieme(id, 0, 0, 1, 0)
  5350.                                 iZombies++
  5351.                         }
  5352.                 }
  5353.                
  5354.                 // Turn the remaining players into humans
  5355.                 for (id = 1; id <= g_maxplayers; id++)
  5356.                 {
  5357.                         // Only those of them who aren't zombies
  5358.                         if (!g_isalive[id] || g_zombie[id])
  5359.                                 continue;
  5360.                        
  5361.                         // Switch to CT
  5362.                         if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5363.                         {
  5364.                                 remove_task(id+TASK_TEAM)
  5365.                                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5366.                                 fm_user_team_update(id)
  5367.                         }
  5368.                 }
  5369.                
  5370.                 // Play multi infection sound
  5371.                 ArrayGetString(sound_multi, random_num(0, ArraySize(sound_multi) - 1), sound, charsmax(sound))
  5372.                 PlaySound(sound);
  5373.                
  5374.                 // Show Multi Infection HUD notice
  5375.                 set_hudmessage(200, 50, 0, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5376.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_MULTI")
  5377.                
  5378.                 // Mode fully started!
  5379.                 g_modestarted = true
  5380.                
  5381.                 // Round start forward
  5382.                 ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_MULTI, 0);
  5383.         }
  5384.         else if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_PLAGUE) && random_num(1, get_pcvar_num(cvar_plaguechance)) == get_pcvar_num(cvar_plague) && floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil) >= 1
  5385.         && iPlayersnum-(get_pcvar_num(cvar_plaguesurvnum)+get_pcvar_num(cvar_plaguenemnum)+floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)) >= 1 && iPlayersnum >= get_pcvar_num(cvar_plagueminplayers)) || mode == MODE_PLAGUE)
  5386.         {
  5387.                 // Plague Mode
  5388.                 g_plagueround = true
  5389.                 g_lastmode = MODE_PLAGUE
  5390.                
  5391.                 // Turn specified amount of players into Survivors
  5392.                 static iSurvivors, iMaxSurvivors
  5393.                 iMaxSurvivors = get_pcvar_num(cvar_plaguesurvnum)
  5394.                 iSurvivors = 0
  5395.                
  5396.                 while (iSurvivors < iMaxSurvivors)
  5397.                 {
  5398.                         // Choose random guy
  5399.                         id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5400.                        
  5401.                         // Already a survivor?
  5402.                         if (g_survivor[id])
  5403.                                 continue;
  5404.                        
  5405.                         // If not, turn him into one
  5406.                         humanme(id, 1, 0)
  5407.                         iSurvivors++
  5408.                        
  5409.                         // Apply survivor health multiplier
  5410.                         fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguesurvhpmulti)))
  5411.                 }
  5412.                
  5413.                 // Turn specified amount of players into Nemesis
  5414.                 static iNemesis, iMaxNemesis
  5415.                 iMaxNemesis = get_pcvar_num(cvar_plaguenemnum)
  5416.                 iNemesis = 0
  5417.                
  5418.                 while (iNemesis < iMaxNemesis)
  5419.                 {
  5420.                         // Choose random guy
  5421.                         id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5422.                        
  5423.                         // Already a survivor or nemesis?
  5424.                         if (g_survivor[id] || g_nemesis[id])
  5425.                                 continue;
  5426.                        
  5427.                         // If not, turn him into one
  5428.                         zombieme(id, 0, 1, 0, 0)
  5429.                         iNemesis++
  5430.                        
  5431.                         // Apply nemesis health multiplier
  5432.                         fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguenemhpmulti)))
  5433.                 }
  5434.                
  5435.                 // iMaxZombies is rounded up, in case there aren't enough players
  5436.                 iMaxZombies = floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)
  5437.                 iZombies = 0
  5438.                
  5439.                 // Randomly turn iMaxZombies players into zombies
  5440.                 while (iZombies < iMaxZombies)
  5441.                 {
  5442.                         // Keep looping through all players
  5443.                         if (++id > g_maxplayers) id = 1
  5444.                        
  5445.                         // Dead or already a zombie or survivor
  5446.                         if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  5447.                                 continue;
  5448.                        
  5449.                         // Random chance
  5450.                         if (random_num(0, 1))
  5451.                         {
  5452.                                 // Turn into a zombie
  5453.                                 zombieme(id, 0, 0, 1, 0)
  5454.                                 iZombies++
  5455.                         }
  5456.                 }
  5457.                
  5458.                 // Turn the remaining players into humans
  5459.                 for (id = 1; id <= g_maxplayers; id++)
  5460.                 {
  5461.                         // Only those of them who arent zombies or survivor
  5462.                         if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  5463.                                 continue;
  5464.                        
  5465.                         // Switch to CT
  5466.                         if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5467.                         {
  5468.                                 remove_task(id+TASK_TEAM)
  5469.                                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5470.                                 fm_user_team_update(id)
  5471.                         }
  5472.                 }
  5473.                
  5474.                 // Play plague sound
  5475.                 ArrayGetString(sound_plague, random_num(0, ArraySize(sound_plague) - 1), sound, charsmax(sound))
  5476.                 PlaySound(sound);
  5477.                
  5478.                 // Show Plague HUD notice
  5479.                 set_hudmessage(0, 50, 200, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5480.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_PLAGUE")
  5481.                
  5482.                 // Mode fully started!
  5483.                 g_modestarted = true
  5484.                
  5485.                 // Round start forward
  5486.                 ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_PLAGUE, 0);
  5487.         }
  5488.         else
  5489.         {
  5490.                 // Single Infection Mode or Nemesis Mode
  5491.                
  5492.                 // Choose player randomly?
  5493.                 if (mode == MODE_NONE)
  5494.                         id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5495.                
  5496.                 // Remember id for calling our forward later
  5497.                 forward_id = id
  5498.                
  5499.                 if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_NEMESIS) && random_num(1, get_pcvar_num(cvar_nemchance)) == get_pcvar_num(cvar_nem) && iPlayersnum >= get_pcvar_num(cvar_nemminplayers)) || mode == MODE_NEMESIS)
  5500.                 {
  5501.                         // Nemesis Mode
  5502.                         g_nemround = true
  5503.                         g_lastmode = MODE_NEMESIS
  5504.                        
  5505.                         // Turn player into nemesis
  5506.                         zombieme(id, 0, 1, 0, 0)
  5507.                 }
  5508.                 else
  5509.                 {
  5510.                         // Single Infection Mode
  5511.                         g_lastmode = MODE_INFECTION
  5512.                        
  5513.                         // Turn player into the first zombie
  5514.                         zombieme(id, 0, 0, 0, 0)
  5515.                 }
  5516.                
  5517.                 // Remaining players should be humans (CTs)
  5518.                 for (id = 1; id <= g_maxplayers; id++)
  5519.                 {
  5520.                         // Not alive
  5521.                         if (!g_isalive[id])
  5522.                                 continue;
  5523.                        
  5524.                         // First zombie/nemesis
  5525.                         if (g_zombie[id])
  5526.                                 continue;
  5527.                        
  5528.                         // Switch to CT
  5529.                         if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5530.                         {
  5531.                                 remove_task(id+TASK_TEAM)
  5532.                                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5533.                                 fm_user_team_update(id)
  5534.                         }
  5535.                 }
  5536.                
  5537.                 if (g_nemround)
  5538.                 {
  5539.                         // Play Nemesis sound
  5540.                         ArrayGetString(sound_nemesis, random_num(0, ArraySize(sound_nemesis) - 1), sound, charsmax(sound))
  5541.                         PlaySound(sound);
  5542.                        
  5543.                         // Show Nemesis HUD notice
  5544.                         set_hudmessage(255, 20, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5545.                         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_NEMESIS", g_playername[forward_id])
  5546.                        
  5547.                         // Mode fully started!
  5548.                         g_modestarted = true
  5549.                        
  5550.                         // Round start forward
  5551.                         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_NEMESIS, forward_id);
  5552.                 }
  5553.                 else
  5554.                 {
  5555.                         // Show First Zombie HUD notice
  5556.                         set_hudmessage(255, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  5557.                         ShowSyncHudMsg(0, g_MsgSync, "%L",LANG_PLAYER, "NOTICE_FIRST", g_playername[forward_id])
  5558.                        
  5559.                         // Mode fully started!
  5560.                         g_modestarted = true
  5561.                        
  5562.                         // Round start forward
  5563.                         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_INFECTION, forward_id);
  5564.                 }
  5565.         }
  5566.        
  5567.         // Start ambience sounds after a mode begins
  5568.         if ((g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && g_nemround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && g_survround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && g_swarmround) || (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && g_plagueround) || (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && !g_nemround && !g_survround && !g_swarmround && !g_plagueround))
  5569.         {
  5570.                 remove_task(TASK_AMBIENCESOUNDS)
  5571.                 set_task(2.0, "ambience_sound_effects", TASK_AMBIENCESOUNDS)
  5572.         }
  5573. }
  5574.  
  5575. // Zombie Me Function (player id, infector, turn into a nemesis, silent mode, deathmsg and rewards)
  5576. zombieme(id, infector, nemesis, silentmode, rewards)
  5577. {
  5578.         // User infect attempt forward
  5579.         ExecuteForward(g_fwUserInfect_attempt, g_fwDummyResult, id, infector, nemesis)
  5580.        
  5581.         // One or more plugins blocked the infection. Only allow this after making sure it's
  5582.         // not going to leave us with no zombies. Take into account a last player leaving case.
  5583.         // BUGFIX: only allow after a mode has started, to prevent blocking first zombie e.g.
  5584.         if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetZombies() > g_lastplayerleaving)
  5585.                 return;
  5586.        
  5587.         // Pre user infect forward
  5588.         ExecuteForward(g_fwUserInfected_pre, g_fwDummyResult, id, infector, nemesis)
  5589.        
  5590.         // Show zombie class menu if they haven't chosen any (e.g. just connected)
  5591.         if (g_zombieclassnext[id] == ZCLASS_NONE && get_pcvar_num(cvar_zclasses))
  5592.                 set_task(0.2, "show_menu_zclass", id)
  5593.        
  5594.         // Set selected zombie class
  5595.         g_zombieclass[id] = g_zombieclassnext[id]
  5596.         // If no class selected yet, use the first (default) one
  5597.         if (g_zombieclass[id] == ZCLASS_NONE) g_zombieclass[id] = 0
  5598.        
  5599.         // Way to go...
  5600.         g_zombie[id] = true
  5601.         g_nemesis[id] = false
  5602.         g_survivor[id] = false
  5603.         g_firstzombie[id] = false
  5604.        
  5605.         // Remove survivor's aura (bugfix)
  5606.         set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
  5607.        
  5608.         // Remove spawn protection (bugfix)
  5609.         g_nodamage[id] = false
  5610.         set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
  5611.        
  5612.         // Reset burning duration counter (bugfix)
  5613.         g_burning_duration[id] = 0
  5614.        
  5615.         // Show deathmsg and reward infector?
  5616.         if (rewards && infector)
  5617.         {
  5618.                 // Send death notice and fix the "dead" attrib on scoreboard
  5619.                 SendDeathMsg(infector, id)
  5620.                 FixDeadAttrib(id)
  5621.                
  5622.                 // Reward frags, deaths, health, and ammo packs
  5623.                 UpdateFrags(infector, id, get_pcvar_num(cvar_fragsinfect), 1, 1)
  5624.                 g_ammopacks[infector] += get_pcvar_num(cvar_ammoinfect)
  5625.                 fm_set_user_health(infector, pev(infector, pev_health) + get_pcvar_num(cvar_zombiebonushp))
  5626.         }
  5627.        
  5628.         // Cache speed, knockback, and name for player's class
  5629.         g_zombie_spd[id] = float(ArrayGetCell(g_zclass_spd, g_zombieclass[id]))
  5630.         g_zombie_knockback[id] = Float:ArrayGetCell(g_zclass_kb, g_zombieclass[id])
  5631.         ArrayGetString(g_zclass_name, g_zombieclass[id], g_zombie_classname[id], charsmax(g_zombie_classname[]))
  5632.        
  5633.         // Set zombie attributes based on the mode
  5634.         static sound[64]
  5635.         if (!silentmode)
  5636.         {
  5637.                 if (nemesis)
  5638.                 {
  5639.                         // Nemesis
  5640.                         g_nemesis[id] = true
  5641.                        
  5642.                         // Set health [0 = auto]
  5643.                         if (get_pcvar_num(cvar_nemhp) == 0)
  5644.                         {
  5645.                                 if (get_pcvar_num(cvar_nembasehp) == 0)
  5646.                                         fm_set_user_health(id, ArrayGetCell(g_zclass_hp, 0) * fnGetAlive())
  5647.                                 else
  5648.                                         fm_set_user_health(id, get_pcvar_num(cvar_nembasehp) * fnGetAlive())
  5649.                         }
  5650.                         else
  5651.                                 fm_set_user_health(id, get_pcvar_num(cvar_nemhp))
  5652.                        
  5653.                         // Set gravity, unless frozen
  5654.                         if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_nemgravity))
  5655.                 }
  5656.                 else if (fnGetZombies() == 1)
  5657.                 {
  5658.                         // First zombie
  5659.                         g_firstzombie[id] = true
  5660.                        
  5661.                         // Set health and gravity, unless frozen
  5662.                         fm_set_user_health(id, floatround(float(ArrayGetCell(g_zclass_hp, g_zombieclass[id])) * get_pcvar_float(cvar_zombiefirsthp)))
  5663.                         if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5664.                        
  5665.                         // Infection sound
  5666.                         ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound))
  5667.                         emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  5668.                 }
  5669.                 else
  5670.                 {
  5671.                         // Infected by someone
  5672.                        
  5673.                         // Set health and gravity, unless frozen
  5674.                         fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
  5675.                         if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5676.                        
  5677.                         // Infection sound
  5678.                         ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound))
  5679.                         emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  5680.                        
  5681.                         // Show Infection HUD notice
  5682.                         set_hudmessage(255, 0, 0, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  5683.                        
  5684.                         if (infector) // infected by someone?
  5685.                                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT2", g_playername[id], g_playername[infector])
  5686.                         else
  5687.                                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT", g_playername[id])
  5688.                 }
  5689.         }
  5690.         else
  5691.         {
  5692.                 // Silent mode, no HUD messages, no infection sounds
  5693.                
  5694.                 // Set health and gravity, unless frozen
  5695.                 fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
  5696.                 if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5697.         }
  5698.        
  5699.         // Remove previous tasks
  5700.         remove_task(id+TASK_MODEL)
  5701.         remove_task(id+TASK_BLOOD)
  5702.         remove_task(id+TASK_AURA)
  5703.         remove_task(id+TASK_BURN)
  5704.        
  5705.         // Switch to T
  5706.         if (fm_cs_get_user_team(id) != FM_CS_TEAM_T) // need to change team?
  5707.         {
  5708.                 remove_task(id+TASK_TEAM)
  5709.                 fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5710.                 fm_user_team_update(id)
  5711.         }
  5712.        
  5713.         // Custom models stuff
  5714.         static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  5715.         already_has_model = false
  5716.        
  5717.         if (g_handle_models_on_separate_ent)
  5718.         {
  5719.                 // Set the right model
  5720.                 if (g_nemesis[id])
  5721.                 {
  5722.                         iRand = random_num(0, ArraySize(model_nemesis) - 1)
  5723.                         ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5724.                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
  5725.                 }
  5726.                 else
  5727.                 {
  5728.                         if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  5729.                         {
  5730.                                 iRand = random_num(0, ArraySize(model_admin_zombie) - 1)
  5731.                                 ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5732.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
  5733.                         }
  5734.                         else
  5735.                         {
  5736.                                 iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
  5737.                                 ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5738.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
  5739.                         }
  5740.                 }
  5741.                
  5742.                 // Set model on player model entity
  5743.                 fm_set_playermodel_ent(id)
  5744.                
  5745.                 // Nemesis glow / remove glow on player model entity, unless frozen
  5746.                 if (!g_frozen[id])
  5747.                 {
  5748.                         if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  5749.                                 fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  5750.                         else
  5751.                                 fm_set_rendering(g_ent_playermodel[id])
  5752.                 }
  5753.         }
  5754.         else
  5755.         {
  5756.                 // Get current model for comparing it with the current one
  5757.                 fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  5758.                
  5759.                 // Set the right model, after checking that we don't already have it
  5760.                 if (g_nemesis[id])
  5761.                 {
  5762.                         size = ArraySize(model_nemesis)
  5763.                         for (i = 0; i < size; i++)
  5764.                         {
  5765.                                 ArrayGetString(model_nemesis, i, tempmodel, charsmax(tempmodel))
  5766.                                 if (equal(currentmodel, tempmodel)) already_has_model = true
  5767.                         }
  5768.                        
  5769.                         if (!already_has_model)
  5770.                         {
  5771.                                 iRand = random_num(0, size - 1)
  5772.                                 ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5773.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
  5774.                         }
  5775.                 }
  5776.                 else
  5777.                 {
  5778.                         if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  5779.                         {
  5780.                                 size = ArraySize(model_admin_zombie)
  5781.                                 for (i = 0; i < size; i++)
  5782.                                 {
  5783.                                         ArrayGetString(model_admin_zombie, i, tempmodel, charsmax(tempmodel))
  5784.                                         if (equal(currentmodel, tempmodel)) already_has_model = true
  5785.                                 }
  5786.                                
  5787.                                 if (!already_has_model)
  5788.                                 {
  5789.                                         iRand = random_num(0, size - 1)
  5790.                                         ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5791.                                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
  5792.                                 }
  5793.                         }
  5794.                         else
  5795.                         {
  5796.                                 for (i = ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]); i < ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]); i++)
  5797.                                 {
  5798.                                         ArrayGetString(g_zclass_playermodel, i, tempmodel, charsmax(tempmodel))
  5799.                                         if (equal(currentmodel, tempmodel)) already_has_model = true
  5800.                                 }
  5801.                                
  5802.                                 if (!already_has_model)
  5803.                                 {
  5804.                                         iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
  5805.                                         ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5806.                                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
  5807.                                 }
  5808.                         }
  5809.                 }
  5810.                
  5811.                 // Need to change the model?
  5812.                 if (!already_has_model)
  5813.                 {
  5814.                         // An additional delay is offset at round start
  5815.                         // since SVC_BAD is more likely to be triggered there
  5816.                         if (g_newround)
  5817.                                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  5818.                         else
  5819.                                 fm_user_model_update(id+TASK_MODEL)
  5820.                 }
  5821.                
  5822.                 // Nemesis glow / remove glow, unless frozen
  5823.                 if (!g_frozen[id])
  5824.                 {
  5825.                         if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  5826.                                 fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  5827.                         else
  5828.                                 fm_set_rendering(id)
  5829.                 }
  5830.         }
  5831.        
  5832.         // Remove any zoom (bugfix)
  5833.         cs_set_user_zoom(id, CS_RESET_ZOOM, 1)
  5834.        
  5835.         // Remove armor
  5836.         set_pev(id, pev_armorvalue, 0.0)
  5837.        
  5838.         // Drop weapons when infected
  5839.         drop_weapons(id, 1)
  5840.         drop_weapons(id, 2)
  5841.        
  5842.         // Strip zombies from guns and give them a knife
  5843.         fm_strip_user_weapons(id)
  5844.         fm_give_item(id, "weapon_knife")
  5845.        
  5846.         // Fancy effects
  5847.         infection_effects(id)
  5848.        
  5849.         // Nemesis aura task
  5850.         if (g_nemesis[id] && get_pcvar_num(cvar_nemaura))
  5851.                 set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
  5852.        
  5853.         // Give Zombies Night Vision?
  5854.         if (get_pcvar_num(cvar_nvggive))
  5855.         {
  5856.                 g_nvision[id] = true
  5857.                
  5858.                 if (!g_isbot[id])
  5859.                 {
  5860.                         // Turn on Night Vision automatically?
  5861.                         if (get_pcvar_num(cvar_nvggive) == 1)
  5862.                         {
  5863.                                 g_nvisionenabled[id] = true
  5864.                                
  5865.                                 // Custom nvg?
  5866.                                 if (get_pcvar_num(cvar_customnvg))
  5867.                                 {
  5868.                                         remove_task(id+TASK_NVISION)
  5869.                                         set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  5870.                                 }
  5871.                                 else
  5872.                                         set_user_gnvision(id, 1)
  5873.                         }
  5874.                         // Turn off nightvision when infected (bugfix)
  5875.                         else if (g_nvisionenabled[id])
  5876.                         {
  5877.                                 if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  5878.                                 else set_user_gnvision(id, 0)
  5879.                                 g_nvisionenabled[id] = false
  5880.                         }
  5881.                 }
  5882.                 else
  5883.                         cs_set_user_nvg(id, 1); // turn on NVG for bots
  5884.         }
  5885.         // Disable nightvision when infected (bugfix)
  5886.         else if (g_nvision[id])
  5887.         {
  5888.                 if (g_isbot[id]) cs_set_user_nvg(id, 0) // Turn off NVG for bots
  5889.                 if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  5890.                 else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  5891.                 g_nvision[id] = false
  5892.                 g_nvisionenabled[id] = false
  5893.         }
  5894.        
  5895.         // Set custom FOV?
  5896.         if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
  5897.         {
  5898.                 message_begin(MSG_ONE, g_msgSetFOV, _, id)
  5899.                 write_byte(get_pcvar_num(cvar_zombiefov)) // fov angle
  5900.                 message_end()
  5901.         }
  5902.        
  5903.         // Call the bloody task
  5904.         if (!g_nemesis[id] && get_pcvar_num(cvar_zombiebleeding))
  5905.                 set_task(0.7, "make_blood", id+TASK_BLOOD, _, _, "b")
  5906.        
  5907.         // Idle sounds task
  5908.         if (!g_nemesis[id])
  5909.                 set_task(random_float(50.0, 70.0), "zombie_play_idle", id+TASK_BLOOD, _, _, "b")
  5910.        
  5911.         // Turn off zombie's flashlight
  5912.         turn_off_flashlight(id)
  5913.        
  5914.         // Post user infect forward
  5915.         ExecuteForward(g_fwUserInfected_post, g_fwDummyResult, id, infector, nemesis)
  5916.        
  5917.         // Last Zombie Check
  5918.         fnCheckLastZombie()
  5919. }
  5920.  
  5921. // Function Human Me (player id, turn into a survivor, silent mode)
  5922. humanme(id, survivor, silentmode)
  5923. {
  5924.         // User humanize attempt forward
  5925.         ExecuteForward(g_fwUserHumanize_attempt, g_fwDummyResult, id, survivor)
  5926.        
  5927.         // One or more plugins blocked the "humanization". Only allow this after making sure it's
  5928.         // not going to leave us with no humans. Take into account a last player leaving case.
  5929.         // BUGFIX: only allow after a mode has started, to prevent blocking first survivor e.g.
  5930.         if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetHumans() > g_lastplayerleaving)
  5931.                 return;
  5932.        
  5933.         // Pre user humanize forward
  5934.         ExecuteForward(g_fwUserHumanized_pre, g_fwDummyResult, id, survivor)
  5935.        
  5936.         // Remove previous tasks
  5937.         remove_task(id+TASK_MODEL)
  5938.         remove_task(id+TASK_BLOOD)
  5939.         remove_task(id+TASK_AURA)
  5940.         remove_task(id+TASK_BURN)
  5941.         remove_task(id+TASK_NVISION)
  5942.        
  5943.         // Reset some vars
  5944.         g_zombie[id] = false
  5945.         g_nemesis[id] = false
  5946.         g_survivor[id] = false
  5947.         g_firstzombie[id] = false
  5948.         g_canbuy[id] = true
  5949.         g_nvision[id] = false
  5950.         g_nvisionenabled[id] = false
  5951.        
  5952.         // Remove survivor's aura (bugfix)
  5953.         set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
  5954.        
  5955.         // Remove spawn protection (bugfix)
  5956.         g_nodamage[id] = false
  5957.         set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
  5958.        
  5959.         // Reset burning duration counter (bugfix)
  5960.         g_burning_duration[id] = 0
  5961.        
  5962.         // Drop previous weapons
  5963.         drop_weapons(id, 1)
  5964.         drop_weapons(id, 2)
  5965.        
  5966.         // Strip off from weapons
  5967.         fm_strip_user_weapons(id)
  5968.         fm_give_item(id, "weapon_knife")
  5969.        
  5970.         // Set human attributes based on the mode
  5971.         if (survivor)
  5972.         {
  5973.                 // Survivor
  5974.                 g_survivor[id] = true
  5975.                
  5976.                 // Set Health [0 = auto]
  5977.                 if (get_pcvar_num(cvar_survhp) == 0)
  5978.                 {
  5979.                         if (get_pcvar_num(cvar_survbasehp) == 0)
  5980.                                 fm_set_user_health(id, get_pcvar_num(cvar_humanhp) * fnGetAlive())
  5981.                         else
  5982.                                 fm_set_user_health(id, get_pcvar_num(cvar_survbasehp) * fnGetAlive())
  5983.                 }
  5984.                 else
  5985.                         fm_set_user_health(id, get_pcvar_num(cvar_survhp))
  5986.                
  5987.                 // Set gravity, unless frozen
  5988.                 if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_survgravity))
  5989.                
  5990.                 // Give survivor his own weapon
  5991.                 static survweapon[32]
  5992.                 get_pcvar_string(cvar_survweapon, survweapon, charsmax(survweapon))
  5993.                 fm_give_item(id, survweapon)
  5994.                 ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[cs_weapon_name_to_id(survweapon)], AMMOTYPE[cs_weapon_name_to_id(survweapon)], MAXBPAMMO[cs_weapon_name_to_id(survweapon)])
  5995.                
  5996.                 // Turn off his flashlight
  5997.                 turn_off_flashlight(id)
  5998.                
  5999.                 // Give the survivor a bright light
  6000.                 if (get_pcvar_num(cvar_survaura)) set_pev(id, pev_effects, pev(id, pev_effects) | EF_BRIGHTLIGHT)
  6001.                
  6002.                 // Survivor bots will also need nightvision to see in the dark
  6003.                 if (g_isbot[id])
  6004.                 {
  6005.                         g_nvision[id] = true
  6006.                         cs_set_user_nvg(id, 1)
  6007.                 }
  6008.         }
  6009.         else
  6010.         {
  6011.                 // Human taking an antidote
  6012.                
  6013.                 // Set health
  6014.                 fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
  6015.                
  6016.                 // Set gravity, unless frozen
  6017.                 if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
  6018.                
  6019.                 // Show custom buy menu?
  6020.                 if (get_pcvar_num(cvar_buycustom))
  6021.                         set_task(0.2, "show_menu_buy1", id+TASK_SPAWN)
  6022.                
  6023.                 // Silent mode = no HUD messages, no antidote sound
  6024.                 if (!silentmode)
  6025.                 {
  6026.                         // Antidote sound
  6027.                         static sound[64]
  6028.                         ArrayGetString(sound_antidote, random_num(0, ArraySize(sound_antidote) - 1), sound, charsmax(sound))
  6029.                         emit_sound(id, CHAN_ITEM, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  6030.                        
  6031.                         // Show Antidote HUD notice
  6032.                         set_hudmessage(0, 0, 255, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  6033.                         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_ANTIDOTE", g_playername[id])
  6034.                 }
  6035.         }
  6036.        
  6037.         // Switch to CT
  6038.         if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  6039.         {
  6040.                 remove_task(id+TASK_TEAM)
  6041.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  6042.                 fm_user_team_update(id)
  6043.         }
  6044.        
  6045.         // Custom models stuff
  6046.         static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  6047.         already_has_model = false
  6048.        
  6049.         if (g_handle_models_on_separate_ent)
  6050.         {
  6051.                 // Set the right model
  6052.                 if (g_survivor[id])
  6053.                 {
  6054.                         iRand = random_num(0, ArraySize(model_survivor) - 1)
  6055.                         ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6056.                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
  6057.                 }
  6058.                 else
  6059.                 {
  6060.                         if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  6061.                         {
  6062.                                 iRand = random_num(0, ArraySize(model_admin_human) - 1)
  6063.                                 ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6064.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  6065.                         }
  6066.                         else
  6067.                         {
  6068.                                 iRand = random_num(0, ArraySize(model_human) - 1)
  6069.                                 ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6070.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  6071.                         }
  6072.                 }
  6073.                
  6074.                 // Set model on player model entity
  6075.                 fm_set_playermodel_ent(id)
  6076.                
  6077.                 // Set survivor glow / remove glow on player model entity, unless frozen
  6078.                 if (!g_frozen[id])
  6079.                 {
  6080.                         if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  6081.                                 fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  6082.                         else
  6083.                                 fm_set_rendering(g_ent_playermodel[id])
  6084.                 }
  6085.         }
  6086.         else
  6087.         {
  6088.                 // Get current model for comparing it with the current one
  6089.                 fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  6090.                
  6091.                 // Set the right model, after checking that we don't already have it
  6092.                 if (g_survivor[id])
  6093.                 {
  6094.                         size = ArraySize(model_survivor)
  6095.                         for (i = 0; i < size; i++)
  6096.                         {
  6097.                                 ArrayGetString(model_survivor, i, tempmodel, charsmax(tempmodel))
  6098.                                 if (equal(currentmodel, tempmodel)) already_has_model = true
  6099.                         }
  6100.                        
  6101.                         if (!already_has_model)
  6102.                         {
  6103.                                 iRand = random_num(0, size - 1)
  6104.                                 ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6105.                                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
  6106.                         }
  6107.                 }
  6108.                 else
  6109.                 {
  6110.                         if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  6111.                         {
  6112.                                 size = ArraySize(model_admin_human)
  6113.                                 for (i = 0; i < size; i++)
  6114.                                 {
  6115.                                         ArrayGetString(model_admin_human, i, tempmodel, charsmax(tempmodel))
  6116.                                         if (equal(currentmodel, tempmodel)) already_has_model = true
  6117.                                 }
  6118.                                
  6119.                                 if (!already_has_model)
  6120.                                 {
  6121.                                         iRand = random_num(0, size - 1)
  6122.                                         ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6123.                                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  6124.                                 }
  6125.                         }
  6126.                         else
  6127.                         {
  6128.                                 size = ArraySize(model_human)
  6129.                                 for (i = 0; i < size; i++)
  6130.                                 {
  6131.                                         ArrayGetString(model_human, i, tempmodel, charsmax(tempmodel))
  6132.                                         if (equal(currentmodel, tempmodel)) already_has_model = true
  6133.                                 }
  6134.                                
  6135.                                 if (!already_has_model)
  6136.                                 {
  6137.                                         iRand = random_num(0, size - 1)
  6138.                                         ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6139.                                         if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  6140.                                 }
  6141.                         }
  6142.                 }
  6143.                
  6144.                 // Need to change the model?
  6145.                 if (!already_has_model)
  6146.                 {
  6147.                         // An additional delay is offset at round start
  6148.                         // since SVC_BAD is more likely to be triggered there
  6149.                         if (g_newround)
  6150.                                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  6151.                         else
  6152.                                 fm_user_model_update(id+TASK_MODEL)
  6153.                 }
  6154.                
  6155.                 // Set survivor glow / remove glow, unless frozen
  6156.                 if (!g_frozen[id])
  6157.                 {
  6158.                         if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  6159.                                 fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  6160.                         else
  6161.                                 fm_set_rendering(id)
  6162.                 }
  6163.         }
  6164.        
  6165.         // Restore FOV?
  6166.         if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
  6167.         {
  6168.                 message_begin(MSG_ONE, g_msgSetFOV, _, id)
  6169.                 write_byte(90) // angle
  6170.                 message_end()
  6171.         }
  6172.        
  6173.         // Disable nightvision
  6174.         if (g_isbot[id]) cs_set_user_nvg(id, 0)
  6175.         else if (!get_pcvar_num(cvar_customnvg) && g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6176.        
  6177.         // Post user humanize forward
  6178.         ExecuteForward(g_fwUserHumanized_post, g_fwDummyResult, id, survivor)
  6179.        
  6180.         // Last Zombie Check
  6181.         fnCheckLastZombie()
  6182. }
  6183.  
  6184. /*================================================================================
  6185.  [Other Functions and Tasks]
  6186. =================================================================================*/
  6187.  
  6188. public cache_cvars()
  6189. {
  6190.         g_cached_zombiesilent = get_pcvar_num(cvar_zombiesilent)
  6191.         g_cached_customflash = get_pcvar_num(cvar_customflash)
  6192.         g_cached_humanspd = get_pcvar_float(cvar_humanspd)
  6193.         g_cached_nemspd = get_pcvar_float(cvar_nemspd)
  6194.         g_cached_survspd = get_pcvar_float(cvar_survspd)
  6195.         g_cached_leapzombies = get_pcvar_num(cvar_leapzombies)
  6196.         g_cached_leapzombiescooldown = get_pcvar_float(cvar_leapzombiescooldown)
  6197.         g_cached_leapnemesis = get_pcvar_num(cvar_leapnemesis)
  6198.         g_cached_leapnemesiscooldown = get_pcvar_float(cvar_leapnemesiscooldown)
  6199.         g_cached_leapsurvivor = get_pcvar_num(cvar_leapsurvivor)
  6200.         g_cached_leapsurvivorcooldown = get_pcvar_float(cvar_leapsurvivorcooldown)
  6201. }
  6202.  
  6203. load_customization_from_files()
  6204. {
  6205.         // Build customization file path
  6206.         new path[64]
  6207.         get_configsdir(path, charsmax(path))
  6208.         format(path, charsmax(path), "%s/%s", path, ZP_CUSTOMIZATION_FILE)
  6209.        
  6210.         // File not present
  6211.         if (!file_exists(path))
  6212.         {
  6213.                 new error[100]
  6214.                 formatex(error, charsmax(error), "Cannot load customization file %s!", path)
  6215.                 set_fail_state(error)
  6216.                 return;
  6217.         }
  6218.        
  6219.         // Set up some vars to hold parsing info
  6220.         new linedata[1024], key[64], value[960], section, teams
  6221.        
  6222.         // Open customization file for reading
  6223.         new file = fopen(path, "rt")
  6224.        
  6225.         while (file && !feof(file))
  6226.         {
  6227.                 // Read one line at a time
  6228.                 fgets(file, linedata, charsmax(linedata))
  6229.                
  6230.                 // Replace newlines with a null character to prevent headaches
  6231.                 replace(linedata, charsmax(linedata), "^n", "")
  6232.                
  6233.                 // Blank line or comment
  6234.                 if (!linedata[0] || linedata[0] == ';') continue;
  6235.                
  6236.                 // New section starting
  6237.                 if (linedata[0] == '[')
  6238.                 {
  6239.                         section++
  6240.                         continue;
  6241.                 }
  6242.                
  6243.                 // Get key and value(s)
  6244.                 strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  6245.                
  6246.                 // Trim spaces
  6247.                 trim(key)
  6248.                 trim(value)
  6249.                
  6250.                 switch (section)
  6251.                 {
  6252.                         case SECTION_ACCESS_FLAGS:
  6253.                         {
  6254.                                 if (equal(key, "ENABLE/DISABLE MOD"))
  6255.                                         g_access_flag[ACCESS_ENABLE_MOD] = read_flags(value)
  6256.                                 else if (equal(key, "ADMIN MENU"))
  6257.                                         g_access_flag[ACCESS_ADMIN_MENU] = read_flags(value)
  6258.                                 else if (equal(key, "START MODE INFECTION"))
  6259.                                         g_access_flag[ACCESS_MODE_INFECTION] = read_flags(value)
  6260.                                 else if (equal(key, "START MODE NEMESIS"))
  6261.                                         g_access_flag[ACCESS_MODE_NEMESIS] = read_flags(value)
  6262.                                 else if (equal(key, "START MODE SURVIVOR"))
  6263.                                         g_access_flag[ACCESS_MODE_SURVIVOR] = read_flags(value)
  6264.                                 else if (equal(key, "START MODE SWARM"))
  6265.                                         g_access_flag[ACCESS_MODE_SWARM] = read_flags(value)
  6266.                                 else if (equal(key, "START MODE MULTI"))
  6267.                                         g_access_flag[ACCESS_MODE_MULTI] = read_flags(value)
  6268.                                 else if (equal(key, "START MODE PLAGUE"))
  6269.                                         g_access_flag[ACCESS_MODE_PLAGUE] = read_flags(value)
  6270.                                 else if (equal(key, "MAKE ZOMBIE"))
  6271.                                         g_access_flag[ACCESS_MAKE_ZOMBIE] = read_flags(value)
  6272.                                 else if (equal(key, "MAKE HUMAN"))
  6273.                                         g_access_flag[ACCESS_MAKE_HUMAN] = read_flags(value)
  6274.                                 else if (equal(key, "MAKE NEMESIS"))
  6275.                                         g_access_flag[ACCESS_MAKE_NEMESIS] = read_flags(value)
  6276.                                 else if (equal(key, "MAKE SURVIVOR"))
  6277.                                         g_access_flag[ACCESS_MAKE_SURVIVOR] = read_flags(value)
  6278.                                 else if (equal(key, "RESPAWN PLAYERS"))
  6279.                                         g_access_flag[ACCESS_RESPAWN_PLAYERS] = read_flags(value)
  6280.                                 else if (equal(key, "ADMIN MODELS"))
  6281.                                         g_access_flag[ACCESS_ADMIN_MODELS] = read_flags(value)
  6282.                         }
  6283.                         case SECTION_PLAYER_MODELS:
  6284.                         {
  6285.                                 if (equal(key, "HUMAN"))
  6286.                                 {
  6287.                                         // Parse models
  6288.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6289.                                         {
  6290.                                                 // Trim spaces
  6291.                                                 trim(key)
  6292.                                                 trim(value)
  6293.                                                
  6294.                                                 // Add to models array
  6295.                                                 ArrayPushString(model_human, key)
  6296.                                         }
  6297.                                 }
  6298.                                 else if (equal(key, "NEMESIS"))
  6299.                                 {
  6300.                                         // Parse models
  6301.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6302.                                         {
  6303.                                                 // Trim spaces
  6304.                                                 trim(key)
  6305.                                                 trim(value)
  6306.                                                
  6307.                                                 // Add to models array
  6308.                                                 ArrayPushString(model_nemesis, key)
  6309.                                         }
  6310.                                 }
  6311.                                 else if (equal(key, "SURVIVOR"))
  6312.                                 {
  6313.                                         // Parse models
  6314.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6315.                                         {
  6316.                                                 // Trim spaces
  6317.                                                 trim(key)
  6318.                                                 trim(value)
  6319.                                                
  6320.                                                 // Add to models array
  6321.                                                 ArrayPushString(model_survivor, key)
  6322.                                         }
  6323.                                 }
  6324.                                 else if (equal(key, "ADMIN ZOMBIE"))
  6325.                                 {
  6326.                                         // Parse models
  6327.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6328.                                         {
  6329.                                                 // Trim spaces
  6330.                                                 trim(key)
  6331.                                                 trim(value)
  6332.                                                
  6333.                                                 // Add to models array
  6334.                                                 ArrayPushString(model_admin_zombie, key)
  6335.                                         }
  6336.                                 }
  6337.                                 else if (equal(key, "ADMIN HUMAN"))
  6338.                                 {
  6339.                                         // Parse models
  6340.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6341.                                         {
  6342.                                                 // Trim spaces
  6343.                                                 trim(key)
  6344.                                                 trim(value)
  6345.                                                
  6346.                                                 // Add to models array
  6347.                                                 ArrayPushString(model_admin_human, key)
  6348.                                         }
  6349.                                 }
  6350.                                 else if (equal(key, "FORCE CONSISTENCY"))
  6351.                                         g_force_consistency = str_to_num(value)
  6352.                                 else if (equal(key, "SAME MODELS FOR ALL"))
  6353.                                         g_same_models_for_all = str_to_num(value)
  6354.                                 else if (g_same_models_for_all && equal(key, "ZOMBIE"))
  6355.                                 {
  6356.                                         // Parse models
  6357.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6358.                                         {
  6359.                                                 // Trim spaces
  6360.                                                 trim(key)
  6361.                                                 trim(value)
  6362.                                                
  6363.                                                 // Add to models array
  6364.                                                 ArrayPushString(g_zclass_playermodel, key)
  6365.                                                
  6366.                                                 // Precache model and retrieve its modelindex
  6367.                                                 formatex(linedata, charsmax(linedata), "models/player/%s/%s.mdl", key, key)
  6368.                                                 ArrayPushCell(g_zclass_modelindex, engfunc(EngFunc_PrecacheModel, linedata))
  6369.                                                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, linedata)
  6370.                                                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, linedata)
  6371.                                         }
  6372.                                 }
  6373.                         }
  6374.                         case SECTION_WEAPON_MODELS:
  6375.                         {
  6376.                                 if (equal(key, "V_KNIFE HUMAN"))
  6377.                                         copy(model_vknife_human, charsmax(model_vknife_human), value)
  6378.                                 else if (equal(key, "V_KNIFE NEMESIS"))
  6379.                                         copy(model_vknife_nemesis, charsmax(model_vknife_nemesis), value)
  6380.                                 else if (equal(key, "V_M249 SURVIVOR"))
  6381.                                         copy(model_vm249_survivor, charsmax(model_vm249_survivor), value)
  6382.                                 else if (equal(key, "GRENADE INFECT"))
  6383.                                         copy(model_grenade_infect, charsmax(model_grenade_infect), value)
  6384.                                 else if (equal(key, "GRENADE FIRE"))
  6385.                                         copy(model_grenade_fire, charsmax(model_grenade_fire), value)
  6386.                                 else if (equal(key, "GRENADE FROST"))
  6387.                                         copy(model_grenade_frost, charsmax(model_grenade_frost), value)
  6388.                                 else if (equal(key, "GRENADE FLARE"))
  6389.                                         copy(model_grenade_flare, charsmax(model_grenade_flare), value)
  6390.                                 else if (equal(key, "V_KNIFE ADMIN HUMAN"))
  6391.                                         copy(model_vknife_admin_human, charsmax(model_vknife_admin_human), value)
  6392.                                 else if (equal(key, "V_KNIFE ADMIN ZOMBIE"))
  6393.                                         copy(model_vknife_admin_zombie, charsmax(model_vknife_admin_zombie), value)
  6394.                         }
  6395.                         case SECTION_GRENADE_SPRITES:
  6396.                         {
  6397.                                 if (equal(key, "TRAIL"))
  6398.                                         copy(sprite_grenade_trail, charsmax(sprite_grenade_trail), value)
  6399.                                 else if (equal(key, "RING"))
  6400.                                         copy(sprite_grenade_ring, charsmax(sprite_grenade_ring), value)
  6401.                                 else if (equal(key, "FIRE"))
  6402.                                         copy(sprite_grenade_fire, charsmax(sprite_grenade_fire), value)
  6403.                                 else if (equal(key, "SMOKE"))
  6404.                                         copy(sprite_grenade_smoke, charsmax(sprite_grenade_smoke), value)
  6405.                                 else if (equal(key, "GLASS"))
  6406.                                         copy(sprite_grenade_glass, charsmax(sprite_grenade_glass), value)
  6407.                         }
  6408.                         case SECTION_SOUNDS:
  6409.                         {
  6410.                                 if (equal(key, "WIN ZOMBIES"))
  6411.                                 {
  6412.                                         // Parse sounds
  6413.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6414.                                         {
  6415.                                                 // Trim spaces
  6416.                                                 trim(key)
  6417.                                                 trim(value)
  6418.                                                
  6419.                                                 // Add to sounds array
  6420.                                                 ArrayPushString(sound_win_zombies, key)
  6421.                                         }
  6422.                                 }
  6423.                                 else if (equal(key, "WIN HUMANS"))
  6424.                                 {
  6425.                                         // Parse sounds
  6426.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6427.                                         {
  6428.                                                 // Trim spaces
  6429.                                                 trim(key)
  6430.                                                 trim(value)
  6431.                                                
  6432.                                                 // Add to sounds array
  6433.                                                 ArrayPushString(sound_win_humans, key)
  6434.                                         }
  6435.                                 }
  6436.                                 else if (equal(key, "WIN NO ONE"))
  6437.                                 {
  6438.                                         // Parse sounds
  6439.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6440.                                         {
  6441.                                                 // Trim spaces
  6442.                                                 trim(key)
  6443.                                                 trim(value)
  6444.                                                
  6445.                                                 // Add to sounds array
  6446.                                                 ArrayPushString(sound_win_no_one, key)
  6447.                                         }
  6448.                                 }
  6449.                                 else if (equal(key, "ZOMBIE INFECT"))
  6450.                                 {
  6451.                                         // Parse sounds
  6452.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6453.                                         {
  6454.                                                 // Trim spaces
  6455.                                                 trim(key)
  6456.                                                 trim(value)
  6457.                                                
  6458.                                                 // Add to sounds array
  6459.                                                 ArrayPushString(zombie_infect, key)
  6460.                                         }
  6461.                                 }
  6462.                                 else if (equal(key, "ZOMBIE PAIN"))
  6463.                                 {
  6464.                                         // Parse sounds
  6465.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6466.                                         {
  6467.                                                 // Trim spaces
  6468.                                                 trim(key)
  6469.                                                 trim(value)
  6470.                                                
  6471.                                                 // Add to sounds array
  6472.                                                 ArrayPushString(zombie_pain, key)
  6473.                                         }
  6474.                                 }
  6475.                                 else if (equal(key, "NEMESIS PAIN"))
  6476.                                 {
  6477.                                         // Parse sounds
  6478.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6479.                                         {
  6480.                                                 // Trim spaces
  6481.                                                 trim(key)
  6482.                                                 trim(value)
  6483.                                                
  6484.                                                 // Add to sounds array
  6485.                                                 ArrayPushString(nemesis_pain, key)
  6486.                                         }
  6487.                                 }
  6488.                                 else if (equal(key, "ZOMBIE DIE"))
  6489.                                 {
  6490.                                         // Parse sounds
  6491.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6492.                                         {
  6493.                                                 // Trim spaces
  6494.                                                 trim(key)
  6495.                                                 trim(value)
  6496.                                                
  6497.                                                 // Add to sounds array
  6498.                                                 ArrayPushString(zombie_die, key)
  6499.                                         }
  6500.                                 }
  6501.                                 else if (equal(key, "ZOMBIE FALL"))
  6502.                                 {
  6503.                                         // Parse sounds
  6504.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6505.                                         {
  6506.                                                 // Trim spaces
  6507.                                                 trim(key)
  6508.                                                 trim(value)
  6509.                                                
  6510.                                                 // Add to sounds array
  6511.                                                 ArrayPushString(zombie_fall, key)
  6512.                                         }
  6513.                                 }
  6514.                                 else if (equal(key, "ZOMBIE MISS SLASH"))
  6515.                                 {
  6516.                                         // Parse sounds
  6517.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6518.                                         {
  6519.                                                 // Trim spaces
  6520.                                                 trim(key)
  6521.                                                 trim(value)
  6522.                                                
  6523.                                                 // Add to sounds array
  6524.                                                 ArrayPushString(zombie_miss_slash, key)
  6525.                                         }
  6526.                                 }
  6527.                                 else if (equal(key, "ZOMBIE MISS WALL"))
  6528.                                 {
  6529.                                         // Parse sounds
  6530.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6531.                                         {
  6532.                                                 // Trim spaces
  6533.                                                 trim(key)
  6534.                                                 trim(value)
  6535.                                                
  6536.                                                 // Add to sounds array
  6537.                                                 ArrayPushString(zombie_miss_wall, key)
  6538.                                         }
  6539.                                 }
  6540.                                 else if (equal(key, "ZOMBIE HIT NORMAL"))
  6541.                                 {
  6542.                                         // Parse sounds
  6543.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6544.                                         {
  6545.                                                 // Trim spaces
  6546.                                                 trim(key)
  6547.                                                 trim(value)
  6548.                                                
  6549.                                                 // Add to sounds array
  6550.                                                 ArrayPushString(zombie_hit_normal, key)
  6551.                                         }
  6552.                                 }
  6553.                                 else if (equal(key, "ZOMBIE HIT STAB"))
  6554.                                 {
  6555.                                         // Parse sounds
  6556.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6557.                                         {
  6558.                                                 // Trim spaces
  6559.                                                 trim(key)
  6560.                                                 trim(value)
  6561.                                                
  6562.                                                 // Add to sounds array
  6563.                                                 ArrayPushString(zombie_hit_stab, key)
  6564.                                         }
  6565.                                 }
  6566.                                 else if (equal(key, "ZOMBIE IDLE"))
  6567.                                 {
  6568.                                         // Parse sounds
  6569.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6570.                                         {
  6571.                                                 // Trim spaces
  6572.                                                 trim(key)
  6573.                                                 trim(value)
  6574.                                                
  6575.                                                 // Add to sounds array
  6576.                                                 ArrayPushString(zombie_idle, key)
  6577.                                         }
  6578.                                 }
  6579.                                 else if (equal(key, "ZOMBIE IDLE LAST"))
  6580.                                 {
  6581.                                         // Parse sounds
  6582.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6583.                                         {
  6584.                                                 // Trim spaces
  6585.                                                 trim(key)
  6586.                                                 trim(value)
  6587.                                                
  6588.                                                 // Add to sounds array
  6589.                                                 ArrayPushString(zombie_idle_last, key)
  6590.                                         }
  6591.                                 }
  6592.                                 else if (equal(key, "ZOMBIE MADNESS"))
  6593.                                 {
  6594.                                         // Parse sounds
  6595.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6596.                                         {
  6597.                                                 // Trim spaces
  6598.                                                 trim(key)
  6599.                                                 trim(value)
  6600.                                                
  6601.                                                 // Add to sounds array
  6602.                                                 ArrayPushString(zombie_madness, key)
  6603.                                         }
  6604.                                 }
  6605.                                 else if (equal(key, "ROUND NEMESIS"))
  6606.                                 {
  6607.                                         // Parse sounds
  6608.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6609.                                         {
  6610.                                                 // Trim spaces
  6611.                                                 trim(key)
  6612.                                                 trim(value)
  6613.                                                
  6614.                                                 // Add to sounds array
  6615.                                                 ArrayPushString(sound_nemesis, key)
  6616.                                         }
  6617.                                 }
  6618.                                 else if (equal(key, "ROUND SURVIVOR"))
  6619.                                 {
  6620.                                         // Parse sounds
  6621.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6622.                                         {
  6623.                                                 // Trim spaces
  6624.                                                 trim(key)
  6625.                                                 trim(value)
  6626.                                                
  6627.                                                 // Add to sounds array
  6628.                                                 ArrayPushString(sound_survivor, key)
  6629.                                         }
  6630.                                 }
  6631.                                 else if (equal(key, "ROUND SWARM"))
  6632.                                 {
  6633.                                         // Parse sounds
  6634.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6635.                                         {
  6636.                                                 // Trim spaces
  6637.                                                 trim(key)
  6638.                                                 trim(value)
  6639.                                                
  6640.                                                 // Add to sounds array
  6641.                                                 ArrayPushString(sound_swarm, key)
  6642.                                         }
  6643.                                 }
  6644.                                 else if (equal(key, "ROUND MULTI"))
  6645.                                 {
  6646.                                         // Parse sounds
  6647.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6648.                                         {
  6649.                                                 // Trim spaces
  6650.                                                 trim(key)
  6651.                                                 trim(value)
  6652.                                                
  6653.                                                 // Add to sounds array
  6654.                                                 ArrayPushString(sound_multi, key)
  6655.                                         }
  6656.                                 }
  6657.                                 else if (equal(key, "ROUND PLAGUE"))
  6658.                                 {
  6659.                                         // Parse sounds
  6660.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6661.                                         {
  6662.                                                 // Trim spaces
  6663.                                                 trim(key)
  6664.                                                 trim(value)
  6665.                                                
  6666.                                                 // Add to sounds array
  6667.                                                 ArrayPushString(sound_plague, key)
  6668.                                         }
  6669.                                 }
  6670.                                 else if (equal(key, "GRENADE INFECT EXPLODE"))
  6671.                                 {
  6672.                                         // Parse sounds
  6673.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6674.                                         {
  6675.                                                 // Trim spaces
  6676.                                                 trim(key)
  6677.                                                 trim(value)
  6678.                                                
  6679.                                                 // Add to sounds array
  6680.                                                 ArrayPushString(grenade_infect, key)
  6681.                                         }
  6682.                                 }
  6683.                                 else if (equal(key, "GRENADE INFECT PLAYER"))
  6684.                                 {
  6685.                                         // Parse sounds
  6686.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6687.                                         {
  6688.                                                 // Trim spaces
  6689.                                                 trim(key)
  6690.                                                 trim(value)
  6691.                                                
  6692.                                                 // Add to sounds array
  6693.                                                 ArrayPushString(grenade_infect_player, key)
  6694.                                         }
  6695.                                 }
  6696.                                 else if (equal(key, "GRENADE FIRE EXPLODE"))
  6697.                                 {
  6698.                                         // Parse sounds
  6699.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6700.                                         {
  6701.                                                 // Trim spaces
  6702.                                                 trim(key)
  6703.                                                 trim(value)
  6704.                                                
  6705.                                                 // Add to sounds array
  6706.                                                 ArrayPushString(grenade_fire, key)
  6707.                                         }
  6708.                                 }
  6709.                                 else if (equal(key, "GRENADE FIRE PLAYER"))
  6710.                                 {
  6711.                                         // Parse sounds
  6712.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6713.                                         {
  6714.                                                 // Trim spaces
  6715.                                                 trim(key)
  6716.                                                 trim(value)
  6717.                                                
  6718.                                                 // Add to sounds array
  6719.                                                 ArrayPushString(grenade_fire_player, key)
  6720.                                         }
  6721.                                 }
  6722.                                 else if (equal(key, "GRENADE FROST EXPLODE"))
  6723.                                 {
  6724.                                         // Parse sounds
  6725.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6726.                                         {
  6727.                                                 // Trim spaces
  6728.                                                 trim(key)
  6729.                                                 trim(value)
  6730.                                                
  6731.                                                 // Add to sounds array
  6732.                                                 ArrayPushString(grenade_frost, key)
  6733.                                         }
  6734.                                 }
  6735.                                 else if (equal(key, "GRENADE FROST PLAYER"))
  6736.                                 {
  6737.                                         // Parse sounds
  6738.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6739.                                         {
  6740.                                                 // Trim spaces
  6741.                                                 trim(key)
  6742.                                                 trim(value)
  6743.                                                
  6744.                                                 // Add to sounds array
  6745.                                                 ArrayPushString(grenade_frost_player, key)
  6746.                                         }
  6747.                                 }
  6748.                                 else if (equal(key, "GRENADE FROST BREAK"))
  6749.                                 {
  6750.                                         // Parse sounds
  6751.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6752.                                         {
  6753.                                                 // Trim spaces
  6754.                                                 trim(key)
  6755.                                                 trim(value)
  6756.                                                
  6757.                                                 // Add to sounds array
  6758.                                                 ArrayPushString(grenade_frost_break, key)
  6759.                                         }
  6760.                                 }
  6761.                                 else if (equal(key, "GRENADE FLARE"))
  6762.                                 {
  6763.                                         // Parse sounds
  6764.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6765.                                         {
  6766.                                                 // Trim spaces
  6767.                                                 trim(key)
  6768.                                                 trim(value)
  6769.                                                
  6770.                                                 // Add to sounds array
  6771.                                                 ArrayPushString(grenade_flare, key)
  6772.                                         }
  6773.                                 }
  6774.                                 else if (equal(key, "ANTIDOTE"))
  6775.                                 {
  6776.                                         // Parse sounds
  6777.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6778.                                         {
  6779.                                                 // Trim spaces
  6780.                                                 trim(key)
  6781.                                                 trim(value)
  6782.                                                
  6783.                                                 // Add to sounds array
  6784.                                                 ArrayPushString(sound_antidote, key)
  6785.                                         }
  6786.                                 }
  6787.                                 else if (equal(key, "THUNDER"))
  6788.                                 {
  6789.                                         // Parse sounds
  6790.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6791.                                         {
  6792.                                                 // Trim spaces
  6793.                                                 trim(key)
  6794.                                                 trim(value)
  6795.                                                
  6796.                                                 // Add to sounds array
  6797.                                                 ArrayPushString(sound_thunder, key)
  6798.                                         }
  6799.                                 }
  6800.                         }
  6801.                         case SECTION_AMBIENCE_SOUNDS:
  6802.                         {
  6803.                                 if (equal(key, "INFECTION ENABLE"))
  6804.                                         g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] = str_to_num(value)
  6805.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION SOUNDS"))
  6806.                                 {
  6807.                                         // Parse sounds
  6808.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6809.                                         {
  6810.                                                 // Trim spaces
  6811.                                                 trim(key)
  6812.                                                 trim(value)
  6813.                                                
  6814.                                                 // Add to sounds array
  6815.                                                 ArrayPushString(sound_ambience1, key)
  6816.                                                 ArrayPushCell(sound_ambience1_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6817.                                         }
  6818.                                 }
  6819.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION DURATIONS"))
  6820.                                 {
  6821.                                         // Parse sounds
  6822.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6823.                                         {
  6824.                                                 // Trim spaces
  6825.                                                 trim(key)
  6826.                                                 trim(value)
  6827.                                                
  6828.                                                 // Add to sounds array
  6829.                                                 ArrayPushCell(sound_ambience1_duration, str_to_num(key))
  6830.                                         }
  6831.                                 }
  6832.                                 else if (equal(key, "NEMESIS ENABLE"))
  6833.                                         g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] = str_to_num(value)
  6834.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS SOUNDS"))
  6835.                                 {
  6836.                                         // Parse sounds
  6837.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6838.                                         {
  6839.                                                 // Trim spaces
  6840.                                                 trim(key)
  6841.                                                 trim(value)
  6842.                                                
  6843.                                                 // Add to sounds array
  6844.                                                 ArrayPushString(sound_ambience2, key)
  6845.                                                 ArrayPushCell(sound_ambience2_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6846.                                         }
  6847.                                 }
  6848.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS DURATIONS"))
  6849.                                 {
  6850.                                         // Parse sounds
  6851.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6852.                                         {
  6853.                                                 // Trim spaces
  6854.                                                 trim(key)
  6855.                                                 trim(value)
  6856.                                                
  6857.                                                 // Add to sounds array
  6858.                                                 ArrayPushCell(sound_ambience2_duration, str_to_num(key))
  6859.                                         }
  6860.                                 }
  6861.                                 else if (equal(key, "SURVIVOR ENABLE"))
  6862.                                         g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] = str_to_num(value)
  6863.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR SOUNDS"))
  6864.                                 {
  6865.                                         // Parse sounds
  6866.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6867.                                         {
  6868.                                                 // Trim spaces
  6869.                                                 trim(key)
  6870.                                                 trim(value)
  6871.                                                
  6872.                                                 // Add to sounds array
  6873.                                                 ArrayPushString(sound_ambience3, key)
  6874.                                                 ArrayPushCell(sound_ambience3_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6875.                                         }
  6876.                                 }
  6877.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR DURATIONS"))
  6878.                                 {
  6879.                                         // Parse sounds
  6880.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6881.                                         {
  6882.                                                 // Trim spaces
  6883.                                                 trim(key)
  6884.                                                 trim(value)
  6885.                                                
  6886.                                                 // Add to sounds array
  6887.                                                 ArrayPushCell(sound_ambience3_duration, str_to_num(key))
  6888.                                         }
  6889.                                 }
  6890.                                 else if (equal(key, "SWARM ENABLE"))
  6891.                                         g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] = str_to_num(value)
  6892.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM SOUNDS"))
  6893.                                 {
  6894.                                         // Parse sounds
  6895.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6896.                                         {
  6897.                                                 // Trim spaces
  6898.                                                 trim(key)
  6899.                                                 trim(value)
  6900.                                                
  6901.                                                 // Add to sounds array
  6902.                                                 ArrayPushString(sound_ambience4, key)
  6903.                                                 ArrayPushCell(sound_ambience4_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6904.                                         }
  6905.                                 }
  6906.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM DURATIONS"))
  6907.                                 {
  6908.                                         // Parse sounds
  6909.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6910.                                         {
  6911.                                                 // Trim spaces
  6912.                                                 trim(key)
  6913.                                                 trim(value)
  6914.                                                
  6915.                                                 // Add to sounds array
  6916.                                                 ArrayPushCell(sound_ambience4_duration, str_to_num(key))
  6917.                                         }
  6918.                                 }
  6919.                                 else if (equal(key, "PLAGUE ENABLE"))
  6920.                                         g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] = str_to_num(value)
  6921.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE SOUNDS"))
  6922.                                 {
  6923.                                         // Parse sounds
  6924.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6925.                                         {
  6926.                                                 // Trim spaces
  6927.                                                 trim(key)
  6928.                                                 trim(value)
  6929.                                                
  6930.                                                 // Add to sounds array
  6931.                                                 ArrayPushString(sound_ambience5, key)
  6932.                                                 ArrayPushCell(sound_ambience5_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6933.                                         }
  6934.                                 }
  6935.                                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE DURATIONS"))
  6936.                                 {
  6937.                                         // Parse sounds
  6938.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6939.                                         {
  6940.                                                 // Trim spaces
  6941.                                                 trim(key)
  6942.                                                 trim(value)
  6943.                                                
  6944.                                                 // Add to sounds array
  6945.                                                 ArrayPushCell(sound_ambience5_duration, str_to_num(key))
  6946.                                         }
  6947.                                 }
  6948.                         }
  6949.                         case SECTION_BUY_MENU_WEAPONS:
  6950.                         {
  6951.                                 if (equal(key, "PRIMARY"))
  6952.                                 {
  6953.                                         // Parse weapons
  6954.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6955.                                         {
  6956.                                                 // Trim spaces
  6957.                                                 trim(key)
  6958.                                                 trim(value)
  6959.                                                
  6960.                                                 // Add to weapons array
  6961.                                                 ArrayPushString(g_primary_items, key)
  6962.                                                 ArrayPushCell(g_primary_weaponids, cs_weapon_name_to_id(key))
  6963.                                         }
  6964.                                 }
  6965.                                 else if (equal(key, "SECONDARY"))
  6966.                                 {
  6967.                                         // Parse weapons
  6968.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6969.                                         {
  6970.                                                 // Trim spaces
  6971.                                                 trim(key)
  6972.                                                 trim(value)
  6973.                                                
  6974.                                                 // Add to weapons array
  6975.                                                 ArrayPushString(g_secondary_items, key)
  6976.                                                 ArrayPushCell(g_secondary_weaponids, cs_weapon_name_to_id(key))
  6977.                                         }
  6978.                                 }
  6979.                                 else if (equal(key, "ADDITIONAL ITEMS"))
  6980.                                 {
  6981.                                         // Parse weapons
  6982.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6983.                                         {
  6984.                                                 // Trim spaces
  6985.                                                 trim(key)
  6986.                                                 trim(value)
  6987.                                                
  6988.                                                 // Add to weapons array
  6989.                                                 ArrayPushString(g_additional_items, key)
  6990.                                         }
  6991.                                 }
  6992.                         }
  6993.                         case SECTION_EXTRA_ITEMS_WEAPONS:
  6994.                         {
  6995.                                 if (equal(key, "NAMES"))
  6996.                                 {
  6997.                                         // Parse weapon items
  6998.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6999.                                         {
  7000.                                                 // Trim spaces
  7001.                                                 trim(key)
  7002.                                                 trim(value)
  7003.                                                
  7004.                                                 // Add to weapons array
  7005.                                                 ArrayPushString(g_extraweapon_names, key)
  7006.                                         }
  7007.                                 }
  7008.                                 else if (equal(key, "ITEMS"))
  7009.                                 {
  7010.                                         // Parse weapon items
  7011.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7012.                                         {
  7013.                                                 // Trim spaces
  7014.                                                 trim(key)
  7015.                                                 trim(value)
  7016.                                                
  7017.                                                 // Add to weapons array
  7018.                                                 ArrayPushString(g_extraweapon_items, key)
  7019.                                         }
  7020.                                 }
  7021.                                 else if (equal(key, "COSTS"))
  7022.                                 {
  7023.                                         // Parse weapon items
  7024.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7025.                                         {
  7026.                                                 // Trim spaces
  7027.                                                 trim(key)
  7028.                                                 trim(value)
  7029.                                                
  7030.                                                 // Add to weapons array
  7031.                                                 ArrayPushCell(g_extraweapon_costs, str_to_num(key))
  7032.                                         }
  7033.                                 }
  7034.                         }
  7035.                         case SECTION_HARD_CODED_ITEMS_COSTS:
  7036.                         {
  7037.                                 if (equal(key, "NIGHT VISION"))
  7038.                                         g_extra_costs2[EXTRA_NVISION] = str_to_num(value)
  7039.                                 else if (equal(key, "ANTIDOTE"))
  7040.                                         g_extra_costs2[EXTRA_ANTIDOTE] = str_to_num(value)
  7041.                                 else if (equal(key, "ZOMBIE MADNESS"))
  7042.                                         g_extra_costs2[EXTRA_MADNESS] = str_to_num(value)
  7043.                                 else if (equal(key, "INFECTION BOMB"))
  7044.                                         g_extra_costs2[EXTRA_INFBOMB] = str_to_num(value)
  7045.                         }
  7046.                         case SECTION_WEATHER_EFFECTS:
  7047.                         {
  7048.                                 if (equal(key, "RAIN"))
  7049.                                         g_ambience_rain = str_to_num(value)
  7050.                                 else if (equal(key, "SNOW"))
  7051.                                         g_ambience_snow = str_to_num(value)
  7052.                                 else if (equal(key, "FOG"))
  7053.                                         g_ambience_fog = str_to_num(value)
  7054.                                 else if (equal(key, "FOG DENSITY"))
  7055.                                         copy(g_fog_density, charsmax(g_fog_density), value)
  7056.                                 else if (equal(key, "FOG COLOR"))
  7057.                                         copy(g_fog_color, charsmax(g_fog_color), value)
  7058.                         }
  7059.                         case SECTION_SKY:
  7060.                         {
  7061.                                 if (equal(key, "ENABLE"))
  7062.                                         g_sky_enable = str_to_num(value)
  7063.                                 else if (equal(key, "SKY NAMES"))
  7064.                                 {
  7065.                                         // Parse sky names
  7066.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7067.                                         {
  7068.                                                 // Trim spaces
  7069.                                                 trim(key)
  7070.                                                 trim(value)
  7071.                                                
  7072.                                                 // Add to skies array
  7073.                                                 ArrayPushString(g_sky_names, key)
  7074.                                                
  7075.                                                 // Preache custom sky files
  7076.                                                 formatex(linedata, charsmax(linedata), "gfx/env/%sbk.tga", key)
  7077.                                                 engfunc(EngFunc_PrecacheGeneric, linedata)
  7078.                                                 formatex(linedata, charsmax(linedata), "gfx/env/%sdn.tga", key)
  7079.                                                 engfunc(EngFunc_PrecacheGeneric, linedata)
  7080.                                                 formatex(linedata, charsmax(linedata), "gfx/env/%sft.tga", key)
  7081.                                                 engfunc(EngFunc_PrecacheGeneric, linedata)
  7082.                                                 formatex(linedata, charsmax(linedata), "gfx/env/%slf.tga", key)
  7083.                                                 engfunc(EngFunc_PrecacheGeneric, linedata)
  7084.                                                 formatex(linedata, charsmax(linedata), "gfx/env/%srt.tga", key)
  7085.                                                 engfunc(EngFunc_PrecacheGeneric, linedata)
  7086.                                                 formatex(linedata, charsmax(linedata), "gfx/env/%sup.tga", key)
  7087.                                                 engfunc(EngFunc_PrecacheGeneric, linedata)
  7088.                                         }
  7089.                                 }
  7090.                         }
  7091.                         case SECTION_LIGHTNING:
  7092.                         {
  7093.                                 if (equal(key, "LIGHTS"))
  7094.                                 {
  7095.                                         // Parse lights
  7096.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7097.                                         {
  7098.                                                 // Trim spaces
  7099.                                                 trim(key)
  7100.                                                 trim(value)
  7101.                                                
  7102.                                                 // Add to lightning array
  7103.                                                 ArrayPushString(lights_thunder, key)
  7104.                                         }
  7105.                                 }
  7106.                         }
  7107.                         case SECTION_ZOMBIE_DECALS:
  7108.                         {
  7109.                                 if (equal(key, "DECALS"))
  7110.                                 {
  7111.                                         // Parse decals
  7112.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7113.                                         {
  7114.                                                 // Trim spaces
  7115.                                                 trim(key)
  7116.                                                 trim(value)
  7117.                                                
  7118.                                                 // Add to zombie decals array
  7119.                                                 ArrayPushCell(zombie_decals, str_to_num(key))
  7120.                                         }
  7121.                                 }
  7122.                         }
  7123.                         case SECTION_KNOCKBACK:
  7124.                         {
  7125.                                 // Format weapon entity name
  7126.                                 strtolower(key)
  7127.                                 format(key, charsmax(key), "weapon_%s", key)
  7128.                                
  7129.                                 // Add value to knockback power array
  7130.                                 kb_weapon_power[cs_weapon_name_to_id(key)] = str_to_float(value)
  7131.                         }
  7132.                         case SECTION_OBJECTIVE_ENTS:
  7133.                         {
  7134.                                 if (equal(key, "CLASSNAMES"))
  7135.                                 {
  7136.                                         // Parse classnames
  7137.                                         while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7138.                                         {
  7139.                                                 // Trim spaces
  7140.                                                 trim(key)
  7141.                                                 trim(value)
  7142.                                                
  7143.                                                 // Add to objective ents array
  7144.                                                 ArrayPushString(g_objective_ents, key)
  7145.                                         }
  7146.                                 }
  7147.                         }
  7148.                         case SECTION_SVC_BAD:
  7149.                         {
  7150.                                 if (equal(key, "MODELCHANGE DELAY"))
  7151.                                         g_modelchange_delay = str_to_float(value)
  7152.                                 else if (equal(key, "HANDLE MODELS ON SEPARATE ENT"))
  7153.                                         g_handle_models_on_separate_ent = str_to_num(value)
  7154.                                 else if (equal(key, "SET MODELINDEX OFFSET"))
  7155.                                         g_set_modelindex_offset = str_to_num(value)
  7156.                         }
  7157.                 }
  7158.         }
  7159.         if (file) fclose(file)
  7160.        
  7161.         // Build zombie classes file path
  7162.         get_configsdir(path, charsmax(path))
  7163.         format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
  7164.        
  7165.         // Parse if present
  7166.         if (file_exists(path))
  7167.         {
  7168.                 // Open zombie classes file for reading
  7169.                 file = fopen(path, "rt")
  7170.                
  7171.                 while (file && !feof(file))
  7172.                 {
  7173.                         // Read one line at a time
  7174.                         fgets(file, linedata, charsmax(linedata))
  7175.                        
  7176.                         // Replace newlines with a null character to prevent headaches
  7177.                         replace(linedata, charsmax(linedata), "^n", "")
  7178.                        
  7179.                         // Blank line or comment
  7180.                         if (!linedata[0] || linedata[0] == ';') continue;
  7181.                        
  7182.                         // New class starting
  7183.                         if (linedata[0] == '[')
  7184.                         {
  7185.                                 // Remove first and last characters (braces)
  7186.                                 linedata[strlen(linedata) - 1] = 0
  7187.                                 copy(linedata, charsmax(linedata), linedata[1])
  7188.                                
  7189.                                 // Store its real name for future reference
  7190.                                 ArrayPushString(g_zclass2_realname, linedata)
  7191.                                 continue;
  7192.                         }
  7193.                        
  7194.                         // Get key and value(s)
  7195.                         strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  7196.                        
  7197.                         // Trim spaces
  7198.                         trim(key)
  7199.                         trim(value)
  7200.                        
  7201.                         if (equal(key, "NAME"))
  7202.                                 ArrayPushString(g_zclass2_name, value)
  7203.                         else if (equal(key, "INFO"))
  7204.                                 ArrayPushString(g_zclass2_info, value)
  7205.                         else if (equal(key, "MODELS"))
  7206.                         {
  7207.                                 // Set models start index
  7208.                                 ArrayPushCell(g_zclass2_modelsstart, ArraySize(g_zclass2_playermodel))
  7209.                                
  7210.                                 // Parse class models
  7211.                                 while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7212.                                 {
  7213.                                         // Trim spaces
  7214.                                         trim(key)
  7215.                                         trim(value)
  7216.                                        
  7217.                                         // Add to class models array
  7218.                                         ArrayPushString(g_zclass2_playermodel, key)
  7219.                                         ArrayPushCell(g_zclass2_modelindex, -1)
  7220.                                 }
  7221.                                
  7222.                                 // Set models end index
  7223.                                 ArrayPushCell(g_zclass2_modelsend, ArraySize(g_zclass2_playermodel))
  7224.                         }
  7225.                         else if (equal(key, "CLAWMODEL"))
  7226.                                 ArrayPushString(g_zclass2_clawmodel, value)
  7227.                         else if (equal(key, "HEALTH"))
  7228.                                 ArrayPushCell(g_zclass2_hp, str_to_num(value))
  7229.                         else if (equal(key, "SPEED"))
  7230.                                 ArrayPushCell(g_zclass2_spd, str_to_num(value))
  7231.                         else if (equal(key, "GRAVITY"))
  7232.                                 ArrayPushCell(g_zclass2_grav, str_to_float(value))
  7233.                         else if (equal(key, "KNOCKBACK"))
  7234.                                 ArrayPushCell(g_zclass2_kb, str_to_float(value))
  7235.                 }
  7236.                 if (file) fclose(file)
  7237.         }
  7238.        
  7239.         // Build extra items file path
  7240.         get_configsdir(path, charsmax(path))
  7241.         format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
  7242.        
  7243.         // Parse if present
  7244.         if (file_exists(path))
  7245.         {
  7246.                 // Open extra items file for reading
  7247.                 file = fopen(path, "rt")
  7248.                
  7249.                 while (file && !feof(file))
  7250.                 {
  7251.                         // Read one line at a time
  7252.                         fgets(file, linedata, charsmax(linedata))
  7253.                        
  7254.                         // Replace newlines with a null character to prevent headaches
  7255.                         replace(linedata, charsmax(linedata), "^n", "")
  7256.                        
  7257.                         // Blank line or comment
  7258.                         if (!linedata[0] || linedata[0] == ';') continue;
  7259.                        
  7260.                         // New item starting
  7261.                         if (linedata[0] == '[')
  7262.                         {
  7263.                                 // Remove first and last characters (braces)
  7264.                                 linedata[strlen(linedata) - 1] = 0
  7265.                                 copy(linedata, charsmax(linedata), linedata[1])
  7266.                                
  7267.                                 // Store its real name for future reference
  7268.                                 ArrayPushString(g_extraitem2_realname, linedata)
  7269.                                 continue;
  7270.                         }
  7271.                        
  7272.                         // Get key and value(s)
  7273.                         strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  7274.                        
  7275.                         // Trim spaces
  7276.                         trim(key)
  7277.                         trim(value)
  7278.                        
  7279.                         if (equal(key, "NAME"))
  7280.                                 ArrayPushString(g_extraitem2_name, value)
  7281.                         else if (equal(key, "COST"))
  7282.                                 ArrayPushCell(g_extraitem2_cost, str_to_num(value))
  7283.                         else if (equal(key, "TEAMS"))
  7284.                         {
  7285.                                 // Clear teams bitsum
  7286.                                 teams = 0
  7287.                                
  7288.                                 // Parse teams
  7289.                                 while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7290.                                 {
  7291.                                         // Trim spaces
  7292.                                         trim(key)
  7293.                                         trim(value)
  7294.                                        
  7295.                                         if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_ZOMBIE]))
  7296.                                                 teams |= ZP_TEAM_ZOMBIE
  7297.                                         else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_HUMAN]))
  7298.                                                 teams |= ZP_TEAM_HUMAN
  7299.                                         else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_NEMESIS]))
  7300.                                                 teams |= ZP_TEAM_NEMESIS
  7301.                                         else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_SURVIVOR]))
  7302.                                                 teams |= ZP_TEAM_SURVIVOR
  7303.                                 }
  7304.                                
  7305.                                 // Add to teams array
  7306.                                 ArrayPushCell(g_extraitem2_team, teams)
  7307.                         }
  7308.                 }
  7309.                 if (file) fclose(file)
  7310.         }
  7311. }
  7312.  
  7313. save_customization()
  7314. {
  7315.         new i, k, buffer[512]
  7316.        
  7317.         // Build zombie classes file path
  7318.         new path[64]
  7319.         get_configsdir(path, charsmax(path))
  7320.         format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
  7321.        
  7322.         // Open zombie classes file for appending data
  7323.         new file = fopen(path, "at"), size = ArraySize(g_zclass_name)
  7324.        
  7325.         // Add any new zombie classes data at the end if needed
  7326.         for (i = 0; i < size; i++)
  7327.         {
  7328.                 if (ArrayGetCell(g_zclass_new, i))
  7329.                 {
  7330.                         // Add real name
  7331.                         ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
  7332.                         format(buffer, charsmax(buffer), "^n[%s]", buffer)
  7333.                         fputs(file, buffer)
  7334.                        
  7335.                         // Add caption
  7336.                         ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
  7337.                         format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
  7338.                         fputs(file, buffer)
  7339.                        
  7340.                         // Add info
  7341.                         ArrayGetString(g_zclass_info, i, buffer, charsmax(buffer))
  7342.                         format(buffer, charsmax(buffer), "^nINFO = %s", buffer)
  7343.                         fputs(file, buffer)
  7344.                        
  7345.                         // Add models
  7346.                         for (k = ArrayGetCell(g_zclass_modelsstart, i); k < ArrayGetCell(g_zclass_modelsend, i); k++)
  7347.                         {
  7348.                                 if (k == ArrayGetCell(g_zclass_modelsstart, i))
  7349.                                 {
  7350.                                         // First model, overwrite buffer
  7351.                                         ArrayGetString(g_zclass_playermodel, k, buffer, charsmax(buffer))
  7352.                                 }
  7353.                                 else
  7354.                                 {
  7355.                                         // Successive models, append to buffer
  7356.                                         ArrayGetString(g_zclass_playermodel, k, path, charsmax(path))
  7357.                                         format(buffer, charsmax(buffer), "%s , %s", buffer, path)
  7358.                                 }
  7359.                         }
  7360.                         format(buffer, charsmax(buffer), "^nMODELS = %s", buffer)
  7361.                         fputs(file, buffer)
  7362.                        
  7363.                         // Add clawmodel
  7364.                         ArrayGetString(g_zclass_clawmodel, i, buffer, charsmax(buffer))
  7365.                         format(buffer, charsmax(buffer), "^nCLAWMODEL = %s", buffer)
  7366.                         fputs(file, buffer)
  7367.                        
  7368.                         // Add health
  7369.                         formatex(buffer, charsmax(buffer), "^nHEALTH = %d", ArrayGetCell(g_zclass_hp, i))
  7370.                         fputs(file, buffer)
  7371.                        
  7372.                         // Add speed
  7373.                         formatex(buffer, charsmax(buffer), "^nSPEED = %d", ArrayGetCell(g_zclass_spd, i))
  7374.                         fputs(file, buffer)
  7375.                        
  7376.                         // Add gravity
  7377.                         formatex(buffer, charsmax(buffer), "^nGRAVITY = %.2f", Float:ArrayGetCell(g_zclass_grav, i))
  7378.                         fputs(file, buffer)
  7379.                        
  7380.                         // Add knockback
  7381.                         formatex(buffer, charsmax(buffer), "^nKNOCKBACK = %.2f^n", Float:ArrayGetCell(g_zclass_kb, i))
  7382.                         fputs(file, buffer)
  7383.                 }
  7384.         }
  7385.         fclose(file)
  7386.        
  7387.         // Build extra items file path
  7388.         get_configsdir(path, charsmax(path))
  7389.         format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
  7390.        
  7391.         // Open extra items file for appending data
  7392.         file = fopen(path, "at")
  7393.         size = ArraySize(g_extraitem_name)
  7394.        
  7395.         // Add any new extra items data at the end if needed
  7396.         for (i = EXTRAS_CUSTOM_STARTID; i < size; i++)
  7397.         {
  7398.                 if (ArrayGetCell(g_extraitem_new, i))
  7399.                 {
  7400.                         // Add real name
  7401.                         ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
  7402.                         format(buffer, charsmax(buffer), "^n[%s]", buffer)
  7403.                         fputs(file, buffer)
  7404.                        
  7405.                         // Add caption
  7406.                         ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
  7407.                         format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
  7408.                         fputs(file, buffer)
  7409.                        
  7410.                         // Add cost
  7411.                         formatex(buffer, charsmax(buffer), "^nCOST = %d", ArrayGetCell(g_extraitem_cost, i))
  7412.                         fputs(file, buffer)
  7413.                        
  7414.                         // Add team
  7415.                         formatex(buffer, charsmax(buffer), "^nTEAMS = %s^n", ZP_TEAM_NAMES[ArrayGetCell(g_extraitem_team, i)])
  7416.                         fputs(file, buffer)
  7417.                 }
  7418.         }
  7419.         fclose(file)
  7420.        
  7421.         // Free arrays containing class/item overrides
  7422.         ArrayDestroy(g_zclass2_realname)
  7423.         ArrayDestroy(g_zclass2_name)
  7424.         ArrayDestroy(g_zclass2_info)
  7425.         ArrayDestroy(g_zclass2_modelsstart)
  7426.         ArrayDestroy(g_zclass2_modelsend)
  7427.         ArrayDestroy(g_zclass2_playermodel)
  7428.         ArrayDestroy(g_zclass2_modelindex)
  7429.         ArrayDestroy(g_zclass2_clawmodel)
  7430.         ArrayDestroy(g_zclass2_hp)
  7431.         ArrayDestroy(g_zclass2_spd)
  7432.         ArrayDestroy(g_zclass2_grav)
  7433.         ArrayDestroy(g_zclass2_kb)
  7434.         ArrayDestroy(g_zclass_new)
  7435.         ArrayDestroy(g_extraitem2_realname)
  7436.         ArrayDestroy(g_extraitem2_name)
  7437.         ArrayDestroy(g_extraitem2_cost)
  7438.         ArrayDestroy(g_extraitem2_team)
  7439.         ArrayDestroy(g_extraitem_new)
  7440. }
  7441.  
  7442. // Register Ham Forwards for CZ bots
  7443. public register_ham_czbots(id)
  7444. {
  7445.         // Make sure it's a CZ bot and it's still connected
  7446.         if (g_hamczbots || !g_isconnected[id] || !get_pcvar_num(cvar_botquota))
  7447.                 return;
  7448.        
  7449.         RegisterHamFromEntity(Ham_Spawn, id, "fw_PlayerSpawn_Post", 1)
  7450.         RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled")
  7451.         RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled_Post", 1)
  7452.         RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage")
  7453.         RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage_Post", 1)
  7454.         RegisterHamFromEntity(Ham_TraceAttack, id, "fw_TraceAttack")
  7455.        
  7456.         // Ham forwards for CZ bots succesfully registered
  7457.         g_hamczbots = true
  7458.        
  7459.         // If the bot has already spawned, call the forward manually for him
  7460.         if (is_user_alive(id)) fw_PlayerSpawn_Post(id)
  7461. }
  7462.  
  7463. // Disable minmodels task
  7464. public disable_minmodels(id)
  7465. {
  7466.         if (!g_isconnected[id]) return;
  7467.         client_cmd(id, "cl_minmodels 0")
  7468. }
  7469.  
  7470. // Bots automatically buy extra items
  7471. public bot_buy_extras(taskid)
  7472. {
  7473.         // Nemesis or Survivor bots have nothing to buy by default
  7474.         if (!g_isalive[ID_SPAWN] || g_survivor[ID_SPAWN] || g_nemesis[ID_SPAWN])
  7475.                 return;
  7476.        
  7477.         if (!g_zombie[ID_SPAWN]) // human bots
  7478.         {
  7479.                 // Attempt to buy Night Vision
  7480.                 buy_extra_item(ID_SPAWN, EXTRA_NVISION)
  7481.                
  7482.                 // Attempt to buy a weapon
  7483.                 buy_extra_item(ID_SPAWN, random_num(EXTRA_WEAPONS_STARTID, EXTRAS_CUSTOM_STARTID-1))
  7484.         }
  7485.         else // zombie bots
  7486.         {
  7487.                 // Attempt to buy an Antidote
  7488.                 buy_extra_item(ID_SPAWN, EXTRA_ANTIDOTE)
  7489.         }
  7490. }
  7491.  
  7492. // Refill BP Ammo Task
  7493. public refill_bpammo(const args[], id)
  7494. {
  7495.         // Player died or turned into a zombie
  7496.         if (!g_isalive[id] || g_zombie[id])
  7497.                 return;
  7498.        
  7499.         set_msg_block(g_msgAmmoPickup, BLOCK_ONCE)
  7500.         ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[REFILL_WEAPONID], AMMOTYPE[REFILL_WEAPONID], MAXBPAMMO[REFILL_WEAPONID])
  7501. }
  7502.  
  7503. // Balance Teams Task
  7504. balance_teams()
  7505. {
  7506.         // Get amount of users playing
  7507.         static iPlayersnum
  7508.         iPlayersnum = fnGetPlaying()
  7509.        
  7510.         // No players, don't bother
  7511.         if (iPlayersnum < 1) return;
  7512.        
  7513.         // Split players evenly
  7514.         static iTerrors, iMaxTerrors, id, team[33]
  7515.         iMaxTerrors = iPlayersnum/2
  7516.         iTerrors = 0
  7517.        
  7518.         // First, set everyone to CT
  7519.         for (id = 1; id <= g_maxplayers; id++)
  7520.         {
  7521.                 // Skip if not connected
  7522.                 if (!g_isconnected[id])
  7523.                         continue;
  7524.                
  7525.                 team[id] = fm_cs_get_user_team(id)
  7526.                
  7527.                 // Skip if not playing
  7528.                 if (team[id] == FM_CS_TEAM_SPECTATOR || team[id] == FM_CS_TEAM_UNASSIGNED)
  7529.                         continue;
  7530.                
  7531.                 // Set team
  7532.                 remove_task(id+TASK_TEAM)
  7533.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  7534.                 team[id] = FM_CS_TEAM_CT
  7535.         }
  7536.        
  7537.         // Then randomly set half of the players to Terrorists
  7538.         while (iTerrors < iMaxTerrors)
  7539.         {
  7540.                 // Keep looping through all players
  7541.                 if (++id > g_maxplayers) id = 1
  7542.                
  7543.                 // Skip if not connected
  7544.                 if (!g_isconnected[id])
  7545.                         continue;
  7546.                
  7547.                 // Skip if not playing or already a Terrorist
  7548.                 if (team[id] != FM_CS_TEAM_CT)
  7549.                         continue;
  7550.                
  7551.                 // Random chance
  7552.                 if (random_num(0, 1))
  7553.                 {
  7554.                         fm_cs_set_user_team(id, FM_CS_TEAM_T)
  7555.                         team[id] = FM_CS_TEAM_T
  7556.                         iTerrors++
  7557.                 }
  7558.         }
  7559. }
  7560.  
  7561. // Welcome Message Task
  7562. public welcome_msg()
  7563. {
  7564.         // Show mod info
  7565.         zp_colored_print(0, "^x01**** ^x04%s^x01 ****", g_modname)
  7566.         zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "NOTICE_INFO1")
  7567.         if (!get_pcvar_num(cvar_infammo)) zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "NOTICE_INFO2")
  7568.        
  7569.         // Show T-virus HUD notice
  7570.         set_hudmessage(0, 125, 200, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  7571.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_VIRUS_FREE")
  7572. }
  7573.  
  7574. // Respawn Player Task
  7575. public respawn_player_task(taskid)
  7576. {
  7577.         // Get player's team
  7578.         static team
  7579.         team = fm_cs_get_user_team(ID_SPAWN)
  7580.        
  7581.         // Respawn player automatically if allowed on current round
  7582.         if (!g_endround && team != FM_CS_TEAM_SPECTATOR && team != FM_CS_TEAM_UNASSIGNED && !g_isalive[ID_SPAWN] && (!g_survround || get_pcvar_num(cvar_allowrespawnsurv)) && (!g_swarmround || get_pcvar_num(cvar_allowrespawnswarm)) && (!g_nemround || get_pcvar_num(cvar_allowrespawnnem)) && (!g_plagueround || get_pcvar_num(cvar_allowrespawnplague)))
  7583.         {
  7584.                 // Infection rounds = none of the above
  7585.                 if (!get_pcvar_num(cvar_allowrespawninfection) && !g_survround && !g_nemround && !g_swarmround && !g_plagueround)
  7586.                         return;
  7587.                
  7588.                 // Override respawn as zombie setting on nemesis and survivor rounds
  7589.                 if (g_survround) g_respawn_as_zombie[ID_SPAWN] = true
  7590.                 else if (g_nemround) g_respawn_as_zombie[ID_SPAWN] = false
  7591.                
  7592.                 respawn_player_manually(ID_SPAWN)
  7593.         }
  7594. }
  7595.  
  7596. // Respawn Player Manually (called after respawn checks are done)
  7597. respawn_player_manually(id)
  7598. {
  7599.         // Set proper team before respawning, so that the TeamInfo message that's sent doesn't confuse PODBots
  7600.         if (g_respawn_as_zombie[id])
  7601.                 fm_cs_set_user_team(id, FM_CS_TEAM_T)
  7602.         else
  7603.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  7604.        
  7605.         // Respawning a player has never been so easy
  7606.         ExecuteHamB(Ham_CS_RoundRespawn, id)
  7607. }
  7608.  
  7609. // Check Round Task -check that we still have both zombies and humans on a round-
  7610. check_round(leaving_player)
  7611. {
  7612.         // Round ended or make_a_zombie task still active
  7613.         if (g_endround || task_exists(TASK_MAKEZOMBIE))
  7614.                 return;
  7615.        
  7616.         // Get alive players count
  7617.         static iPlayersnum, id
  7618.         iPlayersnum = fnGetAlive()
  7619.        
  7620.         // Last alive player, don't bother
  7621.         if (iPlayersnum < 2)
  7622.                 return;
  7623.        
  7624.         // Last zombie disconnecting
  7625.         if (g_zombie[leaving_player] && fnGetZombies() == 1)
  7626.         {
  7627.                 // Only one CT left, don't bother
  7628.                 if (fnGetHumans() == 1 && fnGetCTs() == 1)
  7629.                         return;
  7630.                
  7631.                 // Pick a random one to take his place
  7632.                 while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
  7633.                
  7634.                 // Show last zombie left notice
  7635.                 zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_ZOMBIE_LEFT", g_playername[id])
  7636.                
  7637.                 // Set player leaving flag
  7638.                 g_lastplayerleaving = true
  7639.                
  7640.                 // Turn into a Nemesis or just a zombie?
  7641.                 if (g_nemesis[leaving_player])
  7642.                         zombieme(id, 0, 1, 0, 0)
  7643.                 else
  7644.                         zombieme(id, 0, 0, 0, 0)
  7645.                
  7646.                 // Remove player leaving flag
  7647.                 g_lastplayerleaving = false
  7648.                
  7649.                 // If Nemesis, set chosen player's health to that of the one who's leaving
  7650.                 if (get_pcvar_num(cvar_keephealthondisconnect) && g_nemesis[leaving_player])
  7651.                         fm_set_user_health(id, pev(leaving_player, pev_health))
  7652.         }
  7653.        
  7654.         // Last human disconnecting
  7655.         else if (!g_zombie[leaving_player] && fnGetHumans() == 1)
  7656.         {
  7657.                 // Only one T left, don't bother
  7658.                 if (fnGetZombies() == 1 && fnGetTs() == 1)
  7659.                         return;
  7660.                
  7661.                 // Pick a random one to take his place
  7662.                 while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
  7663.                
  7664.                 // Show last human left notice
  7665.                 zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_HUMAN_LEFT", g_playername[id])
  7666.                
  7667.                 // Set player leaving flag
  7668.                 g_lastplayerleaving = true
  7669.                
  7670.                 // Turn into a Survivor or just a human?
  7671.                 if (g_survivor[leaving_player])
  7672.                         humanme(id, 1, 0)
  7673.                 else
  7674.                         humanme(id, 0, 0)
  7675.                
  7676.                 // Remove player leaving flag
  7677.                 g_lastplayerleaving = false
  7678.                
  7679.                 // If Survivor, set chosen player's health to that of the one who's leaving
  7680.                 if (get_pcvar_num(cvar_keephealthondisconnect) && g_survivor[leaving_player])
  7681.                         fm_set_user_health(id, pev(leaving_player, pev_health))
  7682.         }
  7683. }
  7684.  
  7685. // Lighting Effects Task
  7686. public lighting_effects()
  7687. {
  7688.         // Cache some CVAR values at every 5 secs
  7689.         cache_cvars()
  7690.        
  7691.         // Get lighting style
  7692.         static lighting[2]
  7693.         get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
  7694.         strtolower(lighting)
  7695.        
  7696.         // Lighting disabled? ["0"]
  7697.         if (lighting[0] == '0')
  7698.                 return;
  7699.        
  7700.         // Darkest light settings?
  7701.         if (lighting[0] >= 'a' && lighting[0] <= 'd')
  7702.         {
  7703.                 static thunderclap_in_progress, Float:thunder
  7704.                 thunderclap_in_progress = task_exists(TASK_THUNDER)
  7705.                 thunder = get_pcvar_float(cvar_thunder)
  7706.                
  7707.                 // Set thunderclap tasks if not existant
  7708.                 if (thunder > 0.0 && !task_exists(TASK_THUNDER_PRE) && !thunderclap_in_progress)
  7709.                 {
  7710.                         g_lights_i = 0
  7711.                         ArrayGetString(lights_thunder, random_num(0, ArraySize(lights_thunder) - 1), g_lights_cycle, charsmax(g_lights_cycle))
  7712.                         g_lights_cycle_len = strlen(g_lights_cycle)
  7713.                         set_task(thunder, "thunderclap", TASK_THUNDER_PRE)
  7714.                 }
  7715.                
  7716.                 // Set lighting only when no thunderclaps are going on
  7717.                 if (!thunderclap_in_progress) engfunc(EngFunc_LightStyle, 0, lighting)
  7718.         }
  7719.         else
  7720.         {
  7721.                 // Remove thunderclap tasks
  7722.                 remove_task(TASK_THUNDER_PRE)
  7723.                 remove_task(TASK_THUNDER)
  7724.                
  7725.                 // Set lighting
  7726.                 engfunc(EngFunc_LightStyle, 0, lighting)
  7727.         }
  7728. }
  7729.  
  7730. // Thunderclap task
  7731. public thunderclap()
  7732. {
  7733.         // Play thunder sound
  7734.         if (g_lights_i == 0)
  7735.         {
  7736.                 static sound[64]
  7737.                 ArrayGetString(sound_thunder, random_num(0, ArraySize(sound_thunder) - 1), sound, charsmax(sound))
  7738.                 PlaySound(sound)
  7739.         }
  7740.        
  7741.         // Set lighting
  7742.         static light[2]
  7743.         light[0] = g_lights_cycle[g_lights_i]
  7744.         engfunc(EngFunc_LightStyle, 0, light)
  7745.        
  7746.         g_lights_i++
  7747.        
  7748.         // Lighting cycle end?
  7749.         if (g_lights_i >= g_lights_cycle_len)
  7750.         {
  7751.                 remove_task(TASK_THUNDER)
  7752.                 lighting_effects()
  7753.         }
  7754.         // Lighting cycle start?
  7755.         else if (!task_exists(TASK_THUNDER))
  7756.                 set_task(0.1, "thunderclap", TASK_THUNDER, _, _, "b")
  7757. }
  7758.  
  7759. // Ambience Sound Effects Task
  7760. public ambience_sound_effects(taskid)
  7761. {
  7762.         // Play a random sound depending on the round
  7763.         static sound[64], iRand, duration, ismp3
  7764.        
  7765.         if (g_nemround) // Nemesis Mode
  7766.         {
  7767.                 iRand = random_num(0, ArraySize(sound_ambience2) - 1)
  7768.                 ArrayGetString(sound_ambience2, iRand, sound, charsmax(sound))
  7769.                 duration = ArrayGetCell(sound_ambience2_duration, iRand)
  7770.                 ismp3 = ArrayGetCell(sound_ambience2_ismp3, iRand)
  7771.         }
  7772.         else if (g_survround) // Survivor Mode
  7773.         {
  7774.                 iRand = random_num(0, ArraySize(sound_ambience3) - 1)
  7775.                 ArrayGetString(sound_ambience3, iRand, sound, charsmax(sound))
  7776.                 duration = ArrayGetCell(sound_ambience3_duration, iRand)
  7777.                 ismp3 = ArrayGetCell(sound_ambience3_ismp3, iRand)
  7778.         }
  7779.         else if (g_swarmround) // Swarm Mode
  7780.         {
  7781.                 iRand = random_num(0, ArraySize(sound_ambience4) - 1)
  7782.                 ArrayGetString(sound_ambience4, iRand, sound, charsmax(sound))
  7783.                 duration = ArrayGetCell(sound_ambience4_duration, iRand)
  7784.                 ismp3 = ArrayGetCell(sound_ambience4_ismp3, iRand)
  7785.         }
  7786.         else if (g_plagueround) // Plague Mode
  7787.         {
  7788.                 iRand = random_num(0, ArraySize(sound_ambience5) - 1)
  7789.                 ArrayGetString(sound_ambience5, iRand, sound, charsmax(sound))
  7790.                 duration = ArrayGetCell(sound_ambience5_duration, iRand)
  7791.                 ismp3 = ArrayGetCell(sound_ambience5_ismp3, iRand)
  7792.         }
  7793.         else // Infection Mode
  7794.         {
  7795.                 iRand = random_num(0, ArraySize(sound_ambience1) - 1)
  7796.                 ArrayGetString(sound_ambience1, iRand, sound, charsmax(sound))
  7797.                 duration = ArrayGetCell(sound_ambience1_duration, iRand)
  7798.                 ismp3 = ArrayGetCell(sound_ambience1_ismp3, iRand)
  7799.         }