OciXCrom

Untitled

Mar 20th, 2017
295
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 355.51 KB | None | 0 0
  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 Fix5a"
  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 remembering menu pages
  493. #define MENU_PAGE_ZCLASS g_menu_data[id][5]
  494. #define MENU_PAGE_EXTRAS g_menu_data[id][6]
  495. #define MENU_PAGE_PLAYERS g_menu_data[id][7]
  496.  
  497. // For extra items menu handlers
  498. #define EXTRAS_CUSTOM_STARTID (EXTRA_WEAPONS_STARTID + ArraySize(g_extraweapon_names))
  499.  
  500. // Menu selections
  501. const MENU_KEY_AUTOSELECT = 7
  502. const MENU_KEY_BACK = 7
  503. const MENU_KEY_NEXT = 8
  504. const MENU_KEY_EXIT = 9
  505.  
  506. // Hard coded extra items
  507. enum
  508. {
  509.     EXTRA_NVISION = 0,
  510.     EXTRA_ANTIDOTE,
  511.     EXTRA_MADNESS,
  512.     EXTRA_INFBOMB,
  513.     EXTRA_WEAPONS_STARTID
  514. }
  515.  
  516. // Game modes
  517. enum
  518. {
  519.     MODE_NONE = 0,
  520.     MODE_INFECTION,
  521.     MODE_NEMESIS,
  522.     MODE_SURVIVOR,
  523.     MODE_SWARM,
  524.     MODE_MULTI,
  525.     MODE_PLAGUE
  526. }
  527.  
  528. // ZP Teams
  529. const ZP_TEAM_NO_ONE = 0
  530. const ZP_TEAM_ANY = 0
  531. const ZP_TEAM_ZOMBIE = (1<<0)
  532. const ZP_TEAM_HUMAN = (1<<1)
  533. const ZP_TEAM_NEMESIS = (1<<2)
  534. const ZP_TEAM_SURVIVOR = (1<<3)
  535. new const ZP_TEAM_NAMES[][] = { "ZOMBIE , HUMAN", "ZOMBIE", "HUMAN", "ZOMBIE , HUMAN", "NEMESIS",
  536.             "ZOMBIE , NEMESIS", "HUMAN , NEMESIS", "ZOMBIE , HUMAN , NEMESIS",
  537.             "SURVIVOR", "ZOMBIE , SURVIVOR", "HUMAN , SURVIVOR", "ZOMBIE , HUMAN , SURVIVOR",
  538.             "NEMESIS , SURVIVOR", "ZOMBIE , NEMESIS , SURVIVOR", "HUMAN, NEMESIS, SURVIVOR",
  539.             "ZOMBIE , HUMAN , NEMESIS , SURVIVOR" }
  540.  
  541. // Zombie classes
  542. const ZCLASS_NONE = -1
  543.  
  544. // HUD messages
  545. const Float:HUD_EVENT_X = -1.0
  546. const Float:HUD_EVENT_Y = 0.17
  547. const Float:HUD_INFECT_X = 0.05
  548. const Float:HUD_INFECT_Y = 0.45
  549. const Float:HUD_SPECT_X = 0.6
  550. const Float:HUD_SPECT_Y = 0.8
  551. const Float:HUD_STATS_X = 0.02
  552. const Float:HUD_STATS_Y = 0.9
  553.  
  554. // Hack to be able to use Ham_Player_ResetMaxSpeed (by joaquimandrade)
  555. new Ham:Ham_Player_ResetMaxSpeed = Ham_Item_PreFrame
  556.  
  557. // CS Player PData Offsets (win32)
  558. const PDATA_SAFE = 2
  559. const OFFSET_PAINSHOCK = 108 // ConnorMcLeod
  560. const OFFSET_CSTEAMS = 114
  561. const OFFSET_CSMONEY = 115
  562. const OFFSET_CSMENUCODE = 205
  563. const OFFSET_FLASHLIGHT_BATTERY = 244
  564. const OFFSET_CSDEATHS = 444
  565. const OFFSET_MODELINDEX = 491 // Orangutanz
  566.  
  567. // CS Player CBase Offsets (win32)
  568. const OFFSET_ACTIVE_ITEM = 373
  569.  
  570. // CS Weapon CBase Offsets (win32)
  571. const OFFSET_WEAPONOWNER = 41
  572.  
  573. // Linux diff's
  574. const OFFSET_LINUX = 5 // offsets 5 higher in Linux builds
  575. const OFFSET_LINUX_WEAPONS = 4 // weapon offsets are only 4 steps higher on Linux
  576.  
  577. // CS Teams
  578. enum
  579. {
  580.     FM_CS_TEAM_UNASSIGNED = 0,
  581.     FM_CS_TEAM_T,
  582.     FM_CS_TEAM_CT,
  583.     FM_CS_TEAM_SPECTATOR
  584. }
  585. new const CS_TEAM_NAMES[][] = { "UNASSIGNED", "TERRORIST", "CT", "SPECTATOR" }
  586.  
  587. // Some constants
  588. const HIDE_MONEY = (1<<5)
  589. const UNIT_SECOND = (1<<12)
  590. const DMG_HEGRENADE = (1<<24)
  591. const IMPULSE_FLASHLIGHT = 100
  592. const USE_USING = 2
  593. const USE_STOPPED = 0
  594. const STEPTIME_SILENT = 999
  595. const BREAK_GLASS = 0x01
  596. const FFADE_IN = 0x0000
  597. const FFADE_STAYOUT = 0x0004
  598. const PEV_SPEC_TARGET = pev_iuser2
  599.  
  600. // Max BP ammo for weapons
  601. new const MAXBPAMMO[] = { -1, 52, -1, 90, 1, 32, 1, 100, 90, 1, 120, 100, 100, 90, 90, 90, 100, 120,
  602.             30, 120, 200, 32, 90, 120, 90, 2, 35, 90, 90, -1, 100 }
  603.  
  604. // Max Clip for weapons
  605. new const MAXCLIP[] = { -1, 13, -1, 10, -1, 7, -1, 30, 30, -1, 30, 20, 25, 30, 35, 25, 12, 20,
  606.             10, 30, 100, 8, 30, 30, 20, -1, 7, 30, 30, -1, 50 }
  607.  
  608. // Amount of ammo to give when buying additional clips for weapons
  609. new const BUYAMMO[] = { -1, 13, -1, 30, -1, 8, -1, 12, 30, -1, 30, 50, 12, 30, 30, 30, 12, 30,
  610.             10, 30, 30, 8, 30, 30, 30, -1, 7, 30, 30, -1, 50 }
  611.  
  612. // Ammo IDs for weapons
  613. new const AMMOID[] = { -1, 9, -1, 2, 12, 5, 14, 6, 4, 13, 10, 7, 6, 4, 4, 4, 6, 10,
  614.             1, 10, 3, 5, 4, 10, 2, 11, 8, 4, 2, -1, 7 }
  615.  
  616. // Ammo Type Names for weapons
  617. new const AMMOTYPE[][] = { "", "357sig", "", "762nato", "", "buckshot", "", "45acp", "556nato", "", "9mm", "57mm", "45acp",
  618.             "556nato", "556nato", "556nato", "45acp", "9mm", "338magnum", "9mm", "556natobox", "buckshot",
  619.             "556nato", "9mm", "762nato", "", "50ae", "556nato", "762nato", "", "57mm" }
  620.  
  621. // Weapon IDs for ammo types
  622. new const AMMOWEAPON[] = { 0, CSW_AWP, CSW_SCOUT, CSW_M249, CSW_AUG, CSW_XM1014, CSW_MAC10, CSW_FIVESEVEN, CSW_DEAGLE,
  623.             CSW_P228, CSW_ELITE, CSW_FLASHBANG, CSW_HEGRENADE, CSW_SMOKEGRENADE, CSW_C4 }
  624.  
  625. // Primary and Secondary Weapon Names
  626. new const WEAPONNAMES[][] = { "", "P228 Compact", "", "Schmidt Scout", "", "XM1014 M4", "", "Ingram MAC-10", "Steyr AUG A1",
  627.             "", "Dual Elite Berettas", "FiveseveN", "UMP 45", "SG-550 Auto-Sniper", "IMI Galil", "Famas",
  628.             "USP .45 ACP Tactical", "Glock 18C", "AWP Magnum Sniper", "MP5 Navy", "M249 Para Machinegun",
  629.             "M3 Super 90", "M4A1 Carbine", "Schmidt TMP", "G3SG1 Auto-Sniper", "", "Desert Eagle .50 AE",
  630.             "SG-552 Commando", "AK-47 Kalashnikov", "", "ES P90" }
  631.  
  632. // Weapon entity names
  633. new const WEAPONENTNAMES[][] = { "", "weapon_p228", "", "weapon_scout", "weapon_hegrenade", "weapon_xm1014", "weapon_c4", "weapon_mac10",
  634.             "weapon_aug", "weapon_smokegrenade", "weapon_elite", "weapon_fiveseven", "weapon_ump45", "weapon_sg550",
  635.             "weapon_galil", "weapon_famas", "weapon_usp", "weapon_glock18", "weapon_awp", "weapon_mp5navy", "weapon_m249",
  636.             "weapon_m3", "weapon_m4a1", "weapon_tmp", "weapon_g3sg1", "weapon_flashbang", "weapon_deagle", "weapon_sg552",
  637.             "weapon_ak47", "weapon_knife", "weapon_p90" }
  638.  
  639. // CS sounds
  640. new const sound_flashlight[] = "items/flashlight1.wav"
  641. new const sound_buyammo[] = "items/9mmclip1.wav"
  642. new const sound_armorhit[] = "player/bhit_helmet-1.wav"
  643.  
  644. // Explosion radius for custom grenades
  645. const Float:NADE_EXPLOSION_RADIUS = 240.0
  646.  
  647. // HACK: pev_ field used to store additional ammo on weapons
  648. const PEV_ADDITIONAL_AMMO = pev_iuser1
  649.  
  650. // HACK: pev_ field used to store custom nade types and their values
  651. const PEV_NADE_TYPE = pev_flTimeStepSound
  652. const NADE_TYPE_INFECTION = 1111
  653. const NADE_TYPE_NAPALM = 2222
  654. const NADE_TYPE_FROST = 3333
  655. const NADE_TYPE_FLARE = 4444
  656. const PEV_FLARE_COLOR = pev_punchangle
  657. const PEV_FLARE_DURATION = pev_flSwimTime
  658.  
  659. // Weapon bitsums
  660. 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)
  661. const SECONDARY_WEAPONS_BIT_SUM = (1<<CSW_P228)|(1<<CSW_ELITE)|(1<<CSW_FIVESEVEN)|(1<<CSW_USP)|(1<<CSW_GLOCK18)|(1<<CSW_DEAGLE)
  662.  
  663. // Allowed weapons for zombies (added grenades/bomb for sub-plugin support, since they shouldn't be getting them anyway)
  664. const ZOMBIE_ALLOWED_WEAPONS_BITSUM = (1<<CSW_KNIFE)|(1<<CSW_HEGRENADE)|(1<<CSW_FLASHBANG)|(1<<CSW_SMOKEGRENADE)|(1<<CSW_C4)
  665.  
  666. // Classnames for separate model entities
  667. new const MODEL_ENT_CLASSNAME[] = "player_model"
  668. new const WEAPON_ENT_CLASSNAME[] = "weapon_model"
  669.  
  670. // Menu keys
  671. 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
  672.  
  673. // Ambience Sounds
  674. enum
  675. {
  676.     AMBIENCE_SOUNDS_INFECTION = 0,
  677.     AMBIENCE_SOUNDS_NEMESIS,
  678.     AMBIENCE_SOUNDS_SURVIVOR,
  679.     AMBIENCE_SOUNDS_SWARM,
  680.     AMBIENCE_SOUNDS_PLAGUE,
  681.     MAX_AMBIENCE_SOUNDS
  682. }
  683.  
  684. // Admin menu actions
  685. enum
  686. {
  687.     ACTION_ZOMBIEFY_HUMANIZE = 0,
  688.     ACTION_MAKE_NEMESIS,
  689.     ACTION_MAKE_SURVIVOR,
  690.     ACTION_RESPAWN_PLAYER,
  691.     ACTION_MODE_SWARM,
  692.     ACTION_MODE_MULTI,
  693.     ACTION_MODE_PLAGUE
  694. }
  695.  
  696. // Custom forward return values
  697. const ZP_PLUGIN_HANDLED = 97
  698.  
  699. /*================================================================================
  700.  [Global Variables]
  701. =================================================================================*/
  702.  
  703. // Player vars
  704. new g_zombie[33] // is zombie
  705. new g_nemesis[33] // is nemesis
  706. new g_survivor[33] // is survivor
  707. new g_firstzombie[33] // is first zombie
  708. new g_lastzombie[33] // is last zombie
  709. new g_lasthuman[33] // is last human
  710. new g_frozen[33] // is frozen (can't move)
  711. new Float:g_frozen_gravity[33] // store previous gravity when frozen
  712. new g_nodamage[33] // has spawn protection/zombie madness
  713. new g_respawn_as_zombie[33] // should respawn as zombie
  714. new g_nvision[33] // has night vision
  715. new g_nvisionenabled[33] // has night vision turned on
  716. new g_zombieclass[33] // zombie class
  717. new g_zombieclassnext[33] // zombie class for next infection
  718. new g_flashlight[33] // has custom flashlight turned on
  719. new g_flashbattery[33] = { 100, ... } // custom flashlight battery
  720. new g_canbuy[33] // is allowed to buy a new weapon through the menu
  721. new g_ammopacks[33] // ammo pack count
  722. new g_damagedealt_human[33] // damage dealt as human (used to calculate ammo packs reward)
  723. new g_damagedealt_zombie[33] // damage dealt as zombie (used to calculate ammo packs reward)
  724. new Float:g_lastleaptime[33] // time leap was last used
  725. new Float:g_lastflashtime[33] // time flashlight was last toggled
  726. new g_playermodel[33][32] // current model's short name [player][model]
  727. new g_menu_data[33][8] // data for some menu handlers
  728. new g_ent_playermodel[33] // player model entity
  729. new g_ent_weaponmodel[33] // weapon model entity
  730. new g_burning_duration[33] // burning task duration
  731. new Float:g_buytime[33] // used to calculate custom buytime
  732.  
  733. // Game vars
  734. new g_pluginenabled // ZP enabled
  735. new g_newround // new round starting
  736. new g_endround // round ended
  737. new g_nemround // nemesis round
  738. new g_survround // survivor round
  739. new g_swarmround // swarm round
  740. new g_plagueround // plague round
  741. new g_modestarted // mode fully started
  742. new g_lastmode // last played mode
  743. new g_scorezombies, g_scorehumans, g_gamecommencing // team scores
  744. new g_spawnCount, g_spawnCount2 // available spawn points counter
  745. new Float:g_spawns[MAX_CSDM_SPAWNS][3], Float:g_spawns2[MAX_CSDM_SPAWNS][3] // spawn points data
  746. new g_lights_i // lightning current lights counter
  747. new g_lights_cycle[32] // current lightning cycle
  748. new g_lights_cycle_len // lightning cycle length
  749. new Float:g_models_targettime // for adding delays between Model Change messages
  750. new Float:g_teams_targettime // for adding delays between Team Change messages
  751. new g_MsgSync, g_MsgSync2 // message sync objects
  752. new g_trailSpr, g_exploSpr, g_flameSpr, g_smokeSpr, g_glassSpr // grenade sprites
  753. new g_modname[32] // for formatting the mod name
  754. new g_freezetime // whether CS's freeze time is on
  755. new g_maxplayers // max players counter
  756. new g_czero // whether we are running on a CZ server
  757. new g_hamczbots // whether ham forwards are registered for CZ bots
  758. new g_fwSpawn, g_fwPrecacheSound // spawn and precache sound forward handles
  759. new g_infbombcounter, g_antidotecounter, g_madnesscounter // to limit buying some items
  760. new g_arrays_created // to prevent stuff from being registered before initializing arrays
  761. new g_lastplayerleaving // flag for whenever a player leaves and another takes his place
  762. new g_switchingteam // flag for whenever a player's team change emessage is sent
  763. new g_buyzone_ent // custom buyzone entity
  764.  
  765. // Message IDs vars
  766. new g_msgScoreInfo, g_msgNVGToggle, g_msgScoreAttrib, g_msgAmmoPickup, g_msgScreenFade,
  767. g_msgDeathMsg, g_msgSetFOV, g_msgFlashlight, g_msgFlashBat, g_msgTeamInfo, g_msgDamage,
  768. g_msgHideWeapon, g_msgCrosshair, g_msgSayText, g_msgScreenShake, g_msgCurWeapon
  769.  
  770. // Some forward handlers
  771. new g_fwRoundStart, g_fwRoundEnd, g_fwUserInfected_pre, g_fwUserInfected_post,
  772. g_fwUserHumanized_pre, g_fwUserHumanized_post, g_fwUserInfect_attempt,
  773. g_fwUserHumanize_attempt, g_fwExtraItemSelected, g_fwUserUnfrozen,
  774. g_fwUserLastZombie, g_fwUserLastHuman, g_fwDummyResult
  775.  
  776. // Temporary Database vars (used to restore players stats in case they get disconnected)
  777. new db_name[MAX_STATS_SAVED][32] // player name
  778. new db_ammopacks[MAX_STATS_SAVED] // ammo pack count
  779. new db_zombieclass[MAX_STATS_SAVED] // zombie class
  780. new db_slot_i // additional saved slots counter (should start on maxplayers+1)
  781.  
  782. // Extra Items vars
  783. new Array:g_extraitem_name // caption
  784. new Array:g_extraitem_cost // cost
  785. new Array:g_extraitem_team // team
  786. new g_extraitem_i // loaded extra items counter
  787.  
  788. // For extra items file parsing
  789. new Array:g_extraitem2_realname, Array:g_extraitem2_name, Array:g_extraitem2_cost,
  790. Array:g_extraitem2_team, Array:g_extraitem_new
  791.  
  792. // Zombie Classes vars
  793. new Array:g_zclass_name // caption
  794. new Array:g_zclass_info // description
  795. new Array:g_zclass_modelsstart // start position in models array
  796. new Array:g_zclass_modelsend // end position in models array
  797. new Array:g_zclass_playermodel // player models array
  798. new Array:g_zclass_modelindex // model indices array
  799. new Array:g_zclass_clawmodel // claw model
  800. new Array:g_zclass_hp // health
  801. new Array:g_zclass_spd // speed
  802. new Array:g_zclass_grav // gravity
  803. new Array:g_zclass_kb // knockback
  804. new g_zclass_i // loaded zombie classes counter
  805.  
  806. // For zombie classes file parsing
  807. new Array:g_zclass2_realname, Array:g_zclass2_name, Array:g_zclass2_info,
  808. Array:g_zclass2_modelsstart, Array:g_zclass2_modelsend, Array:g_zclass2_playermodel,
  809. Array:g_zclass2_modelindex, Array:g_zclass2_clawmodel, Array:g_zclass2_hp,
  810. Array:g_zclass2_spd, Array:g_zclass2_grav, Array:g_zclass2_kb, Array:g_zclass_new
  811.  
  812. // Customization vars
  813. new g_access_flag[MAX_ACCESS_FLAGS], Array:model_nemesis, Array:model_survivor, Array:model_human,
  814. Array:model_admin_zombie, Array:model_admin_human, Array:g_modelindex_human,
  815. Array:g_modelindex_nemesis, Array:g_modelindex_survivor, g_same_models_for_all,
  816. Array:g_modelindex_admin_zombie, Array:g_modelindex_admin_human, model_vknife_human[64],
  817. model_vknife_nemesis[64], model_vweapon_survivor[64], model_grenade_infect[64],
  818. model_grenade_fire[64], model_grenade_frost[64], model_grenade_flare[64],
  819. model_vknife_admin_human[64], model_vknife_admin_zombie[64],
  820. sprite_grenade_trail[64], sprite_grenade_ring[64], sprite_grenade_fire[64],
  821. sprite_grenade_smoke[64], sprite_grenade_glass[64], Array:sound_win_zombies,
  822. Array:sound_win_humans, Array:sound_win_no_one, Array:sound_win_zombies_ismp3,
  823. Array:sound_win_humans_ismp3, Array:sound_win_no_one_ismp3, Array:zombie_infect,
  824. Array:zombie_idle, Array:zombie_pain, Array:nemesis_pain, Array:zombie_die, Array:zombie_fall,
  825. Array:zombie_miss_wall, Array:zombie_hit_normal, Array:zombie_hit_stab, g_ambience_rain,
  826. Array:zombie_idle_last, Array:zombie_madness, Array:sound_nemesis, Array:sound_survivor,
  827. Array:sound_swarm, Array:sound_multi, Array:sound_plague, Array:grenade_infect,
  828. Array:grenade_infect_player, Array:grenade_fire, Array:grenade_fire_player,
  829. Array:grenade_frost, Array:grenade_frost_player, Array:grenade_frost_break,
  830. Array:grenade_flare, Array:sound_antidote, Array:sound_thunder, g_ambience_sounds[MAX_AMBIENCE_SOUNDS],
  831. Array:sound_ambience1, Array:sound_ambience2, Array:sound_ambience3, Array:sound_ambience4,
  832. Array:sound_ambience5, Array:sound_ambience1_duration, Array:sound_ambience2_duration,
  833. Array:sound_ambience3_duration, Array:sound_ambience4_duration,
  834. Array:sound_ambience5_duration, Array:sound_ambience1_ismp3, Array:sound_ambience2_ismp3,
  835. Array:sound_ambience3_ismp3, Array:sound_ambience4_ismp3, Array:sound_ambience5_ismp3,
  836. Array:g_primary_items, Array:g_secondary_items, Array:g_additional_items,
  837. Array:g_primary_weaponids, Array:g_secondary_weaponids, Array:g_extraweapon_names,
  838. Array:g_extraweapon_items, Array:g_extraweapon_costs, g_extra_costs2[EXTRA_WEAPONS_STARTID],
  839. g_ambience_snow, g_ambience_fog, g_fog_density[10], g_fog_color[12], g_sky_enable,
  840. Array:g_sky_names, Array:lights_thunder, Array:zombie_decals, Array:g_objective_ents,
  841. Float:g_modelchange_delay, g_set_modelindex_offset, g_handle_models_on_separate_ent,
  842. Float:kb_weapon_power[31] = { -1.0, ... }, Array:zombie_miss_slash, g_force_consistency
  843.  
  844. // CVAR pointers
  845. new cvar_lighting, cvar_zombiefov, cvar_plague, cvar_plaguechance, cvar_zombiefirsthp,
  846. cvar_removemoney, cvar_thunder, cvar_zombiebonushp, cvar_nemhp, cvar_nem, cvar_surv,
  847. cvar_nemchance, cvar_deathmatch, cvar_nemglow, cvar_customnvg, cvar_hitzones, cvar_humanhp,
  848. cvar_nemgravity, cvar_flashsize, cvar_ammodamage_human, cvar_ammodamage_zombie,
  849. cvar_zombiearmor, cvar_survpainfree, cvar_nempainfree, cvar_nemspd, cvar_survchance,
  850. cvar_survhp, cvar_survspd, cvar_humanspd, cvar_swarmchance, cvar_flashdrain,
  851. cvar_zombiebleeding, cvar_removedoors, cvar_customflash, cvar_randspawn, cvar_multi,
  852. cvar_multichance, cvar_infammo, cvar_swarm, cvar_ammoinfect, cvar_toggle,
  853. cvar_knockbackpower, cvar_freezeduration, cvar_triggered, cvar_flashcharge,
  854. cvar_firegrenades, cvar_frostgrenades, cvar_survgravity, cvar_logcommands, cvar_survglow,
  855. cvar_humangravity, cvar_spawnprotection, cvar_nvgsize, cvar_flareduration, cvar_zclasses,
  856. cvar_extraitems, cvar_showactivity, cvar_humanlasthp, cvar_nemignorefrags, cvar_warmup,
  857. cvar_flashdist, cvar_flarecolor, cvar_survignorefrags, cvar_fireduration, cvar_firedamage,
  858. cvar_flaregrenades, cvar_knockbackducking, cvar_knockbackdamage, cvar_knockbackzvel,
  859. cvar_multiratio, cvar_flaresize, cvar_spawndelay, cvar_extraantidote, cvar_extramadness,
  860. cvar_extraweapons, cvar_extranvision, cvar_nvggive, cvar_preventconsecutive, cvar_botquota,
  861. cvar_buycustom, cvar_zombiepainfree, cvar_fireslowdown, cvar_survbasehp, cvar_survaura,
  862. cvar_nemignoreammo, cvar_survignoreammo, cvar_nemaura, cvar_extrainfbomb, cvar_knockback,
  863. cvar_fragsinfect, cvar_fragskill, cvar_humanarmor, cvar_zombiesilent, cvar_removedropped,
  864. cvar_plagueratio, cvar_blocksuicide, cvar_knockbackdist, cvar_nemdamage, cvar_leapzombies,
  865. cvar_leapzombiesforce, cvar_leapzombiesheight, cvar_leapzombiescooldown, cvar_leapnemesis,
  866. cvar_leapnemesisforce, cvar_leapnemesisheight, cvar_leapnemesiscooldown, cvar_leapsurvivor,
  867. cvar_leapsurvivorforce, cvar_leapsurvivorheight, cvar_nemminplayers, cvar_survminplayers,
  868. cvar_respawnonsuicide, cvar_respawnafterlast, cvar_leapsurvivorcooldown, cvar_statssave,
  869. cvar_swarmminplayers, cvar_multiminplayers, cvar_plagueminplayers, cvar_adminmodelshuman,
  870. cvar_adminmodelszombie, cvar_nembasehp, cvar_blockpushables, cvar_respawnworldspawnkill,
  871. cvar_madnessduration, cvar_plaguenemnum, cvar_plaguenemhpmulti, cvar_plaguesurvhpmulti,
  872. cvar_survweapon, cvar_plaguesurvnum, cvar_infectionscreenfade, cvar_infectionscreenshake,
  873. cvar_infectionsparkle, cvar_infectiontracers, cvar_infectionparticles, cvar_infbomblimit,
  874. cvar_allowrespawnsurv, cvar_flashshowall, cvar_allowrespawninfection, cvar_allowrespawnnem,
  875. cvar_allowrespawnswarm, cvar_allowrespawnplague, cvar_survinfammo, cvar_nemknockback,
  876. cvar_nvgcolor[3], cvar_nemnvgcolor[3], cvar_humnvgcolor[3], cvar_flashcolor[3],
  877. cvar_hudicons, cvar_respawnzomb, cvar_respawnhum, cvar_respawnnem, cvar_respawnsurv,
  878. cvar_startammopacks, cvar_randweapons, cvar_antidotelimit, cvar_madnesslimit,
  879. cvar_adminknifemodelshuman, cvar_adminknifemodelszombie, cvar_keephealthondisconnect,
  880. cvar_buyzonetime, cvar_huddisplay
  881.  
  882. // Cached stuff for players
  883. new g_isconnected[33] // whether player is connected
  884. new g_isalive[33] // whether player is alive
  885. new g_isbot[33] // whether player is a bot
  886. new g_currentweapon[33] // player's current weapon id
  887. new g_playername[33][32] // player's name
  888. new Float:g_zombie_spd[33] // zombie class speed
  889. new Float:g_zombie_knockback[33] // zombie class knockback
  890. new g_zombie_classname[33][32] // zombie class name
  891. #define is_user_valid_connected(%1) (1 <= %1 <= g_maxplayers && g_isconnected[%1])
  892. #define is_user_valid_alive(%1) (1 <= %1 <= g_maxplayers && g_isalive[%1])
  893. #define is_user_valid(%1) (1 <= %1 <= g_maxplayers)
  894.  
  895. // Cached CVARs
  896. new g_cached_customflash, g_cached_zombiesilent, g_cached_leapzombies, g_cached_leapnemesis,
  897. g_cached_leapsurvivor, Float:g_cached_leapzombiescooldown, Float:g_cached_leapnemesiscooldown,
  898. Float:g_cached_leapsurvivorcooldown, Float:g_cached_buytime
  899.  
  900. /*================================================================================
  901.  [Natives, Precache and Init]
  902. =================================================================================*/
  903.  
  904. public plugin_natives()
  905. {
  906.     // Player specific natives
  907.     register_native("zp_get_user_zombie", "native_get_user_zombie", 1)
  908.     register_native("zp_get_user_nemesis", "native_get_user_nemesis", 1)
  909.     register_native("zp_get_user_survivor", "native_get_user_survivor", 1)
  910.     register_native("zp_get_user_first_zombie", "native_get_user_first_zombie", 1)
  911.     register_native("zp_get_user_last_zombie", "native_get_user_last_zombie", 1)
  912.     register_native("zp_get_user_last_human", "native_get_user_last_human", 1)
  913.     register_native("zp_get_user_zombie_class", "native_get_user_zombie_class", 1)
  914.     register_native("zp_get_user_next_class", "native_get_user_next_class", 1)
  915.     register_native("zp_set_user_zombie_class", "native_set_user_zombie_class", 1)
  916.     register_native("zp_get_user_ammo_packs", "native_get_user_ammo_packs", 1)
  917.     register_native("zp_set_user_ammo_packs", "native_set_user_ammo_packs", 1)
  918.     register_native("zp_get_zombie_maxhealth", "native_get_zombie_maxhealth", 1)
  919.     register_native("zp_get_user_batteries", "native_get_user_batteries", 1)
  920.     register_native("zp_set_user_batteries", "native_set_user_batteries", 1)
  921.     register_native("zp_get_user_nightvision", "native_get_user_nightvision", 1)
  922.     register_native("zp_set_user_nightvision", "native_set_user_nightvision", 1)
  923.     register_native("zp_infect_user", "native_infect_user", 1)
  924.     register_native("zp_disinfect_user", "native_disinfect_user", 1)
  925.     register_native("zp_make_user_nemesis", "native_make_user_nemesis", 1)
  926.     register_native("zp_make_user_survivor", "native_make_user_survivor", 1)
  927.     register_native("zp_respawn_user", "native_respawn_user", 1)
  928.     register_native("zp_force_buy_extra_item", "native_force_buy_extra_item", 1)
  929.     register_native("zp_override_user_model", "native_override_user_model", 1)
  930.    
  931.     // Round natives
  932.     register_native("zp_has_round_started", "native_has_round_started", 1)
  933.     register_native("zp_is_nemesis_round", "native_is_nemesis_round", 1)
  934.     register_native("zp_is_survivor_round", "native_is_survivor_round", 1)
  935.     register_native("zp_is_swarm_round", "native_is_swarm_round", 1)
  936.     register_native("zp_is_plague_round", "native_is_plague_round", 1)
  937.     register_native("zp_get_zombie_count", "native_get_zombie_count", 1)
  938.     register_native("zp_get_human_count", "native_get_human_count", 1)
  939.     register_native("zp_get_nemesis_count", "native_get_nemesis_count", 1)
  940.     register_native("zp_get_survivor_count", "native_get_survivor_count", 1)
  941.    
  942.     // External additions natives
  943.     register_native("zp_register_extra_item", "native_register_extra_item", 1)
  944.     register_native("zp_register_zombie_class", "native_register_zombie_class", 1)
  945.     register_native("zp_get_extra_item_id", "native_get_extra_item_id", 1)
  946.     register_native("zp_get_zombie_class_id", "native_get_zombie_class_id", 1)
  947.     register_native("zp_get_zombie_class_info", "native_get_zombie_class_info", 1)
  948. }
  949.  
  950. public plugin_precache()
  951. {
  952.     // Register earlier to show up in plugins list properly after plugin disable/error at loading
  953.     register_plugin("Zombie Plague", PLUGIN_VERSION, "MeRcyLeZZ")
  954.    
  955.     // To switch plugin on/off
  956.     register_concmd("zp_toggle", "cmd_toggle", _, "<1/0> - Enable/Disable Zombie Plague (will restart the current map)", 0)
  957.     cvar_toggle = register_cvar("zp_on", "1")
  958.    
  959.     // Plugin disabled?
  960.     if (!get_pcvar_num(cvar_toggle)) return;
  961.     g_pluginenabled = true
  962.    
  963.     // Initialize a few dynamically sized arrays (alright, maybe more than just a few...)
  964.     model_human = ArrayCreate(32, 1)
  965.     model_nemesis = ArrayCreate(32, 1)
  966.     model_survivor = ArrayCreate(32, 1)
  967.     model_admin_human = ArrayCreate(32, 1)
  968.     model_admin_zombie = ArrayCreate(32, 1)
  969.     g_modelindex_human = ArrayCreate(1, 1)
  970.     g_modelindex_nemesis = ArrayCreate(1, 1)
  971.     g_modelindex_survivor = ArrayCreate(1, 1)
  972.     g_modelindex_admin_human = ArrayCreate(1, 1)
  973.     g_modelindex_admin_zombie = ArrayCreate(1, 1)
  974.     sound_win_zombies = ArrayCreate(64, 1)
  975.     sound_win_zombies_ismp3 = ArrayCreate(1, 1)
  976.     sound_win_humans = ArrayCreate(64, 1)
  977.     sound_win_humans_ismp3 = ArrayCreate(1, 1)
  978.     sound_win_no_one = ArrayCreate(64, 1)
  979.     sound_win_no_one_ismp3 = ArrayCreate(1, 1)
  980.     zombie_infect = ArrayCreate(64, 1)
  981.     zombie_pain = ArrayCreate(64, 1)
  982.     nemesis_pain = ArrayCreate(64, 1)
  983.     zombie_die = ArrayCreate(64, 1)
  984.     zombie_fall = ArrayCreate(64, 1)
  985.     zombie_miss_slash = ArrayCreate(64, 1)
  986.     zombie_miss_wall = ArrayCreate(64, 1)
  987.     zombie_hit_normal = ArrayCreate(64, 1)
  988.     zombie_hit_stab = ArrayCreate(64, 1)
  989.     zombie_idle = ArrayCreate(64, 1)
  990.     zombie_idle_last = ArrayCreate(64, 1)
  991.     zombie_madness = ArrayCreate(64, 1)
  992.     sound_nemesis = ArrayCreate(64, 1)
  993.     sound_survivor = ArrayCreate(64, 1)
  994.     sound_swarm = ArrayCreate(64, 1)
  995.     sound_multi = ArrayCreate(64, 1)
  996.     sound_plague = ArrayCreate(64, 1)
  997.     grenade_infect = ArrayCreate(64, 1)
  998.     grenade_infect_player = ArrayCreate(64, 1)
  999.     grenade_fire = ArrayCreate(64, 1)
  1000.     grenade_fire_player = ArrayCreate(64, 1)
  1001.     grenade_frost = ArrayCreate(64, 1)
  1002.     grenade_frost_player = ArrayCreate(64, 1)
  1003.     grenade_frost_break = ArrayCreate(64, 1)
  1004.     grenade_flare = ArrayCreate(64, 1)
  1005.     sound_antidote = ArrayCreate(64, 1)
  1006.     sound_thunder = ArrayCreate(64, 1)
  1007.     sound_ambience1 = ArrayCreate(64, 1)
  1008.     sound_ambience2 = ArrayCreate(64, 1)
  1009.     sound_ambience3 = ArrayCreate(64, 1)
  1010.     sound_ambience4 = ArrayCreate(64, 1)
  1011.     sound_ambience5 = ArrayCreate(64, 1)
  1012.     sound_ambience1_duration = ArrayCreate(1, 1)
  1013.     sound_ambience2_duration = ArrayCreate(1, 1)
  1014.     sound_ambience3_duration = ArrayCreate(1, 1)
  1015.     sound_ambience4_duration = ArrayCreate(1, 1)
  1016.     sound_ambience5_duration = ArrayCreate(1, 1)
  1017.     sound_ambience1_ismp3 = ArrayCreate(1, 1)
  1018.     sound_ambience2_ismp3 = ArrayCreate(1, 1)
  1019.     sound_ambience3_ismp3 = ArrayCreate(1, 1)
  1020.     sound_ambience4_ismp3 = ArrayCreate(1, 1)
  1021.     sound_ambience5_ismp3 = ArrayCreate(1, 1)
  1022.     g_primary_items = ArrayCreate(32, 1)
  1023.     g_secondary_items = ArrayCreate(32, 1)
  1024.     g_additional_items = ArrayCreate(32, 1)
  1025.     g_primary_weaponids = ArrayCreate(1, 1)
  1026.     g_secondary_weaponids = ArrayCreate(1, 1)
  1027.     g_extraweapon_names = ArrayCreate(32, 1)
  1028.     g_extraweapon_items = ArrayCreate(32, 1)
  1029.     g_extraweapon_costs = ArrayCreate(1, 1)
  1030.     g_sky_names = ArrayCreate(32, 1)
  1031.     lights_thunder = ArrayCreate(32, 1)
  1032.     zombie_decals = ArrayCreate(1, 1)
  1033.     g_objective_ents = ArrayCreate(32, 1)
  1034.     g_extraitem_name = ArrayCreate(32, 1)
  1035.     g_extraitem_cost = ArrayCreate(1, 1)
  1036.     g_extraitem_team = ArrayCreate(1, 1)
  1037.     g_extraitem2_realname = ArrayCreate(32, 1)
  1038.     g_extraitem2_name = ArrayCreate(32, 1)
  1039.     g_extraitem2_cost = ArrayCreate(1, 1)
  1040.     g_extraitem2_team = ArrayCreate(1, 1)
  1041.     g_extraitem_new = ArrayCreate(1, 1)
  1042.     g_zclass_name = ArrayCreate(32, 1)
  1043.     g_zclass_info = ArrayCreate(32, 1)
  1044.     g_zclass_modelsstart = ArrayCreate(1, 1)
  1045.     g_zclass_modelsend = ArrayCreate(1, 1)
  1046.     g_zclass_playermodel = ArrayCreate(32, 1)
  1047.     g_zclass_modelindex = ArrayCreate(1, 1)
  1048.     g_zclass_clawmodel = ArrayCreate(32, 1)
  1049.     g_zclass_hp = ArrayCreate(1, 1)
  1050.     g_zclass_spd = ArrayCreate(1, 1)
  1051.     g_zclass_grav = ArrayCreate(1, 1)
  1052.     g_zclass_kb = ArrayCreate(1, 1)
  1053.     g_zclass2_realname = ArrayCreate(32, 1)
  1054.     g_zclass2_name = ArrayCreate(32, 1)
  1055.     g_zclass2_info = ArrayCreate(32, 1)
  1056.     g_zclass2_modelsstart = ArrayCreate(1, 1)
  1057.     g_zclass2_modelsend = ArrayCreate(1, 1)
  1058.     g_zclass2_playermodel = ArrayCreate(32, 1)
  1059.     g_zclass2_modelindex = ArrayCreate(1, 1)
  1060.     g_zclass2_clawmodel = ArrayCreate(32, 1)
  1061.     g_zclass2_hp = ArrayCreate(1, 1)
  1062.     g_zclass2_spd = ArrayCreate(1, 1)
  1063.     g_zclass2_grav = ArrayCreate(1, 1)
  1064.     g_zclass2_kb = ArrayCreate(1, 1)
  1065.     g_zclass_new = ArrayCreate(1, 1)
  1066.    
  1067.     // Allow registering stuff now
  1068.     g_arrays_created = true
  1069.    
  1070.     // Load customization data
  1071.     load_customization_from_files()
  1072.    
  1073.     new i, buffer[100]
  1074.    
  1075.     // Load up the hard coded extra items
  1076.     native_register_extra_item2("NightVision", g_extra_costs2[EXTRA_NVISION], ZP_TEAM_HUMAN)
  1077.     native_register_extra_item2("T-Virus Antidote", g_extra_costs2[EXTRA_ANTIDOTE], ZP_TEAM_ZOMBIE)
  1078.     native_register_extra_item2("Zombie Madness", g_extra_costs2[EXTRA_MADNESS], ZP_TEAM_ZOMBIE)
  1079.     native_register_extra_item2("Infection Bomb", g_extra_costs2[EXTRA_INFBOMB], ZP_TEAM_ZOMBIE)
  1080.    
  1081.     // Extra weapons
  1082.     for (i = 0; i < ArraySize(g_extraweapon_names); i++)
  1083.     {
  1084.         ArrayGetString(g_extraweapon_names, i, buffer, charsmax(buffer))
  1085.         native_register_extra_item2(buffer, ArrayGetCell(g_extraweapon_costs, i), ZP_TEAM_HUMAN)
  1086.     }
  1087.    
  1088.     // Custom player models
  1089.     for (i = 0; i < ArraySize(model_human); i++)
  1090.     {
  1091.         ArrayGetString(model_human, i, buffer, charsmax(buffer))
  1092.         format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1093.         ArrayPushCell(g_modelindex_human, engfunc(EngFunc_PrecacheModel, buffer))
  1094.         if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1095.         if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1096.         // Precache modelT.mdl files too
  1097.         copy(buffer[strlen(buffer)-4], charsmax(buffer) - (strlen(buffer)-4), "T.mdl")
  1098.         if (file_exists(buffer)) engfunc(EngFunc_PrecacheModel, buffer)
  1099.     }
  1100.     for (i = 0; i < ArraySize(model_nemesis); i++)
  1101.     {
  1102.         ArrayGetString(model_nemesis, i, buffer, charsmax(buffer))
  1103.         format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1104.         ArrayPushCell(g_modelindex_nemesis, engfunc(EngFunc_PrecacheModel, buffer))
  1105.         if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1106.         if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1107.         // Precache modelT.mdl files too
  1108.         copy(buffer[strlen(buffer)-4], charsmax(buffer) - (strlen(buffer)-4), "T.mdl")
  1109.         if (file_exists(buffer)) engfunc(EngFunc_PrecacheModel, buffer)
  1110.     }
  1111.     for (i = 0; i < ArraySize(model_survivor); i++)
  1112.     {
  1113.         ArrayGetString(model_survivor, i, buffer, charsmax(buffer))
  1114.         format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1115.         ArrayPushCell(g_modelindex_survivor, engfunc(EngFunc_PrecacheModel, buffer))
  1116.         if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1117.         if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1118.         // Precache modelT.mdl files too
  1119.         copy(buffer[strlen(buffer)-4], charsmax(buffer) - (strlen(buffer)-4), "T.mdl")
  1120.         if (file_exists(buffer)) engfunc(EngFunc_PrecacheModel, buffer)
  1121.     }
  1122.     for (i = 0; i < ArraySize(model_admin_zombie); i++)
  1123.     {
  1124.         ArrayGetString(model_admin_zombie, i, buffer, charsmax(buffer))
  1125.         format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1126.         ArrayPushCell(g_modelindex_admin_zombie, engfunc(EngFunc_PrecacheModel, buffer))
  1127.         if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1128.         if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1129.         // Precache modelT.mdl files too
  1130.         copy(buffer[strlen(buffer)-4], charsmax(buffer) - (strlen(buffer)-4), "T.mdl")
  1131.         if (file_exists(buffer)) engfunc(EngFunc_PrecacheModel, buffer)
  1132.     }
  1133.     for (i = 0; i < ArraySize(model_admin_human); i++)
  1134.     {
  1135.         ArrayGetString(model_admin_human, i, buffer, charsmax(buffer))
  1136.         format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
  1137.         ArrayPushCell(g_modelindex_admin_human, engfunc(EngFunc_PrecacheModel, buffer))
  1138.         if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
  1139.         if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
  1140.         // Precache modelT.mdl files too
  1141.         copy(buffer[strlen(buffer)-4], charsmax(buffer) - (strlen(buffer)-4), "T.mdl")
  1142.         if (file_exists(buffer)) engfunc(EngFunc_PrecacheModel, buffer)
  1143.     }
  1144.    
  1145.     // Custom weapon models
  1146.     engfunc(EngFunc_PrecacheModel, model_vknife_human)
  1147.     engfunc(EngFunc_PrecacheModel, model_vknife_nemesis)
  1148.     engfunc(EngFunc_PrecacheModel, model_vweapon_survivor)
  1149.     engfunc(EngFunc_PrecacheModel, model_grenade_infect)
  1150.     engfunc(EngFunc_PrecacheModel, model_grenade_fire)
  1151.     engfunc(EngFunc_PrecacheModel, model_grenade_frost)
  1152.     engfunc(EngFunc_PrecacheModel, model_grenade_flare)
  1153.     engfunc(EngFunc_PrecacheModel, model_vknife_admin_human)
  1154.     engfunc(EngFunc_PrecacheModel, model_vknife_admin_zombie)
  1155.    
  1156.     // Custom sprites for grenades
  1157.     g_trailSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_trail)
  1158.     g_exploSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_ring)
  1159.     g_flameSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_fire)
  1160.     g_smokeSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_smoke)
  1161.     g_glassSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_glass)
  1162.    
  1163.     // Custom sounds
  1164.     for (i = 0; i < ArraySize(sound_win_zombies); i++)
  1165.     {
  1166.         ArrayGetString(sound_win_zombies, i, buffer, charsmax(buffer))
  1167.         if (ArrayGetCell(sound_win_zombies_ismp3, i))
  1168.         {
  1169.             format(buffer, charsmax(buffer), "sound/%s", buffer)
  1170.             engfunc(EngFunc_PrecacheGeneric, buffer)
  1171.         }
  1172.         else
  1173.         {
  1174.             engfunc(EngFunc_PrecacheSound, buffer)
  1175.         }
  1176.     }
  1177.     for (i = 0; i < ArraySize(sound_win_humans); i++)
  1178.     {
  1179.         ArrayGetString(sound_win_humans, i, buffer, charsmax(buffer))
  1180.         if (ArrayGetCell(sound_win_humans_ismp3, i))
  1181.         {
  1182.             format(buffer, charsmax(buffer), "sound/%s", buffer)
  1183.             engfunc(EngFunc_PrecacheGeneric, buffer)
  1184.         }
  1185.         else
  1186.         {
  1187.             engfunc(EngFunc_PrecacheSound, buffer)
  1188.         }
  1189.     }
  1190.     for (i = 0; i < ArraySize(sound_win_no_one); i++)
  1191.     {
  1192.         ArrayGetString(sound_win_no_one, i, buffer, charsmax(buffer))
  1193.         if (ArrayGetCell(sound_win_no_one_ismp3, i))
  1194.         {
  1195.             format(buffer, charsmax(buffer), "sound/%s", buffer)
  1196.             engfunc(EngFunc_PrecacheGeneric, buffer)
  1197.         }
  1198.         else
  1199.         {
  1200.             engfunc(EngFunc_PrecacheSound, buffer)
  1201.         }
  1202.     }
  1203.     for (i = 0; i < ArraySize(zombie_infect); i++)
  1204.     {
  1205.         ArrayGetString(zombie_infect, i, buffer, charsmax(buffer))
  1206.         engfunc(EngFunc_PrecacheSound, buffer)
  1207.     }
  1208.     for (i = 0; i < ArraySize(zombie_pain); i++)
  1209.     {
  1210.         ArrayGetString(zombie_pain, i, buffer, charsmax(buffer))
  1211.         engfunc(EngFunc_PrecacheSound, buffer)
  1212.     }
  1213.     for (i = 0; i < ArraySize(nemesis_pain); i++)
  1214.     {
  1215.         ArrayGetString(nemesis_pain, i, buffer, charsmax(buffer))
  1216.         engfunc(EngFunc_PrecacheSound, buffer)
  1217.     }
  1218.     for (i = 0; i < ArraySize(zombie_die); i++)
  1219.     {
  1220.         ArrayGetString(zombie_die, i, buffer, charsmax(buffer))
  1221.         engfunc(EngFunc_PrecacheSound, buffer)
  1222.     }
  1223.     for (i = 0; i < ArraySize(zombie_fall); i++)
  1224.     {
  1225.         ArrayGetString(zombie_fall, i, buffer, charsmax(buffer))
  1226.         engfunc(EngFunc_PrecacheSound, buffer)
  1227.     }
  1228.     for (i = 0; i < ArraySize(zombie_miss_slash); i++)
  1229.     {
  1230.         ArrayGetString(zombie_miss_slash, i, buffer, charsmax(buffer))
  1231.         engfunc(EngFunc_PrecacheSound, buffer)
  1232.     }
  1233.     for (i = 0; i < ArraySize(zombie_miss_wall); i++)
  1234.     {
  1235.         ArrayGetString(zombie_miss_wall, i, buffer, charsmax(buffer))
  1236.         engfunc(EngFunc_PrecacheSound, buffer)
  1237.     }
  1238.     for (i = 0; i < ArraySize(zombie_hit_normal); i++)
  1239.     {
  1240.         ArrayGetString(zombie_hit_normal, i, buffer, charsmax(buffer))
  1241.         engfunc(EngFunc_PrecacheSound, buffer)
  1242.     }
  1243.     for (i = 0; i < ArraySize(zombie_hit_stab); i++)
  1244.     {
  1245.         ArrayGetString(zombie_hit_stab, i, buffer, charsmax(buffer))
  1246.         engfunc(EngFunc_PrecacheSound, buffer)
  1247.     }
  1248.     for (i = 0; i < ArraySize(zombie_idle); i++)
  1249.     {
  1250.         ArrayGetString(zombie_idle, i, buffer, charsmax(buffer))
  1251.         engfunc(EngFunc_PrecacheSound, buffer)
  1252.     }
  1253.     for (i = 0; i < ArraySize(zombie_idle_last); i++)
  1254.     {
  1255.         ArrayGetString(zombie_idle_last, i, buffer, charsmax(buffer))
  1256.         engfunc(EngFunc_PrecacheSound, buffer)
  1257.     }
  1258.     for (i = 0; i < ArraySize(zombie_madness); i++)
  1259.     {
  1260.         ArrayGetString(zombie_madness, i, buffer, charsmax(buffer))
  1261.         engfunc(EngFunc_PrecacheSound, buffer)
  1262.     }
  1263.     for (i = 0; i < ArraySize(sound_nemesis); i++)
  1264.     {
  1265.         ArrayGetString(sound_nemesis, i, buffer, charsmax(buffer))
  1266.         engfunc(EngFunc_PrecacheSound, buffer)
  1267.     }
  1268.     for (i = 0; i < ArraySize(sound_survivor); i++)
  1269.     {
  1270.         ArrayGetString(sound_survivor, i, buffer, charsmax(buffer))
  1271.         engfunc(EngFunc_PrecacheSound, buffer)
  1272.     }
  1273.     for (i = 0; i < ArraySize(sound_swarm); i++)
  1274.     {
  1275.         ArrayGetString(sound_swarm, i, buffer, charsmax(buffer))
  1276.         engfunc(EngFunc_PrecacheSound, buffer)
  1277.     }
  1278.     for (i = 0; i < ArraySize(sound_multi); i++)
  1279.     {
  1280.         ArrayGetString(sound_multi, i, buffer, charsmax(buffer))
  1281.         engfunc(EngFunc_PrecacheSound, buffer)
  1282.     }
  1283.     for (i = 0; i < ArraySize(sound_plague); i++)
  1284.     {
  1285.         ArrayGetString(sound_plague, i, buffer, charsmax(buffer))
  1286.         engfunc(EngFunc_PrecacheSound, buffer)
  1287.     }
  1288.     for (i = 0; i < ArraySize(grenade_infect); i++)
  1289.     {
  1290.         ArrayGetString(grenade_infect, i, buffer, charsmax(buffer))
  1291.         engfunc(EngFunc_PrecacheSound, buffer)
  1292.     }
  1293.     for (i = 0; i < ArraySize(grenade_infect_player); i++)
  1294.     {
  1295.         ArrayGetString(grenade_infect_player, i, buffer, charsmax(buffer))
  1296.         engfunc(EngFunc_PrecacheSound, buffer)
  1297.     }
  1298.     for (i = 0; i < ArraySize(grenade_fire); i++)
  1299.     {
  1300.         ArrayGetString(grenade_fire, i, buffer, charsmax(buffer))
  1301.         engfunc(EngFunc_PrecacheSound, buffer)
  1302.     }
  1303.     for (i = 0; i < ArraySize(grenade_fire_player); i++)
  1304.     {
  1305.         ArrayGetString(grenade_fire_player, i, buffer, charsmax(buffer))
  1306.         engfunc(EngFunc_PrecacheSound, buffer)
  1307.     }
  1308.     for (i = 0; i < ArraySize(grenade_frost); i++)
  1309.     {
  1310.         ArrayGetString(grenade_frost, i, buffer, charsmax(buffer))
  1311.         engfunc(EngFunc_PrecacheSound, buffer)
  1312.     }
  1313.     for (i = 0; i < ArraySize(grenade_frost_player); i++)
  1314.     {
  1315.         ArrayGetString(grenade_frost_player, i, buffer, charsmax(buffer))
  1316.         engfunc(EngFunc_PrecacheSound, buffer)
  1317.     }
  1318.     for (i = 0; i < ArraySize(grenade_frost_break); i++)
  1319.     {
  1320.         ArrayGetString(grenade_frost_break, i, buffer, charsmax(buffer))
  1321.         engfunc(EngFunc_PrecacheSound, buffer)
  1322.     }
  1323.     for (i = 0; i < ArraySize(grenade_flare); i++)
  1324.     {
  1325.         ArrayGetString(grenade_flare, i, buffer, charsmax(buffer))
  1326.         engfunc(EngFunc_PrecacheSound, buffer)
  1327.     }
  1328.     for (i = 0; i < ArraySize(sound_antidote); i++)
  1329.     {
  1330.         ArrayGetString(sound_antidote, i, buffer, charsmax(buffer))
  1331.         engfunc(EngFunc_PrecacheSound, buffer)
  1332.     }
  1333.     for (i = 0; i < ArraySize(sound_thunder); i++)
  1334.     {
  1335.         ArrayGetString(sound_thunder, i, buffer, charsmax(buffer))
  1336.         engfunc(EngFunc_PrecacheSound, buffer)
  1337.     }
  1338.    
  1339.     // Ambience Sounds
  1340.     if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION])
  1341.     {
  1342.         for (i = 0; i < ArraySize(sound_ambience1); i++)
  1343.         {
  1344.             ArrayGetString(sound_ambience1, i, buffer, charsmax(buffer))
  1345.            
  1346.             if (ArrayGetCell(sound_ambience1_ismp3, i))
  1347.             {
  1348.                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1349.                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1350.             }
  1351.             else
  1352.             {
  1353.                 engfunc(EngFunc_PrecacheSound, buffer)
  1354.             }
  1355.         }
  1356.     }
  1357.     if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS])
  1358.     {
  1359.         for (i = 0; i < ArraySize(sound_ambience2); i++)
  1360.         {
  1361.             ArrayGetString(sound_ambience2, i, buffer, charsmax(buffer))
  1362.            
  1363.             if (ArrayGetCell(sound_ambience2_ismp3, i))
  1364.             {
  1365.                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1366.                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1367.             }
  1368.             else
  1369.             {
  1370.                 engfunc(EngFunc_PrecacheSound, buffer)
  1371.             }
  1372.         }
  1373.     }
  1374.     if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR])
  1375.     {
  1376.         for (i = 0; i < ArraySize(sound_ambience3); i++)
  1377.         {
  1378.             ArrayGetString(sound_ambience3, i, buffer, charsmax(buffer))
  1379.            
  1380.             if (ArrayGetCell(sound_ambience3_ismp3, i))
  1381.             {
  1382.                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1383.                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1384.             }
  1385.             else
  1386.             {
  1387.                 engfunc(EngFunc_PrecacheSound, buffer)
  1388.             }
  1389.         }
  1390.     }
  1391.     if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM])
  1392.     {
  1393.         for (i = 0; i < ArraySize(sound_ambience4); i++)
  1394.         {
  1395.             ArrayGetString(sound_ambience4, i, buffer, charsmax(buffer))
  1396.            
  1397.             if (ArrayGetCell(sound_ambience4_ismp3, i))
  1398.             {
  1399.                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1400.                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1401.             }
  1402.             else
  1403.             {
  1404.                 engfunc(EngFunc_PrecacheSound, buffer)
  1405.             }
  1406.         }
  1407.     }
  1408.     if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE])
  1409.     {
  1410.         for (i = 0; i < ArraySize(sound_ambience5); i++)
  1411.         {
  1412.             ArrayGetString(sound_ambience5, i, buffer, charsmax(buffer))
  1413.            
  1414.             if (ArrayGetCell(sound_ambience5_ismp3, i))
  1415.             {
  1416.                 format(buffer, charsmax(buffer), "sound/%s", buffer)
  1417.                 engfunc(EngFunc_PrecacheGeneric, buffer)
  1418.             }
  1419.             else
  1420.             {
  1421.                 engfunc(EngFunc_PrecacheSound, buffer)
  1422.             }
  1423.         }
  1424.     }
  1425.    
  1426.     // CS sounds (just in case)
  1427.     engfunc(EngFunc_PrecacheSound, sound_flashlight)
  1428.     engfunc(EngFunc_PrecacheSound, sound_buyammo)
  1429.     engfunc(EngFunc_PrecacheSound, sound_armorhit)
  1430.    
  1431.     new ent
  1432.    
  1433.     // Fake Hostage (to force round ending)
  1434.     ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "hostage_entity"))
  1435.     if (pev_valid(ent))
  1436.     {
  1437.         engfunc(EngFunc_SetOrigin, ent, Float:{8192.0,8192.0,8192.0})
  1438.         dllfunc(DLLFunc_Spawn, ent)
  1439.     }
  1440.    
  1441.     // Weather/ambience effects
  1442.     if (g_ambience_fog)
  1443.     {
  1444.         ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_fog"))
  1445.         if (pev_valid(ent))
  1446.         {
  1447.             fm_set_kvd(ent, "density", g_fog_density, "env_fog")
  1448.             fm_set_kvd(ent, "rendercolor", g_fog_color, "env_fog")
  1449.         }
  1450.     }
  1451.     if (g_ambience_rain) engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_rain"))
  1452.     if (g_ambience_snow) engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_snow"))
  1453.    
  1454.     // Custom buyzone for all players
  1455.     g_buyzone_ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "func_buyzone"))
  1456.     if (pev_valid(g_buyzone_ent))
  1457.     {
  1458.         dllfunc(DLLFunc_Spawn, g_buyzone_ent)
  1459.         set_pev(g_buyzone_ent, pev_solid, SOLID_NOT)
  1460.     }
  1461.    
  1462.     // Prevent some entities from spawning
  1463.     g_fwSpawn = register_forward(FM_Spawn, "fw_Spawn")
  1464.    
  1465.     // Prevent hostage sounds from being precached
  1466.     g_fwPrecacheSound = register_forward(FM_PrecacheSound, "fw_PrecacheSound")
  1467. }
  1468.  
  1469. public plugin_init()
  1470. {
  1471.     // Plugin disabled?
  1472.     if (!g_pluginenabled) return;
  1473.    
  1474.     // No zombie classes?
  1475.     if (!g_zclass_i) set_fail_state("No zombie classes loaded!")
  1476.    
  1477.     // Language files
  1478.     register_dictionary("zombie_plague.txt")
  1479.    
  1480.     // Events
  1481.     register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
  1482.     register_logevent("logevent_round_start",2, "1=Round_Start")
  1483.     register_logevent("logevent_round_end", 2, "1=Round_End")
  1484.     register_event("AmmoX", "event_ammo_x", "be")
  1485.     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])
  1486.         register_event("30", "event_intermission", "a")
  1487.    
  1488.     // HAM Forwards
  1489.     RegisterHam(Ham_Spawn, "player", "fw_PlayerSpawn_Post", 1)
  1490.     RegisterHam(Ham_Killed, "player", "fw_PlayerKilled")
  1491.     RegisterHam(Ham_Killed, "player", "fw_PlayerKilled_Post", 1)
  1492.     RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
  1493.     RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage_Post", 1)
  1494.     RegisterHam(Ham_TraceAttack, "player", "fw_TraceAttack")
  1495.     RegisterHam(Ham_Player_ResetMaxSpeed, "player", "fw_ResetMaxSpeed_Post", 1)
  1496.     RegisterHam(Ham_Use, "func_tank", "fw_UseStationary")
  1497.     RegisterHam(Ham_Use, "func_tankmortar", "fw_UseStationary")
  1498.     RegisterHam(Ham_Use, "func_tankrocket", "fw_UseStationary")
  1499.     RegisterHam(Ham_Use, "func_tanklaser", "fw_UseStationary")
  1500.     RegisterHam(Ham_Use, "func_tank", "fw_UseStationary_Post", 1)
  1501.     RegisterHam(Ham_Use, "func_tankmortar", "fw_UseStationary_Post", 1)
  1502.     RegisterHam(Ham_Use, "func_tankrocket", "fw_UseStationary_Post", 1)
  1503.     RegisterHam(Ham_Use, "func_tanklaser", "fw_UseStationary_Post", 1)
  1504.     RegisterHam(Ham_Use, "func_pushable", "fw_UsePushable")
  1505.     RegisterHam(Ham_Touch, "weaponbox", "fw_TouchWeapon")
  1506.     RegisterHam(Ham_Touch, "armoury_entity", "fw_TouchWeapon")
  1507.     RegisterHam(Ham_Touch, "weapon_shield", "fw_TouchWeapon")
  1508.     RegisterHam(Ham_AddPlayerItem, "player", "fw_AddPlayerItem")
  1509.     for (new i = 1; i < sizeof WEAPONENTNAMES; i++)
  1510.         if (WEAPONENTNAMES[i][0]) RegisterHam(Ham_Item_Deploy, WEAPONENTNAMES[i], "fw_Item_Deploy_Post", 1)
  1511.    
  1512.     // FM Forwards
  1513.     register_forward(FM_ClientDisconnect, "fw_ClientDisconnect")
  1514.     register_forward(FM_ClientDisconnect, "fw_ClientDisconnect_Post", 1)
  1515.     register_forward(FM_ClientKill, "fw_ClientKill")
  1516.     register_forward(FM_EmitSound, "fw_EmitSound")
  1517.     if (!g_handle_models_on_separate_ent) register_forward(FM_SetClientKeyValue, "fw_SetClientKeyValue")
  1518.     register_forward(FM_ClientUserInfoChanged, "fw_ClientUserInfoChanged")
  1519.     register_forward(FM_GetGameDescription, "fw_GetGameDescription")
  1520.     register_forward(FM_SetModel, "fw_SetModel")
  1521.     RegisterHam(Ham_Think, "grenade", "fw_ThinkGrenade")
  1522.     register_forward(FM_CmdStart, "fw_CmdStart")
  1523.     register_forward(FM_PlayerPreThink, "fw_PlayerPreThink")
  1524.     unregister_forward(FM_Spawn, g_fwSpawn)
  1525.     unregister_forward(FM_PrecacheSound, g_fwPrecacheSound)
  1526.    
  1527.     // Client commands
  1528.     register_clcmd("say zpmenu", "clcmd_saymenu")
  1529.     register_clcmd("say /zpmenu", "clcmd_saymenu")
  1530.     register_clcmd("say unstuck", "clcmd_sayunstuck")
  1531.     register_clcmd("say /unstuck", "clcmd_sayunstuck")
  1532.     register_clcmd("nightvision", "clcmd_nightvision")
  1533.     register_clcmd("drop", "clcmd_drop")
  1534.     register_clcmd("buyammo1", "clcmd_buyammo")
  1535.     register_clcmd("buyammo2", "clcmd_buyammo")
  1536.     register_clcmd("chooseteam", "clcmd_changeteam")
  1537.     register_clcmd("jointeam", "clcmd_changeteam")
  1538.    
  1539.     // Menus
  1540.     register_menu("Game Menu", KEYSMENU, "menu_game")
  1541.     register_menu("Buy Menu 1", KEYSMENU, "menu_buy1")
  1542.     register_menu("Buy Menu 2", KEYSMENU, "menu_buy2")
  1543.     register_menu("Mod Info", KEYSMENU, "menu_info")
  1544.     register_menu("Admin Menu", KEYSMENU, "menu_admin")
  1545.    
  1546.     // CS Buy Menus (to prevent zombies/survivor from buying)
  1547.     register_menucmd(register_menuid("#Buy", 1), 511, "menu_cs_buy")
  1548.     register_menucmd(register_menuid("BuyPistol", 1), 511, "menu_cs_buy")
  1549.     register_menucmd(register_menuid("BuyShotgun", 1), 511, "menu_cs_buy")
  1550.     register_menucmd(register_menuid("BuySub", 1), 511, "menu_cs_buy")
  1551.     register_menucmd(register_menuid("BuyRifle", 1), 511, "menu_cs_buy")
  1552.     register_menucmd(register_menuid("BuyMachine", 1), 511, "menu_cs_buy")
  1553.     register_menucmd(register_menuid("BuyItem", 1), 511, "menu_cs_buy")
  1554.     register_menucmd(-28, 511, "menu_cs_buy")
  1555.     register_menucmd(-29, 511, "menu_cs_buy")
  1556.     register_menucmd(-30, 511, "menu_cs_buy")
  1557.     register_menucmd(-32, 511, "menu_cs_buy")
  1558.     register_menucmd(-31, 511, "menu_cs_buy")
  1559.     register_menucmd(-33, 511, "menu_cs_buy")
  1560.     register_menucmd(-34, 511, "menu_cs_buy")
  1561.    
  1562.     // Admin commands
  1563.     register_concmd("zp_zombie", "cmd_zombie", _, "<target> - Turn someone into a Zombie", 0)
  1564.     register_concmd("zp_human", "cmd_human", _, "<target> - Turn someone back to Human", 0)
  1565.     register_concmd("zp_nemesis", "cmd_nemesis", _, "<target> - Turn someone into a Nemesis", 0)
  1566.     register_concmd("zp_survivor", "cmd_survivor", _, "<target> - Turn someone into a Survivor", 0)
  1567.     register_concmd("zp_respawn", "cmd_respawn", _, "<target> - Respawn someone", 0)
  1568.     register_concmd("zp_swarm", "cmd_swarm", _, " - Start Swarm Mode", 0)
  1569.     register_concmd("zp_multi", "cmd_multi", _, " - Start Multi Infection", 0)
  1570.     register_concmd("zp_plague", "cmd_plague", _, " - Start Plague Mode", 0)
  1571.    
  1572.     // Message IDs
  1573.     g_msgScoreInfo = get_user_msgid("ScoreInfo")
  1574.     g_msgTeamInfo = get_user_msgid("TeamInfo")
  1575.     g_msgDeathMsg = get_user_msgid("DeathMsg")
  1576.     g_msgScoreAttrib = get_user_msgid("ScoreAttrib")
  1577.     g_msgSetFOV = get_user_msgid("SetFOV")
  1578.     g_msgScreenFade = get_user_msgid("ScreenFade")
  1579.     g_msgScreenShake = get_user_msgid("ScreenShake")
  1580.     g_msgNVGToggle = get_user_msgid("NVGToggle")
  1581.     g_msgFlashlight = get_user_msgid("Flashlight")
  1582.     g_msgFlashBat = get_user_msgid("FlashBat")
  1583.     g_msgAmmoPickup = get_user_msgid("AmmoPickup")
  1584.     g_msgDamage = get_user_msgid("Damage")
  1585.     g_msgHideWeapon = get_user_msgid("HideWeapon")
  1586.     g_msgCrosshair = get_user_msgid("Crosshair")
  1587.     g_msgSayText = get_user_msgid("SayText")
  1588.     g_msgCurWeapon = get_user_msgid("CurWeapon")
  1589.    
  1590.     // Message hooks
  1591.     register_message(g_msgCurWeapon, "message_cur_weapon")
  1592.     register_message(get_user_msgid("Money"), "message_money")
  1593.     register_message(get_user_msgid("Health"), "message_health")
  1594.     register_message(g_msgFlashBat, "message_flashbat")
  1595.     register_message(g_msgScreenFade, "message_screenfade")
  1596.     register_message(g_msgNVGToggle, "message_nvgtoggle")
  1597.     if (g_handle_models_on_separate_ent) register_message(get_user_msgid("ClCorpse"), "message_clcorpse")
  1598.     register_message(get_user_msgid("WeapPickup"), "message_weappickup")
  1599.     register_message(g_msgAmmoPickup, "message_ammopickup")
  1600.     register_message(get_user_msgid("Scenario"), "message_scenario")
  1601.     register_message(get_user_msgid("HostagePos"), "message_hostagepos")
  1602.     register_message(get_user_msgid("TextMsg"), "message_textmsg")
  1603.     register_message(get_user_msgid("SendAudio"), "message_sendaudio")
  1604.     register_message(get_user_msgid("TeamScore"), "message_teamscore")
  1605.     register_message(g_msgTeamInfo, "message_teaminfo")
  1606.    
  1607.     // CVARS - General Purpose
  1608.     cvar_warmup = register_cvar("zp_delay", "10")
  1609.     cvar_lighting = register_cvar("zp_lighting", "a")
  1610.     cvar_thunder = register_cvar("zp_thunderclap", "90")
  1611.     cvar_triggered = register_cvar("zp_triggered_lights", "1")
  1612.     cvar_removedoors = register_cvar("zp_remove_doors", "0")
  1613.     cvar_blockpushables = register_cvar("zp_blockuse_pushables", "1")
  1614.     cvar_blocksuicide = register_cvar("zp_block_suicide", "1")
  1615.     cvar_randspawn = register_cvar("zp_random_spawn", "1")
  1616.     cvar_respawnworldspawnkill = register_cvar("zp_respawn_on_worldspawn_kill", "1")
  1617.     cvar_removedropped = register_cvar("zp_remove_dropped", "0")
  1618.     cvar_removemoney = register_cvar("zp_remove_money", "1")
  1619.     cvar_buycustom = register_cvar("zp_buy_custom", "1")
  1620.     cvar_buyzonetime = register_cvar("zp_buyzone_time", "0.0")
  1621.     cvar_randweapons = register_cvar("zp_random_weapons", "0")
  1622.     cvar_adminmodelshuman = register_cvar("zp_admin_models_human", "1")
  1623.     cvar_adminknifemodelshuman = register_cvar("zp_admin_knife_models_human", "0")
  1624.     cvar_adminmodelszombie = register_cvar("zp_admin_models_zombie", "1")
  1625.     cvar_adminknifemodelszombie = register_cvar("zp_admin_knife_models_zombie", "0")
  1626.     cvar_zclasses = register_cvar("zp_zombie_classes", "1")
  1627.     cvar_statssave = register_cvar("zp_stats_save", "1")
  1628.     cvar_startammopacks = register_cvar("zp_starting_ammo_packs", "5")
  1629.     cvar_preventconsecutive = register_cvar("zp_prevent_consecutive_modes", "1")
  1630.     cvar_keephealthondisconnect = register_cvar("zp_keep_health_on_disconnect", "1")
  1631.     cvar_huddisplay = register_cvar("zp_hud_display", "1")
  1632.    
  1633.     // CVARS - Deathmatch
  1634.     cvar_deathmatch = register_cvar("zp_deathmatch", "0")
  1635.     cvar_spawndelay = register_cvar("zp_spawn_delay", "5")
  1636.     cvar_spawnprotection = register_cvar("zp_spawn_protection", "5")
  1637.     cvar_respawnonsuicide = register_cvar("zp_respawn_on_suicide", "0")
  1638.     cvar_respawnafterlast = register_cvar("zp_respawn_after_last_human", "1")
  1639.     cvar_allowrespawninfection = register_cvar("zp_infection_allow_respawn", "1")
  1640.     cvar_allowrespawnnem = register_cvar("zp_nem_allow_respawn", "0")
  1641.     cvar_allowrespawnsurv = register_cvar("zp_surv_allow_respawn", "0")
  1642.     cvar_allowrespawnswarm = register_cvar("zp_swarm_allow_respawn", "0")
  1643.     cvar_allowrespawnplague = register_cvar("zp_plague_allow_respawn", "0")
  1644.     cvar_respawnzomb = register_cvar("zp_respawn_zombies", "1")
  1645.     cvar_respawnhum = register_cvar("zp_respawn_humans", "1")
  1646.     cvar_respawnnem = register_cvar("zp_respawn_nemesis", "1")
  1647.     cvar_respawnsurv = register_cvar("zp_respawn_survivors", "1")
  1648.    
  1649.     // CVARS - Extra Items
  1650.     cvar_extraitems = register_cvar("zp_extra_items", "1")
  1651.     cvar_extraweapons = register_cvar("zp_extra_weapons", "1")
  1652.     cvar_extranvision = register_cvar("zp_extra_nvision", "1")
  1653.     cvar_extraantidote = register_cvar("zp_extra_antidote", "1")
  1654.     cvar_antidotelimit = register_cvar("zp_extra_antidote_limit", "999")
  1655.     cvar_extramadness = register_cvar("zp_extra_madness", "1")
  1656.     cvar_madnesslimit = register_cvar("zp_extra_madness_limit", "999")
  1657.     cvar_madnessduration = register_cvar("zp_extra_madness_duration", "5.0")
  1658.     cvar_extrainfbomb = register_cvar("zp_extra_infbomb", "1")
  1659.     cvar_infbomblimit = register_cvar("zp_extra_infbomb_limit", "999")
  1660.    
  1661.     // CVARS - Flashlight and Nightvision
  1662.     cvar_nvggive = register_cvar("zp_nvg_give", "1")
  1663.     cvar_customnvg = register_cvar("zp_nvg_custom", "1")
  1664.     cvar_nvgsize = register_cvar("zp_nvg_size", "80")
  1665.     cvar_nvgcolor[0] = register_cvar("zp_nvg_color_R", "0")
  1666.     cvar_nvgcolor[1] = register_cvar("zp_nvg_color_G", "150")
  1667.     cvar_nvgcolor[2] = register_cvar("zp_nvg_color_B", "0")
  1668.     cvar_humnvgcolor[0] = register_cvar("zp_nvg_hum_color_R", "0")
  1669.     cvar_humnvgcolor[1] = register_cvar("zp_nvg_hum_color_G", "150")
  1670.     cvar_humnvgcolor[2] = register_cvar("zp_nvg_hum_color_B", "0")
  1671.     cvar_nemnvgcolor[0] = register_cvar("zp_nvg_nem_color_R", "150")
  1672.     cvar_nemnvgcolor[1] = register_cvar("zp_nvg_nem_color_G", "0")
  1673.     cvar_nemnvgcolor[2] = register_cvar("zp_nvg_nem_color_B", "0")
  1674.     cvar_customflash = register_cvar("zp_flash_custom", "0")
  1675.     cvar_flashsize = register_cvar("zp_flash_size", "10")
  1676.     cvar_flashdrain = register_cvar("zp_flash_drain", "1")
  1677.     cvar_flashcharge = register_cvar("zp_flash_charge", "5")
  1678.     cvar_flashdist = register_cvar("zp_flash_distance", "1000")
  1679.     cvar_flashcolor[0] = register_cvar("zp_flash_color_R", "100")
  1680.     cvar_flashcolor[1] = register_cvar("zp_flash_color_G", "100")
  1681.     cvar_flashcolor[2] = register_cvar("zp_flash_color_B", "100")
  1682.     cvar_flashshowall = register_cvar("zp_flash_show_all", "1")
  1683.    
  1684.     // CVARS - Knockback
  1685.     cvar_knockback = register_cvar("zp_knockback", "0")
  1686.     cvar_knockbackdamage = register_cvar("zp_knockback_damage", "1")
  1687.     cvar_knockbackpower = register_cvar("zp_knockback_power", "1")
  1688.     cvar_knockbackzvel = register_cvar("zp_knockback_zvel", "0")
  1689.     cvar_knockbackducking = register_cvar("zp_knockback_ducking", "0.25")
  1690.     cvar_knockbackdist = register_cvar("zp_knockback_distance", "500")
  1691.     cvar_nemknockback = register_cvar("zp_knockback_nemesis", "0.25")
  1692.    
  1693.     // CVARS - Leap
  1694.     cvar_leapzombies = register_cvar("zp_leap_zombies", "0")
  1695.     cvar_leapzombiesforce = register_cvar("zp_leap_zombies_force", "500")
  1696.     cvar_leapzombiesheight = register_cvar("zp_leap_zombies_height", "300")
  1697.     cvar_leapzombiescooldown = register_cvar("zp_leap_zombies_cooldown", "5.0")
  1698.     cvar_leapnemesis = register_cvar("zp_leap_nemesis", "1")
  1699.     cvar_leapnemesisforce = register_cvar("zp_leap_nemesis_force", "500")
  1700.     cvar_leapnemesisheight = register_cvar("zp_leap_nemesis_height", "300")
  1701.     cvar_leapnemesiscooldown = register_cvar("zp_leap_nemesis_cooldown", "5.0")
  1702.     cvar_leapsurvivor = register_cvar("zp_leap_survivor", "0")
  1703.     cvar_leapsurvivorforce = register_cvar("zp_leap_survivor_force", "500")
  1704.     cvar_leapsurvivorheight = register_cvar("zp_leap_survivor_height", "300")
  1705.     cvar_leapsurvivorcooldown = register_cvar("zp_leap_survivor_cooldown", "5.0")
  1706.    
  1707.     // CVARS - Humans
  1708.     cvar_humanhp = register_cvar("zp_human_health", "100")
  1709.     cvar_humanlasthp = register_cvar("zp_human_last_extrahp", "0")
  1710.     cvar_humanspd = register_cvar("zp_human_speed", "240")
  1711.     cvar_humangravity = register_cvar("zp_human_gravity", "1.0")
  1712.     cvar_humanarmor = register_cvar("zp_human_armor_protect", "1")
  1713.     cvar_infammo = register_cvar("zp_human_unlimited_ammo", "0")
  1714.     cvar_ammodamage_human = register_cvar("zp_human_damage_reward", "500")
  1715.     cvar_fragskill = register_cvar("zp_human_frags_for_kill", "1")
  1716.    
  1717.     // CVARS - Custom Grenades
  1718.     cvar_firegrenades = register_cvar("zp_fire_grenades", "1")
  1719.     cvar_fireduration = register_cvar("zp_fire_duration", "10")
  1720.     cvar_firedamage = register_cvar("zp_fire_damage", "5")
  1721.     cvar_fireslowdown = register_cvar("zp_fire_slowdown", "0.5")
  1722.     cvar_frostgrenades = register_cvar("zp_frost_grenades", "1")
  1723.     cvar_freezeduration = register_cvar("zp_frost_duration", "3")
  1724.     cvar_flaregrenades = register_cvar("zp_flare_grenades","1")
  1725.     cvar_flareduration = register_cvar("zp_flare_duration", "60")
  1726.     cvar_flaresize = register_cvar("zp_flare_size", "25")
  1727.     cvar_flarecolor = register_cvar("zp_flare_color", "0")
  1728.    
  1729.     // CVARS - Zombies
  1730.     cvar_zombiefirsthp = register_cvar("zp_zombie_first_hp", "2.0")
  1731.     cvar_zombiearmor = register_cvar("zp_zombie_armor", "0.75")
  1732.     cvar_hitzones = register_cvar("zp_zombie_hitzones", "0")
  1733.     cvar_zombiebonushp = register_cvar("zp_zombie_infect_health", "100")
  1734.     cvar_zombiefov = register_cvar("zp_zombie_fov", "110")
  1735.     cvar_zombiesilent = register_cvar("zp_zombie_silent", "1")
  1736.     cvar_zombiepainfree = register_cvar("zp_zombie_painfree", "2")
  1737.     cvar_zombiebleeding = register_cvar("zp_zombie_bleeding", "1")
  1738.     cvar_ammoinfect = register_cvar("zp_zombie_infect_reward", "1")
  1739.     cvar_ammodamage_zombie = register_cvar("zp_zombie_damage_reward", "0")
  1740.     cvar_fragsinfect = register_cvar("zp_zombie_frags_for_infect", "1")
  1741.    
  1742.     // CVARS - Special Effects
  1743.     cvar_infectionscreenfade = register_cvar("zp_infection_screenfade", "1")
  1744.     cvar_infectionscreenshake = register_cvar("zp_infection_screenshake", "1")
  1745.     cvar_infectionsparkle = register_cvar("zp_infection_sparkle", "1")
  1746.     cvar_infectiontracers = register_cvar("zp_infection_tracers", "1")
  1747.     cvar_infectionparticles = register_cvar("zp_infection_particles", "1")
  1748.     cvar_hudicons = register_cvar("zp_hud_icons", "1")
  1749.    
  1750.     // CVARS - Nemesis
  1751.     cvar_nem = register_cvar("zp_nem_enabled", "1")
  1752.     cvar_nemchance = register_cvar("zp_nem_chance", "20")
  1753.     cvar_nemminplayers = register_cvar("zp_nem_min_players", "0")
  1754.     cvar_nemhp = register_cvar("zp_nem_health", "0")
  1755.     cvar_nembasehp = register_cvar("zp_nem_base_health", "0")
  1756.     cvar_nemspd = register_cvar("zp_nem_speed", "250")
  1757.     cvar_nemgravity = register_cvar("zp_nem_gravity", "0.5")
  1758.     cvar_nemdamage = register_cvar("zp_nem_damage", "250")
  1759.     cvar_nemglow = register_cvar("zp_nem_glow", "1")
  1760.     cvar_nemaura = register_cvar("zp_nem_aura", "1")   
  1761.     cvar_nempainfree = register_cvar("zp_nem_painfree", "0")
  1762.     cvar_nemignorefrags = register_cvar("zp_nem_ignore_frags", "1")
  1763.     cvar_nemignoreammo = register_cvar("zp_nem_ignore_rewards", "1")
  1764.    
  1765.     // CVARS - Survivor
  1766.     cvar_surv = register_cvar("zp_surv_enabled", "1")
  1767.     cvar_survchance = register_cvar("zp_surv_chance", "20")
  1768.     cvar_survminplayers = register_cvar("zp_surv_min_players", "0")
  1769.     cvar_survhp = register_cvar("zp_surv_health", "0")
  1770.     cvar_survbasehp = register_cvar("zp_surv_base_health", "0")
  1771.     cvar_survspd = register_cvar("zp_surv_speed", "230")
  1772.     cvar_survgravity = register_cvar("zp_surv_gravity", "1.25")
  1773.     cvar_survglow = register_cvar("zp_surv_glow", "1")
  1774.     cvar_survaura = register_cvar("zp_surv_aura", "1")
  1775.     cvar_survpainfree = register_cvar("zp_surv_painfree", "1")
  1776.     cvar_survignorefrags = register_cvar("zp_surv_ignore_frags", "1")
  1777.     cvar_survignoreammo = register_cvar("zp_surv_ignore_rewards", "1")
  1778.     cvar_survweapon = register_cvar("zp_surv_weapon", "weapon_m249")
  1779.     cvar_survinfammo = register_cvar("zp_surv_unlimited_ammo", "2")
  1780.    
  1781.     // CVARS - Swarm Mode
  1782.     cvar_swarm = register_cvar("zp_swarm_enabled", "1")
  1783.     cvar_swarmchance = register_cvar("zp_swarm_chance", "20")
  1784.     cvar_swarmminplayers = register_cvar("zp_swarm_min_players", "0")
  1785.    
  1786.     // CVARS - Multi Infection
  1787.     cvar_multi = register_cvar("zp_multi_enabled", "1")
  1788.     cvar_multichance = register_cvar("zp_multi_chance", "20")
  1789.     cvar_multiminplayers = register_cvar("zp_multi_min_players", "0")
  1790.     cvar_multiratio = register_cvar("zp_multi_ratio", "0.15")
  1791.    
  1792.     // CVARS - Plague Mode
  1793.     cvar_plague = register_cvar("zp_plague_enabled", "1")
  1794.     cvar_plaguechance = register_cvar("zp_plague_chance", "30")
  1795.     cvar_plagueminplayers = register_cvar("zp_plague_min_players", "0")
  1796.     cvar_plagueratio = register_cvar("zp_plague_ratio", "0.5")
  1797.     cvar_plaguenemnum = register_cvar("zp_plague_nem_number", "1")
  1798.     cvar_plaguenemhpmulti = register_cvar("zp_plague_nem_hp_multi", "0.5")
  1799.     cvar_plaguesurvnum = register_cvar("zp_plague_surv_number", "1")
  1800.     cvar_plaguesurvhpmulti = register_cvar("zp_plague_surv_hp_multi", "0.5")
  1801.    
  1802.     // CVARS - Others
  1803.     cvar_logcommands = register_cvar("zp_logcommands", "1")
  1804.     cvar_showactivity = get_cvar_pointer("amx_show_activity")
  1805.     cvar_botquota = get_cvar_pointer("bot_quota")
  1806.     register_cvar("zp_version", PLUGIN_VERSION, FCVAR_SERVER|FCVAR_SPONLY)
  1807.     set_cvar_string("zp_version", PLUGIN_VERSION)
  1808.    
  1809.     // Custom Forwards
  1810.     g_fwRoundStart = CreateMultiForward("zp_round_started", ET_IGNORE, FP_CELL, FP_CELL)
  1811.     g_fwRoundEnd = CreateMultiForward("zp_round_ended", ET_IGNORE, FP_CELL)
  1812.     g_fwUserInfected_pre = CreateMultiForward("zp_user_infected_pre", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
  1813.     g_fwUserInfected_post = CreateMultiForward("zp_user_infected_post", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
  1814.     g_fwUserHumanized_pre = CreateMultiForward("zp_user_humanized_pre", ET_IGNORE, FP_CELL, FP_CELL)
  1815.     g_fwUserHumanized_post = CreateMultiForward("zp_user_humanized_post", ET_IGNORE, FP_CELL, FP_CELL)
  1816.     g_fwUserInfect_attempt = CreateMultiForward("zp_user_infect_attempt", ET_CONTINUE, FP_CELL, FP_CELL, FP_CELL)
  1817.     g_fwUserHumanize_attempt = CreateMultiForward("zp_user_humanize_attempt", ET_CONTINUE, FP_CELL, FP_CELL)
  1818.     g_fwExtraItemSelected = CreateMultiForward("zp_extra_item_selected", ET_CONTINUE, FP_CELL, FP_CELL)
  1819.     g_fwUserUnfrozen = CreateMultiForward("zp_user_unfrozen", ET_IGNORE, FP_CELL)
  1820.     g_fwUserLastZombie = CreateMultiForward("zp_user_last_zombie", ET_IGNORE, FP_CELL)
  1821.     g_fwUserLastHuman = CreateMultiForward("zp_user_last_human", ET_IGNORE, FP_CELL)
  1822.    
  1823.     // Collect random spawn points
  1824.     load_spawns()
  1825.    
  1826.     // Set a random skybox?
  1827.     if (g_sky_enable)
  1828.     {
  1829.         new sky[32]
  1830.         ArrayGetString(g_sky_names, random_num(0, ArraySize(g_sky_names) - 1), sky, charsmax(sky))
  1831.         set_cvar_string("sv_skyname", sky)
  1832.     }
  1833.    
  1834.     // Disable sky lighting so it doesn't mess with our custom lighting
  1835.     set_cvar_num("sv_skycolor_r", 0)
  1836.     set_cvar_num("sv_skycolor_g", 0)
  1837.     set_cvar_num("sv_skycolor_b", 0)
  1838.    
  1839.     // Create the HUD Sync Objects
  1840.     g_MsgSync = CreateHudSyncObj()
  1841.     g_MsgSync2 = CreateHudSyncObj()
  1842.    
  1843.     // Format mod name
  1844.     formatex(g_modname, charsmax(g_modname), "Zombie Plague %s", PLUGIN_VERSION)
  1845.    
  1846.     // Get Max Players
  1847.     g_maxplayers = get_maxplayers()
  1848.    
  1849.     // Reserved saving slots starts on maxplayers+1
  1850.     db_slot_i = g_maxplayers+1
  1851.    
  1852.     // Check if it's a CZ server
  1853.     new mymod[6]
  1854.     get_modname(mymod, charsmax(mymod))
  1855.     if (equal(mymod, "czero")) g_czero = 1
  1856. }
  1857.  
  1858. public plugin_cfg()
  1859. {
  1860.     // Plugin disabled?
  1861.     if (!g_pluginenabled) return;
  1862.    
  1863.     // Get configs dir
  1864.     new cfgdir[32]
  1865.     get_configsdir(cfgdir, charsmax(cfgdir))
  1866.    
  1867.     // Execute config file (zombieplague.cfg)
  1868.     server_cmd("exec %s/zombieplague.cfg", cfgdir)
  1869.    
  1870.     // Prevent any more stuff from registering
  1871.     g_arrays_created = false
  1872.    
  1873.     // Save customization data
  1874.     save_customization()
  1875.    
  1876.     // Lighting task
  1877.     set_task(5.0, "lighting_effects", _, _, _, "b")
  1878.    
  1879.     // Cache CVARs after configs are loaded / call roundstart manually
  1880.     set_task(0.5, "cache_cvars")
  1881.     set_task(0.5, "event_round_start")
  1882.     set_task(0.5, "logevent_round_start")
  1883. }
  1884.  
  1885. /*================================================================================
  1886.  [Main Events]
  1887. =================================================================================*/
  1888.  
  1889. // Event Round Start
  1890. public event_round_start()
  1891. {
  1892.     // Remove doors/lights?
  1893.     set_task(0.1, "remove_stuff")
  1894.    
  1895.     // New round starting
  1896.     g_newround = true
  1897.     g_endround = false
  1898.     g_survround = false
  1899.     g_nemround = false
  1900.     g_swarmround = false
  1901.     g_plagueround = false
  1902.     g_modestarted = false
  1903.    
  1904.     // Reset bought infection bombs counter
  1905.     g_infbombcounter = 0
  1906.     g_antidotecounter = 0
  1907.     g_madnesscounter = 0
  1908.    
  1909.     // Freezetime begins
  1910.     g_freezetime = true
  1911.    
  1912.     // Show welcome message and T-Virus notice
  1913.     remove_task(TASK_WELCOMEMSG)
  1914.     set_task(2.0, "welcome_msg", TASK_WELCOMEMSG)
  1915.    
  1916.     // Set a new "Make Zombie Task"
  1917.     remove_task(TASK_MAKEZOMBIE)
  1918.     set_task(2.0 + get_pcvar_float(cvar_warmup), "make_zombie_task", TASK_MAKEZOMBIE)
  1919. }
  1920.  
  1921. // Log Event Round Start
  1922. public logevent_round_start()
  1923. {
  1924.     // Freezetime ends
  1925.     g_freezetime = false
  1926. }
  1927.  
  1928. // Log Event Round End
  1929. public logevent_round_end()
  1930. {
  1931.     // Prevent this from getting called twice when restarting (bugfix)
  1932.     static Float:lastendtime, Float:current_time
  1933.     current_time = get_gametime()
  1934.     if (current_time - lastendtime < 0.5) return;
  1935.     lastendtime = current_time
  1936.    
  1937.     // Temporarily save player stats?
  1938.     if (get_pcvar_num(cvar_statssave))
  1939.     {
  1940.         static id, team
  1941.         for (id = 1; id <= g_maxplayers; id++)
  1942.         {
  1943.             // Not connected
  1944.             if (!g_isconnected[id])
  1945.                 continue;
  1946.            
  1947.             team = fm_cs_get_user_team(id)
  1948.            
  1949.             // Not playing
  1950.             if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  1951.                 continue;
  1952.            
  1953.             save_stats(id)
  1954.         }
  1955.     }
  1956.    
  1957.     // Round ended
  1958.     g_endround = true
  1959.    
  1960.     // Stop old tasks (if any)
  1961.     remove_task(TASK_WELCOMEMSG)
  1962.     remove_task(TASK_MAKEZOMBIE)
  1963.    
  1964.     // Stop ambience sounds
  1965.     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))
  1966.     {
  1967.         remove_task(TASK_AMBIENCESOUNDS)
  1968.         ambience_sound_stop()
  1969.     }
  1970.    
  1971.     // Show HUD notice, play win sound, update team scores...
  1972.     static sound[64]
  1973.     if (!fnGetZombies())
  1974.     {
  1975.         // Human team wins
  1976.         set_hudmessage(0, 0, 200, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  1977.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_HUMAN")
  1978.        
  1979.         // Play win sound and increase score, unless game commencing
  1980.         ArrayGetString(sound_win_humans, random_num(0, ArraySize(sound_win_humans) - 1), sound, charsmax(sound))
  1981.         PlaySound(sound)
  1982.         if (!g_gamecommencing) g_scorehumans++
  1983.        
  1984.         // Round end forward
  1985.         ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_HUMAN);
  1986.     }
  1987.     else if (!fnGetHumans())
  1988.     {
  1989.         // Zombie team wins
  1990.         set_hudmessage(200, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  1991.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_ZOMBIE")
  1992.        
  1993.         // Play win sound and increase score, unless game commencing
  1994.         ArrayGetString(sound_win_zombies, random_num(0, ArraySize(sound_win_zombies) - 1), sound, charsmax(sound))
  1995.         PlaySound(sound)
  1996.         if (!g_gamecommencing) g_scorezombies++
  1997.        
  1998.         // Round end forward
  1999.         ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_ZOMBIE);
  2000.     }
  2001.     else
  2002.     {
  2003.         // No one wins
  2004.         set_hudmessage(0, 200, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  2005.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_NO_ONE")
  2006.        
  2007.         // Play win sound
  2008.         ArrayGetString(sound_win_no_one, random_num(0, ArraySize(sound_win_no_one) - 1), sound, charsmax(sound))
  2009.         PlaySound(sound)
  2010.        
  2011.         // Round end forward
  2012.         ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_NO_ONE);
  2013.     }
  2014.    
  2015.     // Game commencing triggers round end
  2016.     g_gamecommencing = false
  2017.    
  2018.     // Balance the teams
  2019.     balance_teams()
  2020. }
  2021.  
  2022. // Event Map Ended
  2023. public event_intermission()
  2024. {
  2025.     // Remove ambience sounds task
  2026.     remove_task(TASK_AMBIENCESOUNDS)
  2027. }
  2028.  
  2029. // BP Ammo update
  2030. public event_ammo_x(id)
  2031. {
  2032.     // Humans only
  2033.     if (g_zombie[id])
  2034.         return;
  2035.    
  2036.     // Get ammo type
  2037.     static type
  2038.     type = read_data(1)
  2039.    
  2040.     // Unknown ammo type
  2041.     if (type >= sizeof AMMOWEAPON)
  2042.         return;
  2043.    
  2044.     // Get weapon's id
  2045.     static weapon
  2046.     weapon = AMMOWEAPON[type]
  2047.    
  2048.     // Primary and secondary only
  2049.     if (MAXBPAMMO[weapon] <= 2)
  2050.         return;
  2051.    
  2052.     // Get ammo amount
  2053.     static amount
  2054.     amount = read_data(2)
  2055.    
  2056.     // Unlimited BP Ammo?
  2057.     if (g_survivor[id] ? get_pcvar_num(cvar_survinfammo) : get_pcvar_num(cvar_infammo))
  2058.     {
  2059.         if (amount < MAXBPAMMO[weapon])
  2060.         {
  2061.             // The BP Ammo refill code causes the engine to send a message, but we
  2062.             // can't have that in this forward or we risk getting some recursion bugs.
  2063.             // For more info see: https://bugs.alliedmods.net/show_bug.cgi?id=3664
  2064.             static args[1]
  2065.             args[0] = weapon
  2066.             set_task(0.1, "refill_bpammo", id, args, sizeof args)
  2067.         }
  2068.     }
  2069.     // Bots automatically buy ammo when needed
  2070.     else if (g_isbot[id] && amount <= BUYAMMO[weapon])
  2071.     {
  2072.         // Task needed for the same reason as above
  2073.         set_task(0.1, "clcmd_buyammo", id)
  2074.     }
  2075. }
  2076.  
  2077. /*================================================================================
  2078.  [Main Forwards]
  2079. =================================================================================*/
  2080.  
  2081. // Entity Spawn Forward
  2082. public fw_Spawn(entity)
  2083. {
  2084.     // Invalid entity
  2085.     if (!pev_valid(entity)) return FMRES_IGNORED;
  2086.    
  2087.     // Get classname
  2088.     new classname[32], objective[32], size = ArraySize(g_objective_ents)
  2089.     pev(entity, pev_classname, classname, charsmax(classname))
  2090.    
  2091.     // Check whether it needs to be removed
  2092.     for (new i = 0; i < size; i++)
  2093.     {
  2094.         ArrayGetString(g_objective_ents, i, objective, charsmax(objective))
  2095.        
  2096.         if (equal(classname, objective))
  2097.         {
  2098.             engfunc(EngFunc_RemoveEntity, entity)
  2099.             return FMRES_SUPERCEDE;
  2100.         }
  2101.     }
  2102.    
  2103.     return FMRES_IGNORED;
  2104. }
  2105.  
  2106. // Sound Precache Forward
  2107. public fw_PrecacheSound(const sound[])
  2108. {
  2109.     // Block all those unneeeded hostage sounds
  2110.     if (equal(sound, "hostage", 7))
  2111.         return FMRES_SUPERCEDE;
  2112.    
  2113.     return FMRES_IGNORED;
  2114. }
  2115.  
  2116. // Ham Player Spawn Post Forward
  2117. public fw_PlayerSpawn_Post(id)
  2118. {
  2119.     // Not alive or didn't join a team yet
  2120.     if (!is_user_alive(id) || !fm_cs_get_user_team(id))
  2121.         return;
  2122.    
  2123.     // Player spawned
  2124.     g_isalive[id] = true
  2125.    
  2126.     // Remove previous tasks
  2127.     remove_task(id+TASK_SPAWN)
  2128.     remove_task(id+TASK_MODEL)
  2129.     remove_task(id+TASK_BLOOD)
  2130.     remove_task(id+TASK_AURA)
  2131.     remove_task(id+TASK_BURN)
  2132.     remove_task(id+TASK_CHARGE)
  2133.     remove_task(id+TASK_FLASH)
  2134.     remove_task(id+TASK_NVISION)
  2135.    
  2136.     // Spawn at a random location?
  2137.     if (get_pcvar_num(cvar_randspawn)) do_random_spawn(id)
  2138.    
  2139.     // Hide money?
  2140.     if (get_pcvar_num(cvar_removemoney))
  2141.         set_task(0.4, "task_hide_money", id+TASK_SPAWN)
  2142.    
  2143.     // Respawn player if he dies because of a worldspawn kill?
  2144.     if (get_pcvar_num(cvar_respawnworldspawnkill))
  2145.         set_task(2.0, "respawn_player_check_task", id+TASK_SPAWN)
  2146.    
  2147.     // Spawn as zombie?
  2148.     if (g_respawn_as_zombie[id] && !g_newround)
  2149.     {
  2150.         reset_vars(id, 0) // reset player vars
  2151.         zombieme(id, 0, 0, 0, 0) // make him zombie right away
  2152.         return;
  2153.     }
  2154.    
  2155.     // Reset player vars
  2156.     reset_vars(id, 0)
  2157.     g_buytime[id] = get_gametime()
  2158.    
  2159.     // Show custom buy menu?
  2160.     if (get_pcvar_num(cvar_buycustom))
  2161.         set_task(0.2, "show_menu_buy1", id+TASK_SPAWN)
  2162.    
  2163.     // Set health and gravity
  2164.     fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
  2165.     set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
  2166.    
  2167.     // Set human maxspeed
  2168.     ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  2169.    
  2170.     // Switch to CT if spawning mid-round
  2171.     if (!g_newround && fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  2172.     {
  2173.         remove_task(id+TASK_TEAM)
  2174.         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  2175.         fm_user_team_update(id)
  2176.     }
  2177.    
  2178.     // Custom models stuff
  2179.     static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  2180.     already_has_model = false
  2181.    
  2182.     if (g_handle_models_on_separate_ent)
  2183.     {
  2184.         // Set the right model
  2185.         if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  2186.         {
  2187.             iRand = random_num(0, ArraySize(model_admin_human) - 1)
  2188.             ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2189.             if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  2190.         }
  2191.         else
  2192.         {
  2193.             iRand = random_num(0, ArraySize(model_human) - 1)
  2194.             ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2195.             if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  2196.         }
  2197.        
  2198.         // Set model on player model entity
  2199.         fm_set_playermodel_ent(id)
  2200.        
  2201.         // Remove glow on player model entity
  2202.         fm_set_rendering(g_ent_playermodel[id])
  2203.     }
  2204.     else
  2205.     {
  2206.         // Get current model for comparing it with the current one
  2207.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  2208.        
  2209.         // Set the right model, after checking that we don't already have it
  2210.         if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  2211.         {
  2212.             size = ArraySize(model_admin_human)
  2213.             for (i = 0; i < size; i++)
  2214.             {
  2215.                 ArrayGetString(model_admin_human, i, tempmodel, charsmax(tempmodel))
  2216.                 if (equal(currentmodel, tempmodel)) already_has_model = true
  2217.             }
  2218.            
  2219.             if (!already_has_model)
  2220.             {
  2221.                 iRand = random_num(0, size - 1)
  2222.                 ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2223.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  2224.             }
  2225.         }
  2226.         else
  2227.         {
  2228.             size = ArraySize(model_human)
  2229.             for (i = 0; i < size; i++)
  2230.             {
  2231.                 ArrayGetString(model_human, i, tempmodel, charsmax(tempmodel))
  2232.                 if (equal(currentmodel, tempmodel)) already_has_model = true
  2233.             }
  2234.            
  2235.             if (!already_has_model)
  2236.             {
  2237.                 iRand = random_num(0, size - 1)
  2238.                 ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  2239.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  2240.             }
  2241.         }
  2242.        
  2243.         // Need to change the model?
  2244.         if (!already_has_model)
  2245.         {
  2246.             // An additional delay is offset at round start
  2247.             // since SVC_BAD is more likely to be triggered there
  2248.             if (g_newround)
  2249.                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  2250.             else
  2251.                 fm_user_model_update(id+TASK_MODEL)
  2252.         }
  2253.        
  2254.         // Remove glow
  2255.         fm_set_rendering(id)
  2256.     }
  2257.    
  2258.     // Bots stuff
  2259.     if (g_isbot[id])
  2260.     {
  2261.         // Turn off NVG for bots
  2262.         cs_set_user_nvg(id, 0)
  2263.        
  2264.         // Automatically buy extra items/weapons after first zombie is chosen
  2265.         if (get_pcvar_num(cvar_extraitems))
  2266.         {
  2267.             if (g_newround) set_task(10.0 + get_pcvar_float(cvar_warmup), "bot_buy_extras", id+TASK_SPAWN)
  2268.             else set_task(10.0, "bot_buy_extras", id+TASK_SPAWN)
  2269.         }
  2270.     }
  2271.    
  2272.     // Enable spawn protection for humans spawning mid-round
  2273.     if (!g_newround && get_pcvar_float(cvar_spawnprotection) > 0.0)
  2274.     {
  2275.         // Do not take damage
  2276.         g_nodamage[id] = true
  2277.        
  2278.         // Make temporarily invisible
  2279.         set_pev(id, pev_effects, pev(id, pev_effects) | EF_NODRAW)
  2280.        
  2281.         // Set task to remove it
  2282.         set_task(get_pcvar_float(cvar_spawnprotection), "remove_spawn_protection", id+TASK_SPAWN)
  2283.     }
  2284.    
  2285.     // Turn off his flashlight (prevents double flashlight bug/exploit)
  2286.     turn_off_flashlight(id)
  2287.    
  2288.     // Set the flashlight charge task to update battery status
  2289.     if (g_cached_customflash)
  2290.         set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
  2291.    
  2292.     // Replace weapon models (bugfix)
  2293.     static weapon_ent
  2294.     weapon_ent = fm_cs_get_current_weapon_ent(id)
  2295.     if (pev_valid(weapon_ent)) replace_weapon_models(id, cs_get_weapon_id(weapon_ent))
  2296.    
  2297.     // Last Zombie Check
  2298.     fnCheckLastZombie()
  2299. }
  2300.  
  2301. // Ham Player Killed Forward
  2302. public fw_PlayerKilled(victim, attacker, shouldgib)
  2303. {
  2304.     // Player killed
  2305.     g_isalive[victim] = false
  2306.     // Disable nodamage mode after we die to prevent spectator nightvision using zombie madness colors bug
  2307.     g_nodamage[victim] = false
  2308.    
  2309.     // Enable dead players nightvision
  2310.     set_task(0.1, "spec_nvision", victim)
  2311.    
  2312.     // Disable nightvision when killed (bugfix)
  2313.     if (get_pcvar_num(cvar_nvggive) == 0 && g_nvision[victim])
  2314.     {
  2315.         if (get_pcvar_num(cvar_customnvg)) remove_task(victim+TASK_NVISION)
  2316.         else if (g_nvisionenabled[victim]) set_user_gnvision(victim, 0)
  2317.         g_nvision[victim] = false
  2318.         g_nvisionenabled[victim] = false
  2319.     }
  2320.    
  2321.     // Turn off nightvision when killed (bugfix)
  2322.     if (get_pcvar_num(cvar_nvggive) == 2 && g_nvision[victim] && g_nvisionenabled[victim])
  2323.     {
  2324.         if (get_pcvar_num(cvar_customnvg)) remove_task(victim+TASK_NVISION)
  2325.         else set_user_gnvision(victim, 0)
  2326.         g_nvisionenabled[victim] = false
  2327.     }
  2328.    
  2329.     // Turn off custom flashlight when killed
  2330.     if (g_cached_customflash)
  2331.     {
  2332.         // Turn it off
  2333.         g_flashlight[victim] = false
  2334.         g_flashbattery[victim] = 100
  2335.        
  2336.         // Remove previous tasks
  2337.         remove_task(victim+TASK_CHARGE)
  2338.         remove_task(victim+TASK_FLASH)
  2339.     }
  2340.    
  2341.     // Stop bleeding/burning/aura when killed
  2342.     if (g_zombie[victim])
  2343.     {
  2344.         remove_task(victim+TASK_BLOOD)
  2345.         remove_task(victim+TASK_AURA)
  2346.         remove_task(victim+TASK_BURN)
  2347.     }
  2348.    
  2349.     // Nemesis explodes!
  2350.     if (g_nemesis[victim])
  2351.         SetHamParamInteger(3, 2)
  2352.    
  2353.     // Determine whether the player killed himself
  2354.     static selfkill
  2355.     selfkill = (victim == attacker || !is_user_valid_connected(attacker)) ? true : false
  2356.    
  2357.     // Killed by a non-player entity or self killed
  2358.     if (selfkill) return;
  2359.    
  2360.     // Ignore Nemesis/Survivor Frags?
  2361.     if ((g_nemesis[attacker] && get_pcvar_num(cvar_nemignorefrags)) || (g_survivor[attacker] && get_pcvar_num(cvar_survignorefrags)))
  2362.         RemoveFrags(attacker, victim)
  2363.    
  2364.     // Zombie/nemesis killed human, reward ammo packs
  2365.     if (g_zombie[attacker] && (!g_nemesis[attacker] || !get_pcvar_num(cvar_nemignoreammo)))
  2366.         g_ammopacks[attacker] += get_pcvar_num(cvar_ammoinfect)
  2367.    
  2368.     // Human killed zombie, add up the extra frags for kill
  2369.     if (!g_zombie[attacker] && get_pcvar_num(cvar_fragskill) > 1)
  2370.         UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragskill) - 1, 0, 0)
  2371.    
  2372.     // Zombie killed human, add up the extra frags for kill
  2373.     if (g_zombie[attacker] && get_pcvar_num(cvar_fragsinfect) > 1)
  2374.         UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragsinfect) - 1, 0, 0)
  2375. }
  2376.  
  2377. // Ham Player Killed Post Forward
  2378. public fw_PlayerKilled_Post(victim, attacker, shouldgib)
  2379. {
  2380.     // Last Zombie Check
  2381.     fnCheckLastZombie()
  2382.    
  2383.     // Determine whether the player killed himself
  2384.     static selfkill
  2385.     selfkill = (victim == attacker || !is_user_valid_connected(attacker)) ? true : false
  2386.    
  2387.     // Respawn if deathmatch is enabled
  2388.     if (get_pcvar_num(cvar_deathmatch))
  2389.     {
  2390.         // Respawn on suicide?
  2391.         if (selfkill && !get_pcvar_num(cvar_respawnonsuicide))
  2392.             return;
  2393.        
  2394.         // Respawn if human/zombie/nemesis/survivor?
  2395.         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)))
  2396.             return;
  2397.        
  2398.         // Set the respawn task
  2399.         set_task(get_pcvar_float(cvar_spawndelay), "respawn_player_task", victim+TASK_SPAWN)
  2400.     }
  2401. }
  2402.  
  2403. // Ham Take Damage Forward
  2404. public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type)
  2405. {
  2406.     // Non-player damage or self damage
  2407.     if (victim == attacker || !is_user_valid_connected(attacker))
  2408.         return HAM_IGNORED;
  2409.    
  2410.     // New round starting or round ended
  2411.     if (g_newround || g_endround)
  2412.         return HAM_SUPERCEDE;
  2413.    
  2414.     // Victim shouldn't take damage or victim is frozen
  2415.     if (g_nodamage[victim] || g_frozen[victim])
  2416.         return HAM_SUPERCEDE;
  2417.    
  2418.     // Prevent friendly fire
  2419.     if (g_zombie[attacker] == g_zombie[victim])
  2420.         return HAM_SUPERCEDE;
  2421.    
  2422.     // Attacker is human...
  2423.     if (!g_zombie[attacker])
  2424.     {
  2425.         // Armor multiplier for the final damage on normal zombies
  2426.         if (!g_nemesis[victim])
  2427.         {
  2428.             damage *= get_pcvar_float(cvar_zombiearmor)
  2429.             SetHamParamFloat(4, damage)
  2430.         }
  2431.        
  2432.         // Reward ammo packs to humans for damaging zombies?
  2433.         if ((get_pcvar_num(cvar_ammodamage_human) > 0) && (!g_survivor[attacker] || !get_pcvar_num(cvar_survignoreammo)))
  2434.         {
  2435.             // Store damage dealt
  2436.             g_damagedealt_human[attacker] += floatround(damage)
  2437.            
  2438.             // Reward ammo packs for every [ammo damage] dealt
  2439.             while (g_damagedealt_human[attacker] > get_pcvar_num(cvar_ammodamage_human))
  2440.             {
  2441.                 g_ammopacks[attacker]++
  2442.                 g_damagedealt_human[attacker] -= get_pcvar_num(cvar_ammodamage_human)
  2443.             }
  2444.         }
  2445.        
  2446.         return HAM_IGNORED;
  2447.     }
  2448.    
  2449.     // Attacker is zombie...
  2450.    
  2451.     // Prevent infection/damage by HE grenade (bugfix)
  2452.     if (damage_type & DMG_HEGRENADE)
  2453.         return HAM_SUPERCEDE;
  2454.    
  2455.     // Nemesis?
  2456.     if (g_nemesis[attacker])
  2457.     {
  2458.         // Ignore nemesis damage override if damage comes from a 3rd party entity
  2459.         // (to prevent this from affecting a sub-plugin's rockets e.g.)
  2460.         if (inflictor == attacker)
  2461.         {
  2462.             // Set nemesis damage
  2463.             SetHamParamFloat(4, get_pcvar_float(cvar_nemdamage))
  2464.         }
  2465.        
  2466.         return HAM_IGNORED;
  2467.     }
  2468.    
  2469.     // Reward ammo packs to zombies for damaging humans?
  2470.     if (get_pcvar_num(cvar_ammodamage_zombie) > 0)
  2471.     {
  2472.         // Store damage dealt
  2473.         g_damagedealt_zombie[attacker] += floatround(damage)
  2474.        
  2475.         // Reward ammo packs for every [ammo damage] dealt
  2476.         while (g_damagedealt_zombie[attacker] > get_pcvar_num(cvar_ammodamage_zombie))
  2477.         {
  2478.             g_ammopacks[attacker]++
  2479.             g_damagedealt_zombie[attacker] -= get_pcvar_num(cvar_ammodamage_zombie)
  2480.         }
  2481.     }
  2482.    
  2483.     // Last human or not an infection round
  2484.     if (g_survround || g_nemround || g_swarmround || g_plagueround || fnGetHumans() == 1)
  2485.         return HAM_IGNORED; // human is killed
  2486.    
  2487.     // Does human armor need to be reduced before infecting?
  2488.     if (get_pcvar_num(cvar_humanarmor))
  2489.     {
  2490.         // Get victim armor
  2491.         static Float:armor
  2492.         pev(victim, pev_armorvalue, armor)
  2493.        
  2494.         // If he has some, block the infection and reduce armor instead
  2495.         if (armor > 0.0)
  2496.         {
  2497.             emit_sound(victim, CHAN_BODY, sound_armorhit, 1.0, ATTN_NORM, 0, PITCH_NORM)
  2498.             if (armor - damage > 0.0)
  2499.                 set_pev(victim, pev_armorvalue, armor - damage)
  2500.             else
  2501.                 cs_set_user_armor(victim, 0, CS_ARMOR_NONE)
  2502.             return HAM_SUPERCEDE;
  2503.         }
  2504.     }
  2505.    
  2506.     // Infection allowed
  2507.     zombieme(victim, attacker, 0, 0, 1) // turn into zombie
  2508.     return HAM_SUPERCEDE;
  2509. }
  2510.  
  2511. // Ham Take Damage Post Forward
  2512. public fw_TakeDamage_Post(victim)
  2513. {
  2514.     // --- Check if victim should be Pain Shock Free ---
  2515.    
  2516.     // Check if proper CVARs are enabled
  2517.     if (g_zombie[victim])
  2518.     {
  2519.         if (g_nemesis[victim])
  2520.         {
  2521.             if (!get_pcvar_num(cvar_nempainfree)) return;
  2522.         }
  2523.         else
  2524.         {
  2525.             switch (get_pcvar_num(cvar_zombiepainfree))
  2526.             {
  2527.                 case 0: return;
  2528.                 case 2: if (!g_lastzombie[victim]) return;
  2529.                 case 3: if (!g_firstzombie[victim]) return;
  2530.             }
  2531.         }
  2532.     }
  2533.     else
  2534.     {
  2535.         if (g_survivor[victim])
  2536.         {
  2537.             if (!get_pcvar_num(cvar_survpainfree)) return;
  2538.         }
  2539.         else return;
  2540.     }
  2541.    
  2542.     // Prevent server crash if entity's private data not initalized
  2543.     if (pev_valid(victim) != PDATA_SAFE)
  2544.         return;
  2545.    
  2546.     // Set pain shock free offset
  2547.     set_pdata_float(victim, OFFSET_PAINSHOCK, 1.0, OFFSET_LINUX)
  2548. }
  2549.  
  2550. // Ham Trace Attack Forward
  2551. public fw_TraceAttack(victim, attacker, Float:damage, Float:direction[3], tracehandle, damage_type)
  2552. {
  2553.     // Non-player damage or self damage
  2554.     if (victim == attacker || !is_user_valid_connected(attacker))
  2555.         return HAM_IGNORED;
  2556.    
  2557.     // New round starting or round ended
  2558.     if (g_newround || g_endround)
  2559.         return HAM_SUPERCEDE;
  2560.    
  2561.     // Victim shouldn't take damage or victim is frozen
  2562.     if (g_nodamage[victim] || g_frozen[victim])
  2563.         return HAM_SUPERCEDE;
  2564.    
  2565.     // Prevent friendly fire
  2566.     if (g_zombie[attacker] == g_zombie[victim])
  2567.         return HAM_SUPERCEDE;
  2568.    
  2569.     // Victim isn't a zombie or not bullet damage, nothing else to do here
  2570.     if (!g_zombie[victim] || !(damage_type & DMG_BULLET))
  2571.         return HAM_IGNORED;
  2572.    
  2573.     // If zombie hitzones are enabled, check whether we hit an allowed one
  2574.     if (get_pcvar_num(cvar_hitzones) && !g_nemesis[victim] && !(get_pcvar_num(cvar_hitzones) & (1<<get_tr2(tracehandle, TR_iHitgroup))))
  2575.         return HAM_SUPERCEDE;
  2576.    
  2577.     // Knockback disabled, nothing else to do here
  2578.     if (!get_pcvar_num(cvar_knockback))
  2579.         return HAM_IGNORED;
  2580.    
  2581.     // Nemesis knockback disabled, nothing else to do here
  2582.     if (g_nemesis[victim] && get_pcvar_float(cvar_nemknockback) == 0.0)
  2583.         return HAM_IGNORED;
  2584.    
  2585.     // Get whether the victim is in a crouch state
  2586.     static ducking
  2587.     ducking = pev(victim, pev_flags) & (FL_DUCKING | FL_ONGROUND) == (FL_DUCKING | FL_ONGROUND)
  2588.    
  2589.     // Zombie knockback when ducking disabled
  2590.     if (ducking && get_pcvar_float(cvar_knockbackducking) == 0.0)
  2591.         return HAM_IGNORED;
  2592.    
  2593.     // Get distance between players
  2594.     static origin1[3], origin2[3]
  2595.     get_user_origin(victim, origin1)
  2596.     get_user_origin(attacker, origin2)
  2597.    
  2598.     // Max distance exceeded
  2599.     if (get_distance(origin1, origin2) > get_pcvar_num(cvar_knockbackdist))
  2600.         return HAM_IGNORED;
  2601.    
  2602.     // Get victim's velocity
  2603.     static Float:velocity[3]
  2604.     pev(victim, pev_velocity, velocity)
  2605.    
  2606.     // Use damage on knockback calculation
  2607.     if (get_pcvar_num(cvar_knockbackdamage))
  2608.         xs_vec_mul_scalar(direction, damage, direction)
  2609.    
  2610.     // Use weapon power on knockback calculation
  2611.     if (get_pcvar_num(cvar_knockbackpower) && kb_weapon_power[g_currentweapon[attacker]] > 0.0)
  2612.         xs_vec_mul_scalar(direction, kb_weapon_power[g_currentweapon[attacker]], direction)
  2613.    
  2614.     // Apply ducking knockback multiplier
  2615.     if (ducking)
  2616.         xs_vec_mul_scalar(direction, get_pcvar_float(cvar_knockbackducking), direction)
  2617.    
  2618.     // Apply zombie class/nemesis knockback multiplier
  2619.     if (g_nemesis[victim])
  2620.         xs_vec_mul_scalar(direction, get_pcvar_float(cvar_nemknockback), direction)
  2621.     else
  2622.         xs_vec_mul_scalar(direction, g_zombie_knockback[victim], direction)
  2623.    
  2624.     // Add up the new vector
  2625.     xs_vec_add(velocity, direction, direction)
  2626.    
  2627.     // Should knockback also affect vertical velocity?
  2628.     if (!get_pcvar_num(cvar_knockbackzvel))
  2629.         direction[2] = velocity[2]
  2630.    
  2631.     // Set the knockback'd victim's velocity
  2632.     set_pev(victim, pev_velocity, direction)
  2633.    
  2634.     return HAM_IGNORED;
  2635. }
  2636.  
  2637. // Ham Reset MaxSpeed Post Forward
  2638. public fw_ResetMaxSpeed_Post(id)
  2639. {
  2640.     // Freezetime active or player not alive
  2641.     if (g_freezetime || !g_isalive[id])
  2642.         return;
  2643.    
  2644.     set_player_maxspeed(id)
  2645. }
  2646.  
  2647. // Ham Use Stationary Gun Forward
  2648. public fw_UseStationary(entity, caller, activator, use_type)
  2649. {
  2650.     // Prevent zombies from using stationary guns
  2651.     if (use_type == USE_USING && is_user_valid_connected(caller) && g_zombie[caller])
  2652.         return HAM_SUPERCEDE;
  2653.    
  2654.     return HAM_IGNORED;
  2655. }
  2656.  
  2657. // Ham Use Stationary Gun Post Forward
  2658. public fw_UseStationary_Post(entity, caller, activator, use_type)
  2659. {
  2660.     // Someone stopped using a stationary gun
  2661.     if (use_type == USE_STOPPED && is_user_valid_connected(caller))
  2662.         replace_weapon_models(caller, g_currentweapon[caller]) // replace weapon models (bugfix)
  2663. }
  2664.  
  2665. // Ham Use Pushable Forward
  2666. public fw_UsePushable()
  2667. {
  2668.     // Prevent speed bug with pushables?
  2669.     if (get_pcvar_num(cvar_blockpushables))
  2670.         return HAM_SUPERCEDE;
  2671.    
  2672.     return HAM_IGNORED;
  2673. }
  2674.  
  2675. // Ham Weapon Touch Forward
  2676. public fw_TouchWeapon(weapon, id)
  2677. {
  2678.     // Not a player
  2679.     if (!is_user_valid_connected(id))
  2680.         return HAM_IGNORED;
  2681.    
  2682.     // Dont pickup weapons if zombie or survivor (+PODBot MM fix)
  2683.     if (g_zombie[id] || (g_survivor[id] && !g_isbot[id]))
  2684.         return HAM_SUPERCEDE;
  2685.    
  2686.     return HAM_IGNORED;
  2687. }
  2688.  
  2689. // Ham Weapon Pickup Forward
  2690. public fw_AddPlayerItem(id, weapon_ent)
  2691. {
  2692.     // HACK: Retrieve our custom extra ammo from the weapon
  2693.     static extra_ammo
  2694.     extra_ammo = pev(weapon_ent, PEV_ADDITIONAL_AMMO)
  2695.    
  2696.     // If present
  2697.     if (extra_ammo)
  2698.     {
  2699.         // Get weapon's id
  2700.         static weaponid
  2701.         weaponid = cs_get_weapon_id(weapon_ent)
  2702.        
  2703.         // Add to player's bpammo
  2704.         ExecuteHamB(Ham_GiveAmmo, id, extra_ammo, AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  2705.         set_pev(weapon_ent, PEV_ADDITIONAL_AMMO, 0)
  2706.     }
  2707. }
  2708.  
  2709. // Ham Weapon Deploy Forward
  2710. public fw_Item_Deploy_Post(weapon_ent)
  2711. {
  2712.     // Get weapon's owner
  2713.     static owner
  2714.     owner = fm_cs_get_weapon_ent_owner(weapon_ent)
  2715.    
  2716.     // Valid owner?
  2717.     if (!pev_valid(owner))
  2718.         return;
  2719.    
  2720.     // Get weapon's id
  2721.     static weaponid
  2722.     weaponid = cs_get_weapon_id(weapon_ent)
  2723.    
  2724.     // Store current weapon's id for reference
  2725.     g_currentweapon[owner] = weaponid
  2726.    
  2727.     // Replace weapon models with custom ones
  2728.     replace_weapon_models(owner, weaponid)
  2729.    
  2730.     // Zombie not holding an allowed weapon for some reason
  2731.     if (g_zombie[owner] && !((1<<weaponid) & ZOMBIE_ALLOWED_WEAPONS_BITSUM))
  2732.     {
  2733.         // Switch to knife
  2734.         g_currentweapon[owner] = CSW_KNIFE
  2735.         engclient_cmd(owner, "weapon_knife")
  2736.     }
  2737. }
  2738.  
  2739. // WeaponMod bugfix
  2740. //forward wpn_gi_reset_weapon(id);
  2741. public wpn_gi_reset_weapon(id)
  2742. {
  2743.     // Replace knife model
  2744.     replace_weapon_models(id, CSW_KNIFE)
  2745. }
  2746.  
  2747. // Client joins the game
  2748. public client_putinserver(id)
  2749. {
  2750.     // Plugin disabled?
  2751.     if (!g_pluginenabled) return;
  2752.    
  2753.     // Player joined
  2754.     g_isconnected[id] = true
  2755.    
  2756.     // Cache player's name
  2757.     get_user_name(id, g_playername[id], charsmax(g_playername[]))
  2758.    
  2759.     // Initialize player vars
  2760.     reset_vars(id, 1)
  2761.    
  2762.     // Load player stats?
  2763.     if (get_pcvar_num(cvar_statssave)) load_stats(id)
  2764.    
  2765.     // Set some tasks for humans only
  2766.     if (!is_user_bot(id))
  2767.     {
  2768.         // Set the custom HUD display task if enabled
  2769.         if (get_pcvar_num(cvar_huddisplay))
  2770.             set_task(1.0, "ShowHUD", id+TASK_SHOWHUD, _, _, "b")
  2771.        
  2772.         // Disable minmodels for clients to see zombies properly
  2773.         set_task(5.0, "disable_minmodels", id)
  2774.     }
  2775.     else
  2776.     {
  2777.         // Set bot flag
  2778.         g_isbot[id] = true
  2779.        
  2780.         // CZ bots seem to use a different "classtype" for player entities
  2781.         // (or something like that) which needs to be hooked separately
  2782.         if (!g_hamczbots && cvar_botquota)
  2783.         {
  2784.             // Set a task to let the private data initialize
  2785.             set_task(0.1, "register_ham_czbots", id)
  2786.         }
  2787.     }
  2788. }
  2789.  
  2790. // Client leaving
  2791. public fw_ClientDisconnect(id)
  2792. {
  2793.     // Check that we still have both humans and zombies to keep the round going
  2794.     if (g_isalive[id]) check_round(id)
  2795.    
  2796.     // Temporarily save player stats?
  2797.     if (get_pcvar_num(cvar_statssave)) save_stats(id)
  2798.    
  2799.     // Remove previous tasks
  2800.     remove_task(id+TASK_TEAM)
  2801.     remove_task(id+TASK_MODEL)
  2802.     remove_task(id+TASK_FLASH)
  2803.     remove_task(id+TASK_CHARGE)
  2804.     remove_task(id+TASK_SPAWN)
  2805.     remove_task(id+TASK_BLOOD)
  2806.     remove_task(id+TASK_AURA)
  2807.     remove_task(id+TASK_BURN)
  2808.     remove_task(id+TASK_NVISION)
  2809.     remove_task(id+TASK_SHOWHUD)
  2810.    
  2811.     if (g_handle_models_on_separate_ent)
  2812.     {
  2813.         // Remove custom model entities
  2814.         fm_remove_model_ents(id)
  2815.     }
  2816.    
  2817.     // Player left, clear cached flags
  2818.     g_isconnected[id] = false
  2819.     g_isbot[id] = false
  2820.     g_isalive[id] = false
  2821. }
  2822.  
  2823. // Client left
  2824. public fw_ClientDisconnect_Post()
  2825. {
  2826.     // Last Zombie Check
  2827.     fnCheckLastZombie()
  2828. }
  2829.  
  2830. // Client Kill Forward
  2831. public fw_ClientKill()
  2832. {
  2833.     // Prevent players from killing themselves?
  2834.     if (get_pcvar_num(cvar_blocksuicide))
  2835.         return FMRES_SUPERCEDE;
  2836.    
  2837.     return FMRES_IGNORED;
  2838. }
  2839.  
  2840. // Emit Sound Forward
  2841. public fw_EmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch)
  2842. {
  2843.     // Block all those unneeeded hostage sounds
  2844.     if (sample[0] == 'h' && sample[1] == 'o' && sample[2] == 's' && sample[3] == 't' && sample[4] == 'a' && sample[5] == 'g' && sample[6] == 'e')
  2845.         return FMRES_SUPERCEDE;
  2846.    
  2847.     // Replace these next sounds for zombies only
  2848.     if (!is_user_valid_connected(id) || !g_zombie[id])
  2849.         return FMRES_IGNORED;
  2850.    
  2851.     static sound[64]
  2852.    
  2853.     // Zombie being hit
  2854.     if (sample[7] == 'b' && sample[8] == 'h' && sample[9] == 'i' && sample[10] == 't')
  2855.     {
  2856.         if (g_nemesis[id])
  2857.         {
  2858.             ArrayGetString(nemesis_pain, random_num(0, ArraySize(nemesis_pain) - 1), sound, charsmax(sound))
  2859.             emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2860.         }
  2861.         else
  2862.         {
  2863.             ArrayGetString(zombie_pain, random_num(0, ArraySize(zombie_pain) - 1), sound, charsmax(sound))
  2864.             emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2865.         }
  2866.         return FMRES_SUPERCEDE;
  2867.     }
  2868.    
  2869.     // Zombie attacks with knife
  2870.     if (sample[8] == 'k' && sample[9] == 'n' && sample[10] == 'i')
  2871.     {
  2872.         if (sample[14] == 's' && sample[15] == 'l' && sample[16] == 'a') // slash
  2873.         {
  2874.             ArrayGetString(zombie_miss_slash, random_num(0, ArraySize(zombie_miss_slash) - 1), sound, charsmax(sound))
  2875.             emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2876.             return FMRES_SUPERCEDE;
  2877.         }
  2878.         if (sample[14] == 'h' && sample[15] == 'i' && sample[16] == 't') // hit
  2879.         {
  2880.             if (sample[17] == 'w') // wall
  2881.             {
  2882.                 ArrayGetString(zombie_miss_wall, random_num(0, ArraySize(zombie_miss_wall) - 1), sound, charsmax(sound))
  2883.                 emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2884.                 return FMRES_SUPERCEDE;
  2885.             }
  2886.             else
  2887.             {
  2888.                 ArrayGetString(zombie_hit_normal, random_num(0, ArraySize(zombie_hit_normal) - 1), sound, charsmax(sound))
  2889.                 emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2890.                 return FMRES_SUPERCEDE;
  2891.             }
  2892.         }
  2893.         if (sample[14] == 's' && sample[15] == 't' && sample[16] == 'a') // stab
  2894.         {
  2895.             ArrayGetString(zombie_hit_stab, random_num(0, ArraySize(zombie_hit_stab) - 1), sound, charsmax(sound))
  2896.             emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2897.             return FMRES_SUPERCEDE;
  2898.         }
  2899.     }
  2900.    
  2901.     // Zombie dies
  2902.     if (sample[7] == 'd' && ((sample[8] == 'i' && sample[9] == 'e') || (sample[8] == 'e' && sample[9] == 'a')))
  2903.     {
  2904.         ArrayGetString(zombie_die, random_num(0, ArraySize(zombie_die) - 1), sound, charsmax(sound))
  2905.         emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2906.         return FMRES_SUPERCEDE;
  2907.     }
  2908.    
  2909.     // Zombie falls off
  2910.     if (sample[10] == 'f' && sample[11] == 'a' && sample[12] == 'l' && sample[13] == 'l')
  2911.     {
  2912.         ArrayGetString(zombie_fall, random_num(0, ArraySize(zombie_fall) - 1), sound, charsmax(sound))
  2913.         emit_sound(id, channel, sound, volume, attn, flags, pitch)
  2914.         return FMRES_SUPERCEDE;
  2915.     }
  2916.    
  2917.     return FMRES_IGNORED;
  2918. }
  2919.  
  2920. // Forward Set ClientKey Value -prevent CS from changing player models-
  2921. public fw_SetClientKeyValue(id, const infobuffer[], const key[])
  2922. {
  2923.     // Block CS model changes
  2924.     if (key[0] == 'm' && key[1] == 'o' && key[2] == 'd' && key[3] == 'e' && key[4] == 'l')
  2925.         return FMRES_SUPERCEDE;
  2926.    
  2927.     return FMRES_IGNORED;
  2928. }
  2929.  
  2930. // Forward Client User Info Changed -prevent players from changing models-
  2931. public fw_ClientUserInfoChanged(id)
  2932. {
  2933.     // Cache player's name
  2934.     get_user_name(id, g_playername[id], charsmax(g_playername[]))
  2935.    
  2936.     if (!g_handle_models_on_separate_ent)
  2937.     {
  2938.         // Get current model
  2939.         static currentmodel[32]
  2940.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  2941.        
  2942.         // If they're different, set model again
  2943.         if (!equal(currentmodel, g_playermodel[id]) && !task_exists(id+TASK_MODEL))
  2944.             fm_cs_set_user_model(id+TASK_MODEL)
  2945.     }
  2946. }
  2947.  
  2948. // Forward Get Game Description
  2949. public fw_GetGameDescription()
  2950. {
  2951.     // Return the mod name so it can be easily identified
  2952.     forward_return(FMV_STRING, g_modname)
  2953.    
  2954.     return FMRES_SUPERCEDE;
  2955. }
  2956.  
  2957. // Forward Set Model
  2958. public fw_SetModel(entity, const model[])
  2959. {
  2960.     // We don't care
  2961.     if (strlen(model) < 8)
  2962.         return;
  2963.    
  2964.     // Remove weapons?
  2965.     if (get_pcvar_float(cvar_removedropped) > 0.0)
  2966.     {
  2967.         // Get entity's classname
  2968.         static classname[10]
  2969.         pev(entity, pev_classname, classname, charsmax(classname))
  2970.        
  2971.         // Check if it's a weapon box
  2972.         if (equal(classname, "weaponbox"))
  2973.         {
  2974.             // They get automatically removed when thinking
  2975.             set_pev(entity, pev_nextthink, get_gametime() + get_pcvar_float(cvar_removedropped))
  2976.             return;
  2977.         }
  2978.     }
  2979.    
  2980.     // Narrow down our matches a bit
  2981.     if (model[7] != 'w' || model[8] != '_')
  2982.         return;
  2983.    
  2984.     // Get damage time of grenade
  2985.     static Float:dmgtime
  2986.     pev(entity, pev_dmgtime, dmgtime)
  2987.    
  2988.     // Grenade not yet thrown
  2989.     if (dmgtime == 0.0)
  2990.         return;
  2991.    
  2992.     // Get whether grenade's owner is a zombie
  2993.     if (g_zombie[pev(entity, pev_owner)])
  2994.     {
  2995.         if (model[9] == 'h' && model[10] == 'e' && get_pcvar_num(cvar_extrainfbomb)) // Infection Bomb
  2996.         {
  2997.             // Give it a glow
  2998.             fm_set_rendering(entity, kRenderFxGlowShell, 0, 200, 0, 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(200) // g
  3009.             write_byte(0) // 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_INFECTION)
  3015.         }
  3016.     }
  3017.     else if (model[9] == 'h' && model[10] == 'e' && get_pcvar_num(cvar_firegrenades)) // Napalm Grenade
  3018.     {
  3019.         // Give it a glow
  3020.         fm_set_rendering(entity, kRenderFxGlowShell, 200, 0, 0, kRenderNormal, 16);
  3021.        
  3022.         // And a colored trail
  3023.         message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  3024.         write_byte(TE_BEAMFOLLOW) // TE id
  3025.         write_short(entity) // entity
  3026.         write_short(g_trailSpr) // sprite
  3027.         write_byte(10) // life
  3028.         write_byte(10) // width
  3029.         write_byte(200) // r
  3030.         write_byte(0) // g
  3031.         write_byte(0) // b
  3032.         write_byte(200) // brightness
  3033.         message_end()
  3034.        
  3035.         // Set grenade type on the thrown grenade entity
  3036.         set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_NAPALM)
  3037.     }
  3038.     else if (model[9] == 'f' && model[10] == 'l' && get_pcvar_num(cvar_frostgrenades)) // Frost Grenade
  3039.     {
  3040.         // Give it a glow
  3041.         fm_set_rendering(entity, kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 16);
  3042.        
  3043.         // And a colored trail
  3044.         message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  3045.         write_byte(TE_BEAMFOLLOW) // TE id
  3046.         write_short(entity) // entity
  3047.         write_short(g_trailSpr) // sprite
  3048.         write_byte(10) // life
  3049.         write_byte(10) // width
  3050.         write_byte(0) // r
  3051.         write_byte(100) // g
  3052.         write_byte(200) // b
  3053.         write_byte(200) // brightness
  3054.         message_end()
  3055.        
  3056.         // Set grenade type on the thrown grenade entity
  3057.         set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FROST)
  3058.     }
  3059.     else if (model[9] == 's' && model[10] == 'm' && get_pcvar_num(cvar_flaregrenades)) // Flare
  3060.     {
  3061.         // Build flare's color
  3062.         static rgb[3]
  3063.         switch (get_pcvar_num(cvar_flarecolor))
  3064.         {
  3065.             case 0: // white
  3066.             {
  3067.                 rgb[0] = 255 // r
  3068.                 rgb[1] = 255 // g
  3069.                 rgb[2] = 255 // b
  3070.             }
  3071.             case 1: // red
  3072.             {
  3073.                 rgb[0] = random_num(50,255) // r
  3074.                 rgb[1] = 0 // g
  3075.                 rgb[2] = 0 // b
  3076.             }
  3077.             case 2: // green
  3078.             {
  3079.                 rgb[0] = 0 // r
  3080.                 rgb[1] = random_num(50,255) // g
  3081.                 rgb[2] = 0 // b
  3082.             }
  3083.             case 3: // blue
  3084.             {
  3085.                 rgb[0] = 0 // r
  3086.                 rgb[1] = 0 // g
  3087.                 rgb[2] = random_num(50,255) // b
  3088.             }
  3089.             case 4: // random (all colors)
  3090.             {
  3091.                 rgb[0] = random_num(50,200) // r
  3092.                 rgb[1] = random_num(50,200) // g
  3093.                 rgb[2] = random_num(50,200) // b
  3094.             }
  3095.             case 5: // random (r,g,b)
  3096.             {
  3097.                 switch (random_num(1, 3))
  3098.                 {
  3099.                     case 1: // red
  3100.                     {
  3101.                         rgb[0] = random_num(50,255) // r
  3102.                         rgb[1] = 0 // g
  3103.                         rgb[2] = 0 // b
  3104.                     }
  3105.                     case 2: // green
  3106.                     {
  3107.                         rgb[0] = 0 // r
  3108.                         rgb[1] = random_num(50,255) // g
  3109.                         rgb[2] = 0 // b
  3110.                     }
  3111.                     case 3: // blue
  3112.                     {
  3113.                         rgb[0] = 0 // r
  3114.                         rgb[1] = 0 // g
  3115.                         rgb[2] = random_num(50,255) // b
  3116.                     }
  3117.                 }
  3118.             }
  3119.         }
  3120.        
  3121.         // Give it a glow
  3122.         fm_set_rendering(entity, kRenderFxGlowShell, rgb[0], rgb[1], rgb[2], kRenderNormal, 16);
  3123.        
  3124.         // And a colored trail
  3125.         message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
  3126.         write_byte(TE_BEAMFOLLOW) // TE id
  3127.         write_short(entity) // entity
  3128.         write_short(g_trailSpr) // sprite
  3129.         write_byte(10) // life
  3130.         write_byte(10) // width
  3131.         write_byte(rgb[0]) // r
  3132.         write_byte(rgb[1]) // g
  3133.         write_byte(rgb[2]) // b
  3134.         write_byte(200) // brightness
  3135.         message_end()
  3136.        
  3137.         // Set grenade type on the thrown grenade entity
  3138.         set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FLARE)
  3139.        
  3140.         // Set flare color on the thrown grenade entity
  3141.         set_pev(entity, PEV_FLARE_COLOR, rgb)
  3142.     }
  3143. }
  3144.  
  3145. // Ham Grenade Think Forward
  3146. public fw_ThinkGrenade(entity)
  3147. {
  3148.     // Invalid entity
  3149.     if (!pev_valid(entity)) return HAM_IGNORED;
  3150.    
  3151.     // Get damage time of grenade
  3152.     static Float:dmgtime, Float:current_time
  3153.     pev(entity, pev_dmgtime, dmgtime)
  3154.     current_time = get_gametime()
  3155.    
  3156.     // Check if it's time to go off
  3157.     if (dmgtime > current_time)
  3158.         return HAM_IGNORED;
  3159.    
  3160.     // Check if it's one of our custom nades
  3161.     switch (pev(entity, PEV_NADE_TYPE))
  3162.     {
  3163.         case NADE_TYPE_INFECTION: // Infection Bomb
  3164.         {
  3165.             infection_explode(entity)
  3166.             return HAM_SUPERCEDE;
  3167.         }
  3168.         case NADE_TYPE_NAPALM: // Napalm Grenade
  3169.         {
  3170.             fire_explode(entity)
  3171.             return HAM_SUPERCEDE;
  3172.         }
  3173.         case NADE_TYPE_FROST: // Frost Grenade
  3174.         {
  3175.             frost_explode(entity)
  3176.             return HAM_SUPERCEDE;
  3177.         }
  3178.         case NADE_TYPE_FLARE: // Flare
  3179.         {
  3180.             // Get its duration
  3181.             static duration
  3182.             duration = pev(entity, PEV_FLARE_DURATION)
  3183.            
  3184.             // Already went off, do lighting loop for the duration of PEV_FLARE_DURATION
  3185.             if (duration > 0)
  3186.             {
  3187.                 // Check whether this is the last loop
  3188.                 if (duration == 1)
  3189.                 {
  3190.                     // Get rid of the flare entity
  3191.                     engfunc(EngFunc_RemoveEntity, entity)
  3192.                     return HAM_SUPERCEDE;
  3193.                 }
  3194.                
  3195.                 // Light it up!
  3196.                 flare_lighting(entity, duration)
  3197.                
  3198.                 // Set time for next loop
  3199.                 set_pev(entity, PEV_FLARE_DURATION, --duration)
  3200.                 set_pev(entity, pev_dmgtime, current_time + 2.0)
  3201.             }
  3202.             // Light up when it's stopped on ground
  3203.             else if ((pev(entity, pev_flags) & FL_ONGROUND) && fm_get_speed(entity) < 10)
  3204.             {
  3205.                 // Flare sound
  3206.                 static sound[64]
  3207.                 ArrayGetString(grenade_flare, random_num(0, ArraySize(grenade_flare) - 1), sound, charsmax(sound))
  3208.                 emit_sound(entity, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  3209.                
  3210.                 // Set duration and start lightning loop on next think
  3211.                 set_pev(entity, PEV_FLARE_DURATION, 1 + get_pcvar_num(cvar_flareduration)/2)
  3212.                 set_pev(entity, pev_dmgtime, current_time + 0.1)
  3213.             }
  3214.             else
  3215.             {
  3216.                 // Delay explosion until we hit ground
  3217.                 set_pev(entity, pev_dmgtime, current_time + 0.5)
  3218.             }
  3219.         }
  3220.     }
  3221.    
  3222.     return HAM_IGNORED;
  3223. }
  3224.  
  3225. // Forward CmdStart
  3226. public fw_CmdStart(id, handle)
  3227. {
  3228.     // Not alive
  3229.     if (!g_isalive[id])
  3230.         return;
  3231.    
  3232.     // This logic looks kinda weird, but it should work in theory...
  3233.     // p = g_zombie[id], q = g_survivor[id], r = g_cached_customflash
  3234.     // ¬(p v q v (¬p ^ r)) <==> ¬p ^ ¬q ^ (p v ¬r)
  3235.     if (!g_zombie[id] && !g_survivor[id] && (g_zombie[id] || !g_cached_customflash))
  3236.         return;
  3237.    
  3238.     // Check if it's a flashlight impulse
  3239.     if (get_uc(handle, UC_Impulse) != IMPULSE_FLASHLIGHT)
  3240.         return;
  3241.    
  3242.     // Block it I say!
  3243.     set_uc(handle, UC_Impulse, 0)
  3244.    
  3245.     // Should human's custom flashlight be turned on?
  3246.     if (!g_zombie[id] && !g_survivor[id] && g_flashbattery[id] > 2 && get_gametime() - g_lastflashtime[id] > 1.2)
  3247.     {
  3248.         // Prevent calling flashlight too quickly (bugfix)
  3249.         g_lastflashtime[id] = get_gametime()
  3250.        
  3251.         // Toggle custom flashlight
  3252.         g_flashlight[id] = !(g_flashlight[id])
  3253.        
  3254.         // Play flashlight toggle sound
  3255.         emit_sound(id, CHAN_ITEM, sound_flashlight, 1.0, ATTN_NORM, 0, PITCH_NORM)
  3256.        
  3257.         // Update flashlight status on the HUD
  3258.         message_begin(MSG_ONE, g_msgFlashlight, _, id)
  3259.         write_byte(g_flashlight[id]) // toggle
  3260.         write_byte(g_flashbattery[id]) // battery
  3261.         message_end()
  3262.        
  3263.         // Remove previous tasks
  3264.         remove_task(id+TASK_CHARGE)
  3265.         remove_task(id+TASK_FLASH)
  3266.        
  3267.         // Set the flashlight charge task
  3268.         set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
  3269.        
  3270.         // Call our custom flashlight task if enabled
  3271.         if (g_flashlight[id]) set_task(0.1, "set_user_flashlight", id+TASK_FLASH, _, _, "b")
  3272.     }
  3273. }
  3274.  
  3275. // Forward Player PreThink
  3276. public fw_PlayerPreThink(id)
  3277. {
  3278.     // Not alive
  3279.     if (!g_isalive[id])
  3280.         return;
  3281.    
  3282.     // Enable custom buyzone for player during buytime, unless zombie or survivor or time expired
  3283.     if (g_cached_buytime > 0.0 && !g_zombie[id] && !g_survivor[id] && (get_gametime() < g_buytime[id] + g_cached_buytime))
  3284.     {
  3285.         if (pev_valid(g_buyzone_ent))
  3286.             dllfunc(DLLFunc_Touch, g_buyzone_ent, id)
  3287.     }
  3288.    
  3289.     // Silent footsteps for zombies?
  3290.     if (g_cached_zombiesilent && g_zombie[id] && !g_nemesis[id])
  3291.         set_pev(id, pev_flTimeStepSound, STEPTIME_SILENT)
  3292.    
  3293.     // Player frozen?
  3294.     if (g_frozen[id])
  3295.     {
  3296.         set_pev(id, pev_velocity, Float:{0.0,0.0,0.0}) // stop motion
  3297.         return; // shouldn't leap while frozen
  3298.     }
  3299.    
  3300.     // --- Check if player should leap ---
  3301.    
  3302.     // Don't allow leap during freezetime
  3303.     if (g_freezetime)
  3304.         return;
  3305.    
  3306.     // Check if proper CVARs are enabled and retrieve leap settings
  3307.     static Float:cooldown, Float:current_time
  3308.     if (g_zombie[id])
  3309.     {
  3310.         if (g_nemesis[id])
  3311.         {
  3312.             if (!g_cached_leapnemesis) return;
  3313.             cooldown = g_cached_leapnemesiscooldown
  3314.         }
  3315.         else
  3316.         {
  3317.             switch (g_cached_leapzombies)
  3318.             {
  3319.                 case 0: return;
  3320.                 case 2: if (!g_firstzombie[id]) return;
  3321.                 case 3: if (!g_lastzombie[id]) return;
  3322.             }
  3323.             cooldown = g_cached_leapzombiescooldown
  3324.         }
  3325.     }
  3326.     else
  3327.     {
  3328.         if (g_survivor[id])
  3329.         {
  3330.             if (!g_cached_leapsurvivor) return;
  3331.             cooldown = g_cached_leapsurvivorcooldown
  3332.         }
  3333.         else return;
  3334.     }
  3335.    
  3336.     current_time = get_gametime()
  3337.    
  3338.     // Cooldown not over yet
  3339.     if (current_time - g_lastleaptime[id] < cooldown)
  3340.         return;
  3341.    
  3342.     // Not doing a longjump (don't perform check for bots, they leap automatically)
  3343.     if (!g_isbot[id] && !(pev(id, pev_button) & (IN_JUMP | IN_DUCK) == (IN_JUMP | IN_DUCK)))
  3344.         return;
  3345.    
  3346.     // Not on ground or not enough speed
  3347.     if (!(pev(id, pev_flags) & FL_ONGROUND) || fm_get_speed(id) < 80)
  3348.         return;
  3349.    
  3350.     static Float:velocity[3]
  3351.    
  3352.     // Make velocity vector
  3353.     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)
  3354.    
  3355.     // Set custom height
  3356.     velocity[2] = g_survivor[id] ? get_pcvar_float(cvar_leapsurvivorheight) : g_nemesis[id] ? get_pcvar_float(cvar_leapnemesisheight) : get_pcvar_float(cvar_leapzombiesheight)
  3357.    
  3358.     // Apply the new velocity
  3359.     set_pev(id, pev_velocity, velocity)
  3360.    
  3361.     // Update last leap time
  3362.     g_lastleaptime[id] = current_time
  3363. }
  3364.  
  3365. /*================================================================================
  3366.  [Client Commands]
  3367. =================================================================================*/
  3368.  
  3369. // Say "/zpmenu"
  3370. public clcmd_saymenu(id)
  3371. {
  3372.     show_menu_game(id) // show game menu
  3373. }
  3374.  
  3375. // Say "/unstuck"
  3376. public clcmd_sayunstuck(id)
  3377. {
  3378.     menu_game(id, 3) // try to get unstuck
  3379. }
  3380.  
  3381. // Nightvision toggle
  3382. public clcmd_nightvision(id)
  3383. {
  3384.     // Nightvision available to player?
  3385.     if (g_nvision[id] || (g_isalive[id] && cs_get_user_nvg(id)))
  3386.     {
  3387.         // Enable-disable
  3388.         g_nvisionenabled[id] = !(g_nvisionenabled[id])
  3389.        
  3390.         // Custom nvg?
  3391.         if (get_pcvar_num(cvar_customnvg))
  3392.         {
  3393.             remove_task(id+TASK_NVISION)
  3394.             if (g_nvisionenabled[id]) set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  3395.         }
  3396.         else
  3397.             set_user_gnvision(id, g_nvisionenabled[id])
  3398.     }
  3399.    
  3400.     return PLUGIN_HANDLED;
  3401. }
  3402.  
  3403. // Weapon Drop
  3404. public clcmd_drop(id)
  3405. {
  3406.     // Survivor should stick with its weapon
  3407.     if (g_survivor[id])
  3408.         return PLUGIN_HANDLED;
  3409.    
  3410.     return PLUGIN_CONTINUE;
  3411. }
  3412.  
  3413. // Buy BP Ammo
  3414. public clcmd_buyammo(id)
  3415. {
  3416.     // Not alive or infinite ammo setting enabled
  3417.     if (!g_isalive[id] || get_pcvar_num(cvar_infammo))
  3418.         return PLUGIN_HANDLED;
  3419.    
  3420.     // Not human
  3421.     if (g_zombie[id])
  3422.     {
  3423.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_HUMAN_ONLY")
  3424.         return PLUGIN_HANDLED;
  3425.     }
  3426.    
  3427.     // Custom buytime enabled and human player standing in buyzone, allow buying weapon's ammo normally instead
  3428.     if (g_cached_buytime > 0.0 && !g_survivor[id] && (get_gametime() < g_buytime[id] + g_cached_buytime) && cs_get_user_buyzone(id))
  3429.         return PLUGIN_CONTINUE;
  3430.    
  3431.     // Not enough ammo packs
  3432.     if (g_ammopacks[id] < 1)
  3433.     {
  3434.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "NOT_ENOUGH_AMMO")
  3435.         return PLUGIN_HANDLED;
  3436.     }
  3437.    
  3438.     // Get user weapons
  3439.     static weapons[32], num, i, currentammo, weaponid, refilled
  3440.     num = 0 // reset passed weapons count (bugfix)
  3441.     refilled = false
  3442.     get_user_weapons(id, weapons, num)
  3443.    
  3444.     // Loop through them and give the right ammo type
  3445.     for (i = 0; i < num; i++)
  3446.     {
  3447.         // Prevents re-indexing the array
  3448.         weaponid = weapons[i]
  3449.        
  3450.         // Primary and secondary only
  3451.         if (MAXBPAMMO[weaponid] > 2)
  3452.         {
  3453.             // Get current ammo of the weapon
  3454.             currentammo = cs_get_user_bpammo(id, weaponid)
  3455.            
  3456.             // Give additional ammo
  3457.             ExecuteHamB(Ham_GiveAmmo, id, BUYAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  3458.            
  3459.             // Check whether we actually refilled the weapon's ammo
  3460.             if (cs_get_user_bpammo(id, weaponid) - currentammo > 0) refilled = true
  3461.         }
  3462.     }
  3463.    
  3464.     // Weapons already have full ammo
  3465.     if (!refilled) return PLUGIN_HANDLED;
  3466.    
  3467.     // Deduce ammo packs, play clip purchase sound, and notify player
  3468.     g_ammopacks[id]--
  3469.     emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  3470.     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "AMMO_BOUGHT")
  3471.    
  3472.     return PLUGIN_HANDLED;
  3473. }
  3474.  
  3475. // Block Team Change
  3476. public clcmd_changeteam(id)
  3477. {
  3478.     static team
  3479.     team = fm_cs_get_user_team(id)
  3480.    
  3481.     // Unless it's a spectator joining the game
  3482.     if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  3483.         return PLUGIN_CONTINUE;
  3484.    
  3485.     // Pressing 'M' (chooseteam) ingame should show the main menu instead
  3486.     show_menu_game(id)
  3487.     return PLUGIN_HANDLED;
  3488. }
  3489.  
  3490. /*================================================================================
  3491.  [Menus]
  3492. =================================================================================*/
  3493.  
  3494. // Game Menu
  3495. show_menu_game(id)
  3496. {
  3497.     // Player disconnected?
  3498.     if (!g_isconnected[id])
  3499.         return;
  3500.    
  3501.     static menu[250], len, userflags
  3502.     len = 0
  3503.     userflags = get_user_flags(id)
  3504.    
  3505.     // Title
  3506.     len += formatex(menu[len], charsmax(menu) - len, "\y%s^n^n", g_modname)
  3507.    
  3508.     // 1. Buy weapons
  3509.     if (get_pcvar_num(cvar_buycustom))
  3510.         len += formatex(menu[len], charsmax(menu) - len, "\r1.\w %L^n", id, "MENU_BUY")
  3511.     else
  3512.         len += formatex(menu[len], charsmax(menu) - len, "\d1. %L^n", id, "MENU_BUY")
  3513.    
  3514.     // 2. Extra items
  3515.     if (get_pcvar_num(cvar_extraitems) && g_isalive[id])
  3516.         len += formatex(menu[len], charsmax(menu) - len, "\r2.\w %L^n", id, "MENU_EXTRABUY")
  3517.     else
  3518.         len += formatex(menu[len], charsmax(menu) - len, "\d2. %L^n", id, "MENU_EXTRABUY")
  3519.    
  3520.     // 3. Zombie class
  3521.     if (get_pcvar_num(cvar_zclasses))
  3522.         len += formatex(menu[len], charsmax(menu) - len, "\r3.\w %L^n", id,"MENU_ZCLASS")
  3523.     else
  3524.         len += formatex(menu[len], charsmax(menu) - len, "\d3. %L^n", id,"MENU_ZCLASS")
  3525.    
  3526.     // 4. Unstuck
  3527.     if (g_isalive[id])
  3528.         len += formatex(menu[len], charsmax(menu) - len, "\r4.\w %L^n", id, "MENU_UNSTUCK")
  3529.     else
  3530.         len += formatex(menu[len], charsmax(menu) - len, "\d4. %L^n", id, "MENU_UNSTUCK")
  3531.    
  3532.     // 5. Help
  3533.     len += formatex(menu[len], charsmax(menu) - len, "\r5.\w %L^n^n", id, "MENU_INFO")
  3534.    
  3535.     // 6. Knife Menu
  3536.     len += formatex(menu[len], charsmax(menu) - len, "\r6.\w Knife Menu^n^n")
  3537.    
  3538.     // 7. Join spec
  3539.     if (!g_isalive[id] || !get_pcvar_num(cvar_blocksuicide) || (userflags & g_access_flag[ACCESS_ADMIN_MENU]))
  3540.         len += formatex(menu[len], charsmax(menu) - len, "\r7.\w %L^n^n", id, "MENU_SPECTATOR")
  3541.     else
  3542.         len += formatex(menu[len], charsmax(menu) - len, "\d7. %L^n^n", id, "MENU_SPECTATOR")
  3543.    
  3544.     // 9. Admin menu
  3545.     if (userflags & g_access_flag[ACCESS_ADMIN_MENU])
  3546.         len += formatex(menu[len], charsmax(menu) - len, "\r9.\w %L", id, "MENU_ADMIN")
  3547.     else
  3548.         len += formatex(menu[len], charsmax(menu) - len, "\d9. %L", id, "MENU_ADMIN")
  3549.    
  3550.     // 0. Exit
  3551.     len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
  3552.    
  3553.     // Fix for AMXX custom menus
  3554.     if (pev_valid(id) == PDATA_SAFE)
  3555.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3556.    
  3557.     show_menu(id, KEYSMENU, menu, -1, "Game Menu")
  3558. }
  3559.  
  3560. // Buy Menu 1
  3561. public show_menu_buy1(taskid)
  3562. {
  3563.     // Get player's id
  3564.     static id
  3565.     (taskid > g_maxplayers) ? (id = ID_SPAWN) : (id = taskid);
  3566.    
  3567.     // Player dead?
  3568.     if (!g_isalive[id])
  3569.         return;
  3570.    
  3571.     // Zombies or survivors get no guns
  3572.     if (g_zombie[id] || g_survivor[id])
  3573.         return;
  3574.    
  3575.     // Bots pick their weapons randomly / Random weapons setting enabled
  3576.     if (get_pcvar_num(cvar_randweapons) || g_isbot[id])
  3577.     {
  3578.         buy_primary_weapon(id, random_num(0, ArraySize(g_primary_items) - 1))
  3579.         menu_buy2(id, random_num(0, ArraySize(g_secondary_items) - 1))
  3580.         return;
  3581.     }
  3582.    
  3583.     // Automatic selection enabled for player and menu called on spawn event
  3584.     if (WPN_AUTO_ON && taskid > g_maxplayers)
  3585.     {
  3586.         buy_primary_weapon(id, WPN_AUTO_PRI)
  3587.         menu_buy2(id, WPN_AUTO_SEC)
  3588.         return;
  3589.     }
  3590.    
  3591.     static menu[300], len, weap, maxloops
  3592.     len = 0
  3593.     maxloops = min(WPN_STARTID+7, WPN_MAXIDS)
  3594.    
  3595.     // Title
  3596.     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))
  3597.    
  3598.     // 1-7. Weapon List
  3599.     for (weap = WPN_STARTID; weap < maxloops; weap++)
  3600.         len += formatex(menu[len], charsmax(menu) - len, "\r%d.\w %s^n", weap-WPN_STARTID+1, WEAPONNAMES[ArrayGetCell(g_primary_weaponids, weap)])
  3601.    
  3602.     // 8. Auto Select
  3603.     len += formatex(menu[len], charsmax(menu) - len, "^n\r8.\w %L \y[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  3604.    
  3605.     // 9. Next/Back - 0. Exit
  3606.     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")
  3607.    
  3608.     // Fix for AMXX custom menus
  3609.     if (pev_valid(id) == PDATA_SAFE)
  3610.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3611.    
  3612.     show_menu(id, KEYSMENU, menu, -1, "Buy Menu 1")
  3613. }
  3614.  
  3615. // Buy Menu 2
  3616. show_menu_buy2(id)
  3617. {
  3618.     // Player dead?
  3619.     if (!g_isalive[id])
  3620.         return;
  3621.    
  3622.     static menu[250], len, weap, maxloops
  3623.     len = 0
  3624.     maxloops = ArraySize(g_secondary_items)
  3625.    
  3626.     // Title
  3627.     len += formatex(menu[len], charsmax(menu) - len, "\y%L^n", id, "MENU_BUY2_TITLE")
  3628.    
  3629.     // 1-6. Weapon List
  3630.     for (weap = 0; weap < maxloops; weap++)
  3631.         len += formatex(menu[len], charsmax(menu) - len, "^n\r%d.\w %s", weap+1, WEAPONNAMES[ArrayGetCell(g_secondary_weaponids, weap)])
  3632.    
  3633.     // 8. Auto Select
  3634.     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")
  3635.    
  3636.     // 0. Exit
  3637.     len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
  3638.    
  3639.     // Fix for AMXX custom menus
  3640.     if (pev_valid(id) == PDATA_SAFE)
  3641.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3642.    
  3643.     show_menu(id, KEYSMENU, menu, -1, "Buy Menu 2")
  3644. }
  3645.  
  3646. // Extra Items Menu
  3647. show_menu_extras(id)
  3648. {
  3649.     // Player dead?
  3650.     if (!g_isalive[id])
  3651.         return;
  3652.    
  3653.     static menuid, menu[128], item, team, buffer[32]
  3654.    
  3655.     // Title
  3656.     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")
  3657.     menuid = menu_create(menu, "menu_extras")
  3658.    
  3659.     // Item List
  3660.     for (item = 0; item < g_extraitem_i; item++)
  3661.     {
  3662.         // Retrieve item's team
  3663.         team = ArrayGetCell(g_extraitem_team, item)
  3664.        
  3665.         // Item not available to player's team/class
  3666.         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)))
  3667.             continue;
  3668.        
  3669.         // Check if it's one of the hardcoded items, check availability, set translated caption
  3670.         switch (item)
  3671.         {
  3672.             case EXTRA_NVISION:
  3673.             {
  3674.                 if (!get_pcvar_num(cvar_extranvision)) continue;
  3675.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA1")
  3676.             }
  3677.             case EXTRA_ANTIDOTE:
  3678.             {
  3679.                 if (!get_pcvar_num(cvar_extraantidote) || g_antidotecounter >= get_pcvar_num(cvar_antidotelimit)) continue;
  3680.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA2")
  3681.             }
  3682.             case EXTRA_MADNESS:
  3683.             {
  3684.                 if (!get_pcvar_num(cvar_extramadness) || g_madnesscounter >= get_pcvar_num(cvar_madnesslimit)) continue;
  3685.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA3")
  3686.             }
  3687.             case EXTRA_INFBOMB:
  3688.             {
  3689.                 if (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit)) continue;
  3690.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA4")
  3691.             }
  3692.             default:
  3693.             {
  3694.                 if (item >= EXTRA_WEAPONS_STARTID && item <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)) continue;
  3695.                 ArrayGetString(g_extraitem_name, item, buffer, charsmax(buffer))
  3696.             }
  3697.         }
  3698.        
  3699.         // Add Item Name and Cost
  3700.         formatex(menu, charsmax(menu), "%s \y%d %L", buffer, ArrayGetCell(g_extraitem_cost, item), id, "AMMO_PACKS2")
  3701.         buffer[0] = item
  3702.         buffer[1] = 0
  3703.         menu_additem(menuid, menu, buffer)
  3704.     }
  3705.    
  3706.     // No items to display?
  3707.     if (menu_items(menuid) <= 0)
  3708.     {
  3709.         zp_colored_print(id, "^x04[ZP]^x01 %L", id ,"CMD_NOT_EXTRAS")
  3710.         menu_destroy(menuid)
  3711.         return;
  3712.     }
  3713.    
  3714.     // Back - Next - Exit
  3715.     formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3716.     menu_setprop(menuid, MPROP_BACKNAME, menu)
  3717.     formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3718.     menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3719.     formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3720.     menu_setprop(menuid, MPROP_EXITNAME, menu)
  3721.        
  3722.     // If remembered page is greater than number of pages, clamp down the value
  3723.     MENU_PAGE_EXTRAS = min(MENU_PAGE_EXTRAS, menu_pages(menuid)-1)
  3724.    
  3725.     // Fix for AMXX custom menus
  3726.     if (pev_valid(id) == PDATA_SAFE)
  3727.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3728.    
  3729.     menu_display(id, menuid, MENU_PAGE_EXTRAS)
  3730. }
  3731.  
  3732. // Zombie Class Menu
  3733. public show_menu_zclass(id)
  3734. {
  3735.     // Player disconnected
  3736.     if (!g_isconnected[id])
  3737.         return;
  3738.    
  3739.     // Bots pick their zombie class randomly
  3740.     if (g_isbot[id])
  3741.     {
  3742.         g_zombieclassnext[id] = random_num(0, g_zclass_i - 1)
  3743.         return;
  3744.     }
  3745.    
  3746.     static menuid, menu[128], class, buffer[32], buffer2[32]
  3747.    
  3748.     // Title
  3749.     formatex(menu, charsmax(menu), "%L\r", id, "MENU_ZCLASS_TITLE")
  3750.     menuid = menu_create(menu, "menu_zclass")
  3751.    
  3752.     // Class List
  3753.     for (class = 0; class < g_zclass_i; class++)
  3754.     {
  3755.         // Retrieve name and info
  3756.         ArrayGetString(g_zclass_name, class, buffer, charsmax(buffer))
  3757.         ArrayGetString(g_zclass_info, class, buffer2, charsmax(buffer2))
  3758.        
  3759.         // Add to menu
  3760.         if (class == g_zombieclassnext[id])
  3761.             formatex(menu, charsmax(menu), "\d%s %s", buffer, buffer2)
  3762.         else
  3763.             formatex(menu, charsmax(menu), "%s \y%s", buffer, buffer2)
  3764.        
  3765.         buffer[0] = class
  3766.         buffer[1] = 0
  3767.         menu_additem(menuid, menu, buffer)
  3768.     }
  3769.    
  3770.     // Back - Next - Exit
  3771.     formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3772.     menu_setprop(menuid, MPROP_BACKNAME, menu)
  3773.     formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3774.     menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3775.     formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3776.     menu_setprop(menuid, MPROP_EXITNAME, menu)
  3777.    
  3778.     // If remembered page is greater than number of pages, clamp down the value
  3779.     MENU_PAGE_ZCLASS = min(MENU_PAGE_ZCLASS, menu_pages(menuid)-1)
  3780.    
  3781.     // Fix for AMXX custom menus
  3782.     if (pev_valid(id) == PDATA_SAFE)
  3783.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3784.    
  3785.     menu_display(id, menuid, MENU_PAGE_ZCLASS)
  3786. }
  3787.  
  3788. // Help Menu
  3789. show_menu_info(id)
  3790. {
  3791.     // Player disconnected?
  3792.     if (!g_isconnected[id])
  3793.         return;
  3794.    
  3795.     static menu[150]
  3796.    
  3797.     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")
  3798.    
  3799.     // Fix for AMXX custom menus
  3800.     if (pev_valid(id) == PDATA_SAFE)
  3801.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3802.    
  3803.     show_menu(id, KEYSMENU, menu, -1, "Mod Info")
  3804. }
  3805.  
  3806. // Admin Menu
  3807. show_menu_admin(id)
  3808. {
  3809.     // Player disconnected?
  3810.     if (!g_isconnected[id])
  3811.         return;
  3812.    
  3813.     static menu[250], len, userflags
  3814.     len = 0
  3815.     userflags = get_user_flags(id)
  3816.    
  3817.     // Title
  3818.     len += formatex(menu[len], charsmax(menu) - len, "\y%L^n^n", id, "MENU_ADMIN_TITLE")
  3819.    
  3820.     // 1. Zombiefy/Humanize command
  3821.     if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
  3822.         len += formatex(menu[len], charsmax(menu) - len, "\r1.\w %L^n", id, "MENU_ADMIN1")
  3823.     else
  3824.         len += formatex(menu[len], charsmax(menu) - len, "\d1. %L^n", id, "MENU_ADMIN1")
  3825.    
  3826.     // 2. Nemesis command
  3827.     if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
  3828.         len += formatex(menu[len], charsmax(menu) - len, "\r2.\w %L^n", id, "MENU_ADMIN2")
  3829.     else
  3830.         len += formatex(menu[len], charsmax(menu) - len, "\d2. %L^n", id, "MENU_ADMIN2")
  3831.    
  3832.     // 3. Survivor command
  3833.     if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
  3834.         len += formatex(menu[len], charsmax(menu) - len, "\r3.\w %L^n", id, "MENU_ADMIN3")
  3835.     else
  3836.         len += formatex(menu[len], charsmax(menu) - len, "\d3. %L^n", id, "MENU_ADMIN3")
  3837.    
  3838.     // 4. Respawn command
  3839.     if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  3840.         len += formatex(menu[len], charsmax(menu) - len, "\r4.\w %L^n", id, "MENU_ADMIN4")
  3841.     else
  3842.         len += formatex(menu[len], charsmax(menu) - len, "\d4. %L^n", id, "MENU_ADMIN4")
  3843.    
  3844.     // 5. Swarm mode command
  3845.     if ((userflags & g_access_flag[ACCESS_MODE_SWARM]) && allowed_swarm())
  3846.         len += formatex(menu[len], charsmax(menu) - len, "\r5.\w %L^n", id, "MENU_ADMIN5")
  3847.     else
  3848.         len += formatex(menu[len], charsmax(menu) - len, "\d5. %L^n", id, "MENU_ADMIN5")
  3849.    
  3850.     // 6. Multi infection command
  3851.     if ((userflags & g_access_flag[ACCESS_MODE_MULTI]) && allowed_multi())
  3852.         len += formatex(menu[len], charsmax(menu) - len, "\r6.\w %L^n", id, "MENU_ADMIN6")
  3853.     else
  3854.         len += formatex(menu[len], charsmax(menu) - len, "\d6. %L^n", id, "MENU_ADMIN6")
  3855.    
  3856.     // 7. Plague mode command
  3857.     if ((userflags & g_access_flag[ACCESS_MODE_PLAGUE]) && allowed_plague())
  3858.         len += formatex(menu[len], charsmax(menu) - len, "\r7.\w %L^n", id, "MENU_ADMIN7")
  3859.     else
  3860.         len += formatex(menu[len], charsmax(menu) - len, "\d7. %L^n", id, "MENU_ADMIN7")
  3861.    
  3862.     // 0. Exit
  3863.     len += formatex(menu[len], charsmax(menu) - len, "^n\r0.\w %L", id, "MENU_EXIT")
  3864.    
  3865.     // Fix for AMXX custom menus
  3866.     if (pev_valid(id) == PDATA_SAFE)
  3867.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3868.    
  3869.     show_menu(id, KEYSMENU, menu, -1, "Admin Menu")
  3870. }
  3871.  
  3872. // Player List Menu
  3873. show_menu_player_list(id)
  3874. {
  3875.     // Player disconnected?
  3876.     if (!g_isconnected[id])
  3877.         return;
  3878.    
  3879.     static menuid, menu[128], player, userflags, buffer[2]
  3880.     userflags = get_user_flags(id)
  3881.    
  3882.     // Title
  3883.     switch (PL_ACTION)
  3884.     {
  3885.         case ACTION_ZOMBIEFY_HUMANIZE: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN1")
  3886.         case ACTION_MAKE_NEMESIS: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN2")
  3887.         case ACTION_MAKE_SURVIVOR: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN3")
  3888.         case ACTION_RESPAWN_PLAYER: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN4")
  3889.     }
  3890.     menuid = menu_create(menu, "menu_player_list")
  3891.    
  3892.     // Player List
  3893.     for (player = 0; player <= g_maxplayers; player++)
  3894.     {
  3895.         // Skip if not connected
  3896.         if (!g_isconnected[player])
  3897.             continue;
  3898.        
  3899.         // Format text depending on the action to take
  3900.         switch (PL_ACTION)
  3901.         {
  3902.             case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  3903.             {
  3904.                 if (g_zombie[player])
  3905.                 {
  3906.                     if (allowed_human(player) && (userflags & g_access_flag[ACCESS_MAKE_HUMAN]))
  3907.                         formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3908.                     else
  3909.                         formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3910.                 }
  3911.                 else
  3912.                 {
  3913.                     if (allowed_zombie(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE])))
  3914.                         formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3915.                     else
  3916.                         formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3917.                 }
  3918.             }
  3919.             case ACTION_MAKE_NEMESIS: // Nemesis command
  3920.             {
  3921.                 if (allowed_nemesis(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS])))
  3922.                 {
  3923.                     if (g_zombie[player])
  3924.                         formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3925.                     else
  3926.                         formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3927.                 }
  3928.                 else
  3929.                     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")
  3930.             }
  3931.             case ACTION_MAKE_SURVIVOR: // Survivor command
  3932.             {
  3933.                 if (allowed_survivor(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR])))
  3934.                 {
  3935.                     if (g_zombie[player])
  3936.                         formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3937.                     else
  3938.                         formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3939.                 }
  3940.                 else
  3941.                     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")
  3942.             }
  3943.             case ACTION_RESPAWN_PLAYER: // Respawn command
  3944.             {
  3945.                 if (allowed_respawn(player) && (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS]))
  3946.                     formatex(menu, charsmax(menu), "%s", g_playername[player])
  3947.                 else
  3948.                     formatex(menu, charsmax(menu), "\d%s", g_playername[player])
  3949.             }
  3950.         }
  3951.        
  3952.         // Add player
  3953.         buffer[0] = player
  3954.         buffer[1] = 0
  3955.         menu_additem(menuid, menu, buffer)
  3956.     }
  3957.    
  3958.     // Back - Next - Exit
  3959.     formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3960.     menu_setprop(menuid, MPROP_BACKNAME, menu)
  3961.     formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3962.     menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3963.     formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3964.     menu_setprop(menuid, MPROP_EXITNAME, menu)
  3965.    
  3966.     // If remembered page is greater than number of pages, clamp down the value
  3967.     MENU_PAGE_PLAYERS = min(MENU_PAGE_PLAYERS, menu_pages(menuid)-1)
  3968.    
  3969.     // Fix for AMXX custom menus
  3970.     if (pev_valid(id) == PDATA_SAFE)
  3971.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3972.    
  3973.     menu_display(id, menuid, MENU_PAGE_PLAYERS)
  3974. }
  3975.  
  3976. /*================================================================================
  3977.  [Menu Handlers]
  3978. =================================================================================*/
  3979.  
  3980. // Game Menu
  3981. public menu_game(id, key)
  3982. {
  3983.     // Player disconnected?
  3984.     if (!g_isconnected[id])
  3985.         return PLUGIN_HANDLED;
  3986.    
  3987.     switch (key)
  3988.     {
  3989.         case 0: // Buy Weapons
  3990.         {
  3991.             // Custom buy menus enabled?
  3992.             if (get_pcvar_num(cvar_buycustom))
  3993.             {
  3994.                 // Disable the remember selection setting
  3995.                 WPN_AUTO_ON = 0
  3996.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "BUY_ENABLED")
  3997.                
  3998.                 // Show menu if player hasn't yet bought anything
  3999.                 if (g_canbuy[id]) show_menu_buy1(id)
  4000.             }
  4001.             else
  4002.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4003.         }
  4004.         case 1: // Extra Items
  4005.         {
  4006.             // Extra items enabled?
  4007.             if (get_pcvar_num(cvar_extraitems))
  4008.             {
  4009.                 // Check whether the player is able to buy anything
  4010.                 if (g_isalive[id])
  4011.                     show_menu_extras(id)
  4012.                 else
  4013.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4014.             }
  4015.             else
  4016.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_EXTRAS")
  4017.         }
  4018.         case 2: // Zombie Classes
  4019.         {
  4020.             // Zombie classes enabled?
  4021.             if (get_pcvar_num(cvar_zclasses))
  4022.                 show_menu_zclass(id)
  4023.             else
  4024.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ZCLASSES")
  4025.         }
  4026.         case 3: // Unstuck
  4027.         {
  4028.             // Check if player is stuck
  4029.             if (g_isalive[id])
  4030.             {
  4031.                 if (is_player_stuck(id))
  4032.                 {
  4033.                     // Move to an initial spawn
  4034.                     if (get_pcvar_num(cvar_randspawn))
  4035.                         do_random_spawn(id) // random spawn (including CSDM)
  4036.                     else
  4037.                         do_random_spawn(id, 1) // regular spawn
  4038.                 }
  4039.                 else
  4040.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_STUCK")
  4041.             }
  4042.             else
  4043.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4044.         }
  4045.         case 4: // Help Menu
  4046.         {
  4047.             show_menu_info(id)
  4048.         }
  4049.         case 5: // Knife Menu
  4050.         {
  4051.             client_cmd(id, "say /knife")
  4052.         }
  4053.         case 6: // Join Spectator
  4054.         {
  4055.             // Player alive?
  4056.             if (g_isalive[id])
  4057.             {
  4058.                 // Prevent abuse by non-admins if block suicide setting is enabled
  4059.                 if (get_pcvar_num(cvar_blocksuicide) && !(get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU]))
  4060.                 {
  4061.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4062.                     return PLUGIN_HANDLED;
  4063.                 }
  4064.                
  4065.                 // Check that we still have both humans and zombies to keep the round going
  4066.                 check_round(id)
  4067.                
  4068.                 // Kill him before he switches team
  4069.                 dllfunc(DLLFunc_ClientKill, id)
  4070.             }
  4071.            
  4072.             // Temporarily save player stats?
  4073.             if (get_pcvar_num(cvar_statssave)) save_stats(id)
  4074.            
  4075.             // Remove previous tasks
  4076.             remove_task(id+TASK_TEAM)
  4077.             remove_task(id+TASK_MODEL)
  4078.             remove_task(id+TASK_FLASH)
  4079.             remove_task(id+TASK_CHARGE)
  4080.             remove_task(id+TASK_SPAWN)
  4081.             remove_task(id+TASK_BLOOD)
  4082.             remove_task(id+TASK_AURA)
  4083.             remove_task(id+TASK_BURN)
  4084.            
  4085.             // Then move him to the spectator team
  4086.             fm_cs_set_user_team(id, FM_CS_TEAM_SPECTATOR)
  4087.             fm_user_team_update(id)
  4088.         }
  4089.         case 9: // Admin Menu
  4090.         {
  4091.             // Check if player has the required access
  4092.             if (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU])
  4093.                 show_menu_admin(id)
  4094.             else
  4095.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4096.         }
  4097.     }
  4098.    
  4099.     return PLUGIN_HANDLED;
  4100. }
  4101.  
  4102. // Buy Menu 1
  4103. public menu_buy1(id, key)
  4104. {
  4105.     // Player dead?
  4106.     if (!g_isalive[id])
  4107.         return PLUGIN_HANDLED;
  4108.    
  4109.     // Zombies or survivors get no guns
  4110.     if (g_zombie[id] || g_survivor[id])
  4111.         return PLUGIN_HANDLED;
  4112.    
  4113.     // Special keys / weapon list exceeded
  4114.     if (key >= MENU_KEY_AUTOSELECT || WPN_SELECTION >= WPN_MAXIDS)
  4115.     {
  4116.         switch (key)
  4117.         {
  4118.             case MENU_KEY_AUTOSELECT: // toggle auto select
  4119.             {
  4120.                 WPN_AUTO_ON = 1 - WPN_AUTO_ON
  4121.             }
  4122.             case MENU_KEY_NEXT: // next/back
  4123.             {
  4124.                 if (WPN_STARTID+7 < WPN_MAXIDS)
  4125.                     WPN_STARTID += 7
  4126.                 else
  4127.                     WPN_STARTID = 0
  4128.             }
  4129.             case MENU_KEY_EXIT: // exit
  4130.             {
  4131.                 return PLUGIN_HANDLED;
  4132.             }
  4133.         }
  4134.        
  4135.         // Show buy menu again
  4136.         show_menu_buy1(id)
  4137.         return PLUGIN_HANDLED;
  4138.     }
  4139.    
  4140.     // Store selected weapon id
  4141.     WPN_AUTO_PRI = WPN_SELECTION
  4142.    
  4143.     // Buy primary weapon
  4144.     buy_primary_weapon(id, WPN_AUTO_PRI)
  4145.    
  4146.     // Show pistols menu
  4147.     show_menu_buy2(id)
  4148.    
  4149.     return PLUGIN_HANDLED;
  4150. }
  4151.  
  4152. // Buy Primary Weapon
  4153. buy_primary_weapon(id, selection)
  4154. {
  4155.     // Drop previous weapons
  4156.     drop_weapons(id, 1)
  4157.     drop_weapons(id, 2)
  4158.    
  4159.     // Strip off from weapons
  4160.     fm_strip_user_weapons(id)
  4161.     fm_give_item(id, "weapon_knife")
  4162.    
  4163.     // Get weapon's id and name
  4164.     static weaponid, wname[32]
  4165.     weaponid = ArrayGetCell(g_primary_weaponids, selection)
  4166.     ArrayGetString(g_primary_items, selection, wname, charsmax(wname))
  4167.    
  4168.     // Give the new weapon and full ammo
  4169.     fm_give_item(id, wname)
  4170.     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4171.    
  4172.     // Weapons bought
  4173.     g_canbuy[id] = false
  4174.    
  4175.     // Give additional items
  4176.     static i
  4177.     for (i = 0; i < ArraySize(g_additional_items); i++)
  4178.     {
  4179.         ArrayGetString(g_additional_items, i, wname, charsmax(wname))
  4180.         fm_give_item(id, wname)
  4181.     }
  4182. }
  4183.  
  4184. // Buy Menu 2
  4185. public menu_buy2(id, key)
  4186. {
  4187.     // Player dead?
  4188.     if (!g_isalive[id])
  4189.         return PLUGIN_HANDLED;
  4190.    
  4191.     // Zombies or survivors get no guns
  4192.     if (g_zombie[id] || g_survivor[id])
  4193.         return PLUGIN_HANDLED;
  4194.    
  4195.     // Special keys / weapon list exceeded
  4196.     if (key >= ArraySize(g_secondary_items))
  4197.     {
  4198.         // Toggle autoselect
  4199.         if (key == MENU_KEY_AUTOSELECT)
  4200.             WPN_AUTO_ON = 1 - WPN_AUTO_ON
  4201.        
  4202.         // Reshow menu unless user exited
  4203.         if (key != MENU_KEY_EXIT)
  4204.             show_menu_buy2(id)
  4205.        
  4206.         return PLUGIN_HANDLED;
  4207.     }
  4208.    
  4209.     // Store selected weapon
  4210.     WPN_AUTO_SEC = key
  4211.    
  4212.     // Drop secondary gun again, in case we picked another (bugfix)
  4213.     drop_weapons(id, 2)
  4214.    
  4215.     // Get weapon's id
  4216.     static weaponid, wname[32]
  4217.     weaponid = ArrayGetCell(g_secondary_weaponids, key)
  4218.     ArrayGetString(g_secondary_items, key, wname, charsmax(wname))
  4219.    
  4220.     // Give the new weapon and full ammo
  4221.     fm_give_item(id, wname)
  4222.     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4223.    
  4224.     return PLUGIN_HANDLED;
  4225. }
  4226.  
  4227. // Extra Items Menu
  4228. public menu_extras(id, menuid, item)
  4229. {
  4230.     // Player disconnected?
  4231.     if (!is_user_connected(id))
  4232.     {
  4233.         menu_destroy(menuid)
  4234.         return PLUGIN_HANDLED;
  4235.     }
  4236.    
  4237.     // Remember player's menu page
  4238.     static menudummy
  4239.     player_menu_info(id, menudummy, menudummy, MENU_PAGE_EXTRAS)
  4240.    
  4241.     // Menu was closed
  4242.     if (item == MENU_EXIT)
  4243.     {
  4244.         menu_destroy(menuid)
  4245.         return PLUGIN_HANDLED;
  4246.     }
  4247.    
  4248.     // Dead players are not allowed to buy items
  4249.     if (!g_isalive[id])
  4250.     {
  4251.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4252.         menu_destroy(menuid)
  4253.         return PLUGIN_HANDLED;
  4254.     }
  4255.    
  4256.     // Retrieve extra item id
  4257.     static buffer[2], dummy, itemid
  4258.     menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4259.     itemid = buffer[0]
  4260.    
  4261.     // Attempt to buy the item
  4262.     buy_extra_item(id, itemid)
  4263.     menu_destroy(menuid)
  4264.     return PLUGIN_HANDLED;
  4265. }
  4266.  
  4267. // Buy Extra Item
  4268. buy_extra_item(id, itemid, ignorecost = 0)
  4269. {
  4270.     // Retrieve item's team
  4271.     static team
  4272.     team = ArrayGetCell(g_extraitem_team, itemid)
  4273.    
  4274.     // Check for team/class specific items
  4275.     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)))
  4276.     {
  4277.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4278.         return;
  4279.     }
  4280.    
  4281.     // Check for unavailable items
  4282.     if ((itemid == EXTRA_NVISION && !get_pcvar_num(cvar_extranvision))
  4283.     || (itemid == EXTRA_ANTIDOTE && (!get_pcvar_num(cvar_extraantidote) || g_antidotecounter >= get_pcvar_num(cvar_antidotelimit)))
  4284.     || (itemid == EXTRA_MADNESS && (!get_pcvar_num(cvar_extramadness) || g_madnesscounter >= get_pcvar_num(cvar_madnesslimit)))
  4285.     || (itemid == EXTRA_INFBOMB && (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit)))
  4286.     || (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)))
  4287.     {
  4288.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4289.         return;
  4290.     }
  4291.    
  4292.     // Check for hard coded items with special conditions
  4293.     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)))
  4294.     || (itemid == EXTRA_MADNESS && g_nodamage[id]) || (itemid == EXTRA_INFBOMB && (g_endround || g_swarmround || g_nemround || g_survround || g_plagueround)))
  4295.     {
  4296.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_CANTUSE")
  4297.         return;
  4298.     }
  4299.    
  4300.     // Ignore item's cost?
  4301.     if (!ignorecost)
  4302.     {
  4303.         // Check that we have enough ammo packs
  4304.         if (g_ammopacks[id] < ArrayGetCell(g_extraitem_cost, itemid))
  4305.         {
  4306.             zp_colored_print(id, "^x04[ZP]^x01 %L", id, "NOT_ENOUGH_AMMO")
  4307.             return;
  4308.         }
  4309.        
  4310.         // Deduce item cost
  4311.         g_ammopacks[id] -= ArrayGetCell(g_extraitem_cost, itemid)
  4312.     }
  4313.    
  4314.     // Check which kind of item we're buying
  4315.     switch (itemid)
  4316.     {
  4317.         case EXTRA_NVISION: // Night Vision
  4318.         {
  4319.             g_nvision[id] = true
  4320.            
  4321.             if (!g_isbot[id])
  4322.             {
  4323.                 g_nvisionenabled[id] = true
  4324.                
  4325.                 // Custom nvg?
  4326.                 if (get_pcvar_num(cvar_customnvg))
  4327.                 {
  4328.                     remove_task(id+TASK_NVISION)
  4329.                     set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  4330.                 }
  4331.                 else
  4332.                     set_user_gnvision(id, 1)
  4333.             }
  4334.             else
  4335.                 cs_set_user_nvg(id, 1)
  4336.         }
  4337.         case EXTRA_ANTIDOTE: // Antidote
  4338.         {
  4339.             // Increase antidote purchase count for this round
  4340.             g_antidotecounter++
  4341.            
  4342.             humanme(id, 0, 0)
  4343.         }
  4344.         case EXTRA_MADNESS: // Zombie Madness
  4345.         {
  4346.             // Increase madness purchase count for this round
  4347.             g_madnesscounter++
  4348.            
  4349.             g_nodamage[id] = true
  4350.             set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
  4351.             set_task(get_pcvar_float(cvar_madnessduration), "madness_over", id+TASK_BLOOD)
  4352.            
  4353.             static sound[64]
  4354.             ArrayGetString(zombie_madness, random_num(0, ArraySize(zombie_madness) - 1), sound, charsmax(sound))
  4355.             emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4356.         }
  4357.         case EXTRA_INFBOMB: // Infection Bomb
  4358.         {
  4359.             // Increase infection bomb purchase count for this round
  4360.             g_infbombcounter++
  4361.            
  4362.             // Already own one
  4363.             if (user_has_weapon(id, CSW_HEGRENADE))
  4364.             {
  4365.                 // Increase BP ammo on it instead
  4366.                 cs_set_user_bpammo(id, CSW_HEGRENADE, cs_get_user_bpammo(id, CSW_HEGRENADE) + 1)
  4367.                
  4368.                 // Flash ammo in hud
  4369.                 message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
  4370.                 write_byte(AMMOID[CSW_HEGRENADE]) // ammo id
  4371.                 write_byte(1) // ammo amount
  4372.                 message_end()
  4373.                
  4374.                 // Play clip purchase sound
  4375.                 emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4376.                
  4377.                 return; // stop here
  4378.             }
  4379.            
  4380.             // Give weapon to the player
  4381.             fm_give_item(id, "weapon_hegrenade")
  4382.         }
  4383.         default:
  4384.         {
  4385.             if (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1) // Weapons
  4386.             {
  4387.                 // Get weapon's id and name
  4388.                 static weaponid, wname[32]
  4389.                 ArrayGetString(g_extraweapon_items, itemid - EXTRA_WEAPONS_STARTID, wname, charsmax(wname))
  4390.                 weaponid = cs_weapon_name_to_id(wname)
  4391.                
  4392.                 // If we are giving a primary/secondary weapon
  4393.                 if (MAXBPAMMO[weaponid] > 2)
  4394.                 {
  4395.                     // Make user drop the previous one
  4396.                     if ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)
  4397.                         drop_weapons(id, 1)
  4398.                     else
  4399.                         drop_weapons(id, 2)
  4400.                    
  4401.                     // Give full BP ammo for the new one
  4402.                     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4403.                 }
  4404.                 // If we are giving a grenade which the user already owns
  4405.                 else if (user_has_weapon(id, weaponid))
  4406.                 {
  4407.                     // Increase BP ammo on it instead
  4408.                     cs_set_user_bpammo(id, weaponid, cs_get_user_bpammo(id, weaponid) + 1)
  4409.                    
  4410.                     // Flash ammo in hud
  4411.                     message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
  4412.                     write_byte(AMMOID[weaponid]) // ammo id
  4413.                     write_byte(1) // ammo amount
  4414.                     message_end()
  4415.                    
  4416.                     // Play clip purchase sound
  4417.                     emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4418.                    
  4419.                     return; // stop here
  4420.                 }
  4421.                
  4422.                 // Give weapon to the player
  4423.                 fm_give_item(id, wname)
  4424.             }
  4425.             else // Custom additions
  4426.             {
  4427.                 // Item selected forward
  4428.                 ExecuteForward(g_fwExtraItemSelected, g_fwDummyResult, id, itemid);
  4429.                
  4430.                 // Item purchase blocked, restore buyer's ammo packs
  4431.                 if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && !ignorecost)
  4432.                     g_ammopacks[id] += ArrayGetCell(g_extraitem_cost, itemid)
  4433.             }
  4434.         }
  4435.     }
  4436. }
  4437.  
  4438. // Zombie Class Menu
  4439. public menu_zclass(id, menuid, item)
  4440. {
  4441.     // Player disconnected?
  4442.     if (!is_user_connected(id))
  4443.     {
  4444.         menu_destroy(menuid)
  4445.         return PLUGIN_HANDLED;
  4446.     }
  4447.    
  4448.     // Remember player's menu page
  4449.     static menudummy
  4450.     player_menu_info(id, menudummy, menudummy, MENU_PAGE_ZCLASS)
  4451.    
  4452.     // Menu was closed
  4453.     if (item == MENU_EXIT)
  4454.     {
  4455.         menu_destroy(menuid)
  4456.         return PLUGIN_HANDLED;
  4457.     }
  4458.    
  4459.     // Retrieve zombie class id
  4460.     static buffer[2], dummy, classid
  4461.     menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4462.     classid = buffer[0]
  4463.    
  4464.     // Store selection for the next infection
  4465.     g_zombieclassnext[id] = classid
  4466.    
  4467.     static name[32]
  4468.     ArrayGetString(g_zclass_name, g_zombieclassnext[id], name, charsmax(name))
  4469.    
  4470.     // Show selected zombie class info and stats
  4471.     zp_colored_print(id, "^x04[ZP]^x01 %L: %s", id, "ZOMBIE_SELECT", name)
  4472.     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]),
  4473.     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))
  4474.    
  4475.     menu_destroy(menuid)
  4476.     return PLUGIN_HANDLED;
  4477. }
  4478.  
  4479. // Info Menu
  4480. public menu_info(id, key)
  4481. {
  4482.     // Player disconnected?
  4483.     if (!g_isconnected[id])
  4484.         return PLUGIN_HANDLED;
  4485.    
  4486.     static motd[1500], len
  4487.     len = 0
  4488.    
  4489.     switch (key)
  4490.     {
  4491.         case 0: // General
  4492.         {
  4493.             static weather, lighting[2]
  4494.             weather = 0
  4495.             get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
  4496.             strtolower(lighting)
  4497.            
  4498.             len += formatex(motd[len], charsmax(motd) - len, "%L ", id, "MOTD_INFO11", "Zombie Plague", PLUGIN_VERSION, "MeRcyLeZZ")
  4499.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO12")
  4500.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_A")
  4501.            
  4502.             if (g_ambience_fog)
  4503.             {
  4504.                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_FOG")
  4505.                 weather++
  4506.             }
  4507.             if (g_ambience_rain)
  4508.             {
  4509.                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_RAIN")
  4510.                 weather++
  4511.             }
  4512.             if (g_ambience_snow)
  4513.             {
  4514.                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_SNOW")
  4515.                 weather++
  4516.             }
  4517.             if (weather < 1) len += formatex(motd[len], charsmax(motd) - len, " %L", id, "MOTD_DISABLED")
  4518.            
  4519.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_B", lighting)
  4520.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_C", id, get_pcvar_num(cvar_triggered) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4521.             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)))
  4522.             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")
  4523.             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")
  4524.             if (get_pcvar_num(cvar_deathmatch)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_G", floatround(get_pcvar_float(cvar_spawnprotection)))
  4525.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_H", id, get_pcvar_num(cvar_randspawn) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4526.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_I", id, get_pcvar_num(cvar_extraitems) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4527.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_J", id, get_pcvar_num(cvar_zclasses) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4528.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_K", id, get_pcvar_num(cvar_customnvg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4529.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_L", id, g_cached_customflash ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4530.            
  4531.             show_motd(id, motd)
  4532.         }
  4533.         case 1: // Humans
  4534.         {
  4535.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2")
  4536.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_A", get_pcvar_num(cvar_humanhp))
  4537.             if (get_pcvar_num(cvar_humanlasthp) > 0) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_B", get_pcvar_num(cvar_humanlasthp))
  4538.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_C", get_pcvar_num(cvar_humanspd))
  4539.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_D", floatround(get_pcvar_float(cvar_humangravity) * 800.0))
  4540.             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")
  4541.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_F", get_pcvar_num(cvar_ammodamage_human))
  4542.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_G", id, get_pcvar_num(cvar_firegrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4543.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_H", id, get_pcvar_num(cvar_frostgrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4544.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_I", id, get_pcvar_num(cvar_flaregrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4545.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_J", id, get_pcvar_num(cvar_knockback) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4546.            
  4547.             show_motd(id, motd)
  4548.         }
  4549.         case 2: // Zombies
  4550.         {
  4551.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3")
  4552.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_A", ArrayGetCell(g_zclass_hp, 0))
  4553.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_B", floatround(float(ArrayGetCell(g_zclass_hp, 0)) * get_pcvar_float(cvar_zombiefirsthp)))
  4554.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_C", floatround(get_pcvar_float(cvar_zombiearmor) * 100.0))
  4555.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_D", ArrayGetCell(g_zclass_spd, 0))
  4556.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_E", floatround(Float:ArrayGetCell(g_zclass_grav, 0) * 800.0))
  4557.             if (get_pcvar_num(cvar_zombiebonushp)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_F", get_pcvar_num(cvar_zombiebonushp))
  4558.             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")
  4559.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_H", id, get_pcvar_num(cvar_zombiebleeding) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4560.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_I", get_pcvar_num(cvar_ammoinfect))
  4561.            
  4562.             show_motd(id, motd)
  4563.         }
  4564.         case 3: // Gameplay Modes
  4565.         {
  4566.             static nemhp[5], survhp[5]
  4567.            
  4568.             // Get nemesis and survivor health
  4569.             num_to_str(get_pcvar_num(cvar_nemhp), nemhp, charsmax(nemhp))
  4570.             num_to_str(get_pcvar_num(cvar_survhp), survhp, charsmax(survhp))
  4571.            
  4572.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4")
  4573.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_A", id, get_pcvar_num(cvar_nem) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4574.             if (get_pcvar_num(cvar_nem))
  4575.             {
  4576.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_B", get_pcvar_num(cvar_nemchance))
  4577.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_C", get_pcvar_num(cvar_nemhp) > 0 ? nemhp : "[Auto]")
  4578.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_D", get_pcvar_num(cvar_nemspd))
  4579.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_E", floatround(get_pcvar_float(cvar_nemgravity) * 800.0))
  4580.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_F", id, g_cached_leapnemesis ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4581.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_G", id, get_pcvar_num(cvar_nempainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4582.             }
  4583.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_H", id, get_pcvar_num(cvar_surv) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4584.             if (get_pcvar_num(cvar_surv))
  4585.             {
  4586.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_I", get_pcvar_num(cvar_survchance))
  4587.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_J", get_pcvar_num(cvar_survhp) > 0 ? survhp : "[Auto]")
  4588.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_K", get_pcvar_num(cvar_survspd))
  4589.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_L", floatround(get_pcvar_float(cvar_survgravity) * 800.0))
  4590.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_M", id, g_cached_leapsurvivor ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4591.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_N", id, get_pcvar_num(cvar_survpainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4592.             }
  4593.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_O", id, get_pcvar_num(cvar_swarm) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4594.             if (get_pcvar_num(cvar_swarm)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_P", get_pcvar_num(cvar_swarmchance))
  4595.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_Q", id, get_pcvar_num(cvar_multi) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4596.             if (get_pcvar_num(cvar_multi))
  4597.             {
  4598.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_R", get_pcvar_num(cvar_multichance))
  4599.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_S", floatround(get_pcvar_float(cvar_multiratio) * 100.0))
  4600.             }
  4601.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_T", id, get_pcvar_num(cvar_plague) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4602.             if (get_pcvar_num(cvar_plague))
  4603.             {
  4604.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_U", get_pcvar_num(cvar_plaguechance))
  4605.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_V", floatround(get_pcvar_float(cvar_plagueratio) * 100.0))
  4606.             }
  4607.            
  4608.             show_motd(id, motd)
  4609.         }
  4610.         default: return PLUGIN_HANDLED;
  4611.     }
  4612.    
  4613.     // Show help menu again if user wishes to read another topic
  4614.     show_menu_info(id)
  4615.    
  4616.     return PLUGIN_HANDLED;
  4617. }
  4618.  
  4619. // Admin Menu
  4620. public menu_admin(id, key)
  4621. {
  4622.     // Player disconnected?
  4623.     if (!g_isconnected[id])
  4624.         return PLUGIN_HANDLED;
  4625.    
  4626.     static userflags
  4627.     userflags = get_user_flags(id)
  4628.    
  4629.     switch (key)
  4630.     {
  4631.         case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  4632.         {
  4633.             if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
  4634.             {
  4635.                 // Show player list for admin to pick a target
  4636.                 PL_ACTION = ACTION_ZOMBIEFY_HUMANIZE
  4637.                 show_menu_player_list(id)
  4638.             }
  4639.             else
  4640.             {
  4641.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4642.                 show_menu_admin(id)
  4643.             }
  4644.         }
  4645.         case ACTION_MAKE_NEMESIS: // Nemesis command
  4646.         {
  4647.             if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
  4648.             {
  4649.                 // Show player list for admin to pick a target
  4650.                 PL_ACTION = ACTION_MAKE_NEMESIS
  4651.                 show_menu_player_list(id)
  4652.             }
  4653.             else
  4654.             {
  4655.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4656.                 show_menu_admin(id)
  4657.             }
  4658.         }
  4659.         case ACTION_MAKE_SURVIVOR: // Survivor command
  4660.         {
  4661.             if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
  4662.             {
  4663.                 // Show player list for admin to pick a target
  4664.                 PL_ACTION = ACTION_MAKE_SURVIVOR
  4665.                 show_menu_player_list(id)
  4666.             }
  4667.             else
  4668.             {
  4669.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4670.                 show_menu_admin(id)
  4671.             }
  4672.         }
  4673.         case ACTION_RESPAWN_PLAYER: // Respawn command
  4674.         {
  4675.             if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  4676.             {
  4677.                 // Show player list for admin to pick a target
  4678.                 PL_ACTION = ACTION_RESPAWN_PLAYER
  4679.                 show_menu_player_list(id)
  4680.             }
  4681.             else
  4682.             {
  4683.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4684.                 show_menu_admin(id)
  4685.             }
  4686.         }
  4687.         case ACTION_MODE_SWARM: // Swarm Mode command
  4688.         {
  4689.             if (userflags & g_access_flag[ACCESS_MODE_SWARM])
  4690.             {
  4691.                 if (allowed_swarm())
  4692.                     command_swarm(id)
  4693.                 else
  4694.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4695.             }
  4696.             else
  4697.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4698.            
  4699.             show_menu_admin(id)
  4700.         }
  4701.         case ACTION_MODE_MULTI: // Multiple Infection command
  4702.         {
  4703.             if (userflags & g_access_flag[ACCESS_MODE_MULTI])
  4704.             {
  4705.                 if (allowed_multi())
  4706.                     command_multi(id)
  4707.                 else
  4708.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4709.             }
  4710.             else
  4711.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4712.            
  4713.             show_menu_admin(id)
  4714.         }
  4715.         case ACTION_MODE_PLAGUE: // Plague Mode command
  4716.         {
  4717.             if (userflags & g_access_flag[ACCESS_MODE_PLAGUE])
  4718.             {
  4719.                 if (allowed_plague())
  4720.                     command_plague(id)
  4721.                 else
  4722.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4723.             }
  4724.             else
  4725.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4726.            
  4727.             show_menu_admin(id)
  4728.         }
  4729.     }
  4730.    
  4731.     return PLUGIN_HANDLED;
  4732. }
  4733.  
  4734. // Player List Menu
  4735. public menu_player_list(id, menuid, item)
  4736. {
  4737.     // Player disconnected?
  4738.     if (!is_user_connected(id))
  4739.     {
  4740.         menu_destroy(menuid)
  4741.         return PLUGIN_HANDLED;
  4742.     }
  4743.    
  4744.     // Remember player's menu page
  4745.     static menudummy
  4746.     player_menu_info(id, menudummy, menudummy, MENU_PAGE_PLAYERS)
  4747.    
  4748.     // Menu was closed
  4749.     if (item == MENU_EXIT)
  4750.     {
  4751.         menu_destroy(menuid)
  4752.         show_menu_admin(id)
  4753.         return PLUGIN_HANDLED;
  4754.     }
  4755.    
  4756.     // Retrieve player id
  4757.     static buffer[2], dummy, playerid
  4758.     menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4759.     playerid = buffer[0]
  4760.    
  4761.     // Perform action on player
  4762.    
  4763.     // Get admin flags
  4764.     static userflags
  4765.     userflags = get_user_flags(id)
  4766.    
  4767.     // Make sure it's still connected
  4768.     if (g_isconnected[playerid])
  4769.     {
  4770.         // Perform the right action if allowed
  4771.         switch (PL_ACTION)
  4772.         {
  4773.             case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  4774.             {
  4775.                 if (g_zombie[playerid])
  4776.                 {
  4777.                     if (userflags & g_access_flag[ACCESS_MAKE_HUMAN])
  4778.                     {
  4779.                         if (allowed_human(playerid))
  4780.                             command_human(id, playerid)
  4781.                         else
  4782.                             zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4783.                     }
  4784.                     else
  4785.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4786.                 }
  4787.                 else
  4788.                 {
  4789.                     if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE]))
  4790.                     {
  4791.                         if (allowed_zombie(playerid))
  4792.                             command_zombie(id, playerid)
  4793.                         else
  4794.                             zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4795.                     }
  4796.                     else
  4797.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4798.                 }
  4799.             }
  4800.             case ACTION_MAKE_NEMESIS: // Nemesis command
  4801.             {
  4802.                 if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS]))
  4803.                 {
  4804.                     if (allowed_nemesis(playerid))
  4805.                         command_nemesis(id, playerid)
  4806.                     else
  4807.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4808.                 }
  4809.                 else
  4810.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4811.             }
  4812.             case ACTION_MAKE_SURVIVOR: // Survivor command
  4813.             {
  4814.                 if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR]))
  4815.                 {
  4816.                     if (allowed_survivor(playerid))
  4817.                         command_survivor(id, playerid)
  4818.                     else
  4819.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4820.                 }
  4821.                 else
  4822.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4823.             }
  4824.             case ACTION_RESPAWN_PLAYER: // Respawn command
  4825.             {
  4826.                 if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  4827.                 {
  4828.                     if (allowed_respawn(playerid))
  4829.                         command_respawn(id, playerid)
  4830.                     else
  4831.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4832.                 }
  4833.                 else
  4834.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4835.             }
  4836.         }
  4837.     }
  4838.     else
  4839.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4840.    
  4841.     menu_destroy(menuid)
  4842.     show_menu_player_list(id)
  4843.     return PLUGIN_HANDLED;
  4844. }
  4845.  
  4846. // CS Buy Menus
  4847. public menu_cs_buy(id, key)
  4848. {
  4849.     // Prevent buying if zombie/survivor (bugfix)
  4850.     if (g_zombie[id] || g_survivor[id])
  4851.         return PLUGIN_HANDLED;
  4852.    
  4853.     return PLUGIN_CONTINUE;
  4854. }
  4855.  
  4856. /*================================================================================
  4857.  [Admin Commands]
  4858. =================================================================================*/
  4859.  
  4860. // zp_toggle [1/0]
  4861. public cmd_toggle(id, level, cid)
  4862. {
  4863.     // Check for access flag - Enable/Disable Mod
  4864.     if (!cmd_access(id, g_access_flag[ACCESS_ENABLE_MOD], cid, 2))
  4865.         return PLUGIN_HANDLED;
  4866.    
  4867.     // Retrieve arguments
  4868.     new arg[2]
  4869.     read_argv(1, arg, charsmax(arg))
  4870.    
  4871.     // Mod already enabled/disabled
  4872.     if (str_to_num(arg) == g_pluginenabled)
  4873.         return PLUGIN_HANDLED;
  4874.    
  4875.     // Set toggle cvar
  4876.     set_pcvar_num(cvar_toggle, str_to_num(arg))
  4877.     client_print(id, print_console, "Zombie Plague %L.", id, str_to_num(arg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4878.    
  4879.     // Retrieve map name
  4880.     new mapname[32]
  4881.     get_mapname(mapname, charsmax(mapname))
  4882.    
  4883.     // Restart current map
  4884.     server_cmd("changelevel %s", mapname)
  4885.    
  4886.     return PLUGIN_HANDLED;
  4887. }
  4888.  
  4889. // zp_zombie [target]
  4890. public cmd_zombie(id, level, cid)
  4891. {
  4892.     // Check for access flag depending on the resulting action
  4893.     if (g_newround)
  4894.     {
  4895.         // Start Mode Infection
  4896.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_INFECTION], cid, 2))
  4897.             return PLUGIN_HANDLED;
  4898.     }
  4899.     else
  4900.     {
  4901.         // Make Zombie
  4902.         if (!cmd_access(id, g_access_flag[ACCESS_MAKE_ZOMBIE], cid, 2))
  4903.             return PLUGIN_HANDLED;
  4904.     }
  4905.    
  4906.     // Retrieve arguments
  4907.     static arg[32], player
  4908.     read_argv(1, arg, charsmax(arg))
  4909.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4910.    
  4911.     // Invalid target
  4912.     if (!player) return PLUGIN_HANDLED;
  4913.    
  4914.     // Target not allowed to be zombie
  4915.     if (!allowed_zombie(player))
  4916.     {
  4917.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4918.         return PLUGIN_HANDLED
  4919.     }
  4920.    
  4921.     command_zombie(id, player)
  4922.    
  4923.     return PLUGIN_HANDLED;
  4924. }
  4925.  
  4926. // zp_human [target]
  4927. public cmd_human(id, level, cid)
  4928. {
  4929.     // Check for access flag - Make Human
  4930.     if (!cmd_access(id, g_access_flag[ACCESS_MAKE_HUMAN], cid, 2))
  4931.         return PLUGIN_HANDLED;
  4932.    
  4933.     // Retrieve arguments
  4934.     static arg[32], player
  4935.     read_argv(1, arg, charsmax(arg))
  4936.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4937.    
  4938.     // Invalid target
  4939.     if (!player) return PLUGIN_HANDLED;
  4940.    
  4941.     // Target not allowed to be human
  4942.     if (!allowed_human(player))
  4943.     {
  4944.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4945.         return PLUGIN_HANDLED;
  4946.     }
  4947.    
  4948.     command_human(id, player)
  4949.    
  4950.     return PLUGIN_HANDLED;
  4951. }
  4952.  
  4953. // zp_survivor [target]
  4954. public cmd_survivor(id, level, cid)
  4955. {
  4956.     // Check for access flag depending on the resulting action
  4957.     if (g_newround)
  4958.     {
  4959.         // Start Mode Survivor
  4960.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_SURVIVOR], cid, 2))
  4961.             return PLUGIN_HANDLED;
  4962.     }
  4963.     else
  4964.     {
  4965.         // Make Survivor
  4966.         if (!cmd_access(id, g_access_flag[ACCESS_MAKE_SURVIVOR], cid, 2))
  4967.             return PLUGIN_HANDLED;
  4968.     }
  4969.    
  4970.     // Retrieve arguments
  4971.     static arg[32], player
  4972.     read_argv(1, arg, charsmax(arg))
  4973.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4974.    
  4975.     // Invalid target
  4976.     if (!player) return PLUGIN_HANDLED;
  4977.    
  4978.     // Target not allowed to be survivor
  4979.     if (!allowed_survivor(player))
  4980.     {
  4981.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4982.         return PLUGIN_HANDLED;
  4983.     }
  4984.    
  4985.     command_survivor(id, player)
  4986.    
  4987.     return PLUGIN_HANDLED;
  4988. }
  4989.  
  4990. // zp_nemesis [target]
  4991. public cmd_nemesis(id, level, cid)
  4992. {
  4993.     // Check for access flag depending on the resulting action
  4994.     if (g_newround)
  4995.     {
  4996.         // Start Mode Nemesis
  4997.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_NEMESIS], cid, 2))
  4998.             return PLUGIN_HANDLED;
  4999.     }
  5000.     else
  5001.     {
  5002.         // Make Nemesis
  5003.         if (!cmd_access(id, g_access_flag[ACCESS_MAKE_NEMESIS], cid, 2))
  5004.             return PLUGIN_HANDLED;
  5005.     }
  5006.    
  5007.     // Retrieve arguments
  5008.     static arg[32], player
  5009.     read_argv(1, arg, charsmax(arg))
  5010.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  5011.    
  5012.     // Invalid target
  5013.     if (!player) return PLUGIN_HANDLED;
  5014.    
  5015.     // Target not allowed to be nemesis
  5016.     if (!allowed_nemesis(player))
  5017.     {
  5018.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5019.         return PLUGIN_HANDLED;
  5020.     }
  5021.    
  5022.     command_nemesis(id, player)
  5023.    
  5024.     return PLUGIN_HANDLED;
  5025. }
  5026.  
  5027. // zp_respawn [target]
  5028. public cmd_respawn(id, level, cid)
  5029. {
  5030.     // Check for access flag - Respawn
  5031.     if (!cmd_access(id, g_access_flag[ACCESS_RESPAWN_PLAYERS], cid, 2))
  5032.         return PLUGIN_HANDLED;
  5033.    
  5034.     // Retrieve arguments
  5035.     static arg[32], player
  5036.     read_argv(1, arg, charsmax(arg))
  5037.     player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
  5038.    
  5039.     // Invalid target
  5040.     if (!player) return PLUGIN_HANDLED;
  5041.    
  5042.     // Target not allowed to be respawned
  5043.     if (!allowed_respawn(player))
  5044.     {
  5045.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5046.         return PLUGIN_HANDLED;
  5047.     }
  5048.    
  5049.     command_respawn(id, player)
  5050.    
  5051.     return PLUGIN_HANDLED;
  5052. }
  5053.  
  5054. // zp_swarm
  5055. public cmd_swarm(id, level, cid)
  5056. {
  5057.     // Check for access flag - Mode Swarm
  5058.     if (!cmd_access(id, g_access_flag[ACCESS_MODE_SWARM], cid, 1))
  5059.         return PLUGIN_HANDLED;
  5060.    
  5061.     // Swarm mode not allowed
  5062.     if (!allowed_swarm())
  5063.     {
  5064.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5065.         return PLUGIN_HANDLED;
  5066.     }
  5067.    
  5068.     command_swarm(id)
  5069.    
  5070.     return PLUGIN_HANDLED;
  5071. }
  5072.  
  5073. // zp_multi
  5074. public cmd_multi(id, level, cid)
  5075. {
  5076.     // Check for access flag - Mode Multi
  5077.     if (!cmd_access(id, g_access_flag[ACCESS_MODE_MULTI], cid, 1))
  5078.         return PLUGIN_HANDLED;
  5079.    
  5080.     // Multi infection mode not allowed
  5081.     if (!allowed_multi())
  5082.     {
  5083.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5084.         return PLUGIN_HANDLED;
  5085.     }
  5086.    
  5087.     command_multi(id)
  5088.    
  5089.     return PLUGIN_HANDLED;
  5090. }
  5091.  
  5092. // zp_plague
  5093. public cmd_plague(id, level, cid)
  5094. {
  5095.     // Check for access flag - Mode Plague
  5096.     if (!cmd_access(id, g_access_flag[ACCESS_MODE_PLAGUE], cid, 1))
  5097.         return PLUGIN_HANDLED;
  5098.    
  5099.     // Plague mode not allowed
  5100.     if (!allowed_plague())
  5101.     {
  5102.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5103.         return PLUGIN_HANDLED;
  5104.     }
  5105.    
  5106.     command_plague(id)
  5107.    
  5108.     return PLUGIN_HANDLED;
  5109. }
  5110.  
  5111. /*================================================================================
  5112.  [Message Hooks]
  5113. =================================================================================*/
  5114.  
  5115. // Current Weapon info
  5116. public message_cur_weapon(msg_id, msg_dest, msg_entity)
  5117. {
  5118.     // Not alive or zombie
  5119.     if (!g_isalive[msg_entity] || g_zombie[msg_entity])
  5120.         return;
  5121.    
  5122.     // Not an active weapon
  5123.     if (get_msg_arg_int(1) != 1)
  5124.         return;
  5125.    
  5126.     // Unlimited clip disabled for class
  5127.     if (g_survivor[msg_entity] ? get_pcvar_num(cvar_survinfammo) <= 1 : get_pcvar_num(cvar_infammo) <= 1)
  5128.         return;
  5129.    
  5130.     // Get weapon's id
  5131.     static weapon
  5132.     weapon = get_msg_arg_int(2)
  5133.    
  5134.     // Unlimited Clip Ammo for this weapon?
  5135.     if (MAXBPAMMO[weapon] > 2)
  5136.     {
  5137.         // Max out clip ammo
  5138.         static weapon_ent
  5139.         weapon_ent = fm_cs_get_current_weapon_ent(msg_entity)
  5140.         if (pev_valid(weapon_ent)) cs_set_weapon_ammo(weapon_ent, MAXCLIP[weapon])
  5141.        
  5142.         // HUD should show full clip all the time
  5143.         set_msg_arg_int(3, get_msg_argtype(3), MAXCLIP[weapon])
  5144.     }
  5145. }
  5146.  
  5147. // Take off player's money
  5148. public message_money(msg_id, msg_dest, msg_entity)
  5149. {
  5150.     // Remove money setting enabled?
  5151.     if (!get_pcvar_num(cvar_removemoney))
  5152.         return PLUGIN_CONTINUE;
  5153.    
  5154.     fm_cs_set_user_money(msg_entity, 0)
  5155.     return PLUGIN_HANDLED;
  5156. }
  5157.  
  5158. // Fix for the HL engine bug when HP is multiples of 256
  5159. public message_health(msg_id, msg_dest, msg_entity)
  5160. {
  5161.     // Get player's health
  5162.     static health
  5163.     health = get_msg_arg_int(1)
  5164.    
  5165.     // Don't bother
  5166.     if (health < 256) return;
  5167.    
  5168.     // Check if we need to fix it
  5169.     if (health % 256 == 0)
  5170.         fm_set_user_health(msg_entity, pev(msg_entity, pev_health) + 1)
  5171.    
  5172.     // HUD can only show as much as 255 hp
  5173.     set_msg_arg_int(1, get_msg_argtype(1), 255)
  5174. }
  5175.  
  5176. // Block flashlight battery messages if custom flashlight is enabled instead
  5177. public message_flashbat()
  5178. {
  5179.     if (g_cached_customflash)
  5180.         return PLUGIN_HANDLED;
  5181.    
  5182.     return PLUGIN_CONTINUE;
  5183. }
  5184.  
  5185. // Flashbangs should only affect zombies
  5186. public message_screenfade(msg_id, msg_dest, msg_entity)
  5187. {
  5188.     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)
  5189.         return PLUGIN_CONTINUE;
  5190.    
  5191.     // Nemesis shouldn't be FBed
  5192.     if (g_zombie[msg_entity] && !g_nemesis[msg_entity])
  5193.     {
  5194.         // Set flash color to nighvision's
  5195.         set_msg_arg_int(4, get_msg_argtype(4), get_pcvar_num(cvar_nvgcolor[0]))
  5196.         set_msg_arg_int(5, get_msg_argtype(5), get_pcvar_num(cvar_nvgcolor[1]))
  5197.         set_msg_arg_int(6, get_msg_argtype(6), get_pcvar_num(cvar_nvgcolor[2]))
  5198.         return PLUGIN_CONTINUE;
  5199.     }
  5200.    
  5201.     return PLUGIN_HANDLED;
  5202. }
  5203.  
  5204. // Prevent spectators' nightvision from being turned off when switching targets, etc.
  5205. public message_nvgtoggle()
  5206. {
  5207.     return PLUGIN_HANDLED;
  5208. }
  5209.  
  5210. // Set correct model on player corpses
  5211. public message_clcorpse()
  5212. {
  5213.     set_msg_arg_string(1, g_playermodel[get_msg_arg_int(12)])
  5214. }
  5215.  
  5216. // Prevent zombies from seeing any weapon pickup icon
  5217. public message_weappickup(msg_id, msg_dest, msg_entity)
  5218. {
  5219.     if (g_zombie[msg_entity])
  5220.         return PLUGIN_HANDLED;
  5221.    
  5222.     return PLUGIN_CONTINUE;
  5223. }
  5224.  
  5225. // Prevent zombies from seeing any ammo pickup icon
  5226. public message_ammopickup(msg_id, msg_dest, msg_entity)
  5227. {
  5228.     if (g_zombie[msg_entity])
  5229.         return PLUGIN_HANDLED;
  5230.    
  5231.     return PLUGIN_CONTINUE;
  5232. }
  5233.  
  5234. // Block hostage HUD display
  5235. public message_scenario()
  5236. {
  5237.     if (get_msg_args() > 1)
  5238.     {
  5239.         static sprite[8]
  5240.         get_msg_arg_string(2, sprite, charsmax(sprite))
  5241.        
  5242.         if (equal(sprite, "hostage"))
  5243.             return PLUGIN_HANDLED;
  5244.     }
  5245.    
  5246.     return PLUGIN_CONTINUE;
  5247. }
  5248.  
  5249. // Block hostages from appearing on radar
  5250. public message_hostagepos()
  5251. {
  5252.     return PLUGIN_HANDLED;
  5253. }
  5254.  
  5255. // Block some text messages
  5256. public message_textmsg()
  5257. {
  5258.     static textmsg[22]
  5259.     get_msg_arg_string(2, textmsg, charsmax(textmsg))
  5260.    
  5261.     // Game restarting, reset scores and call round end to balance the teams
  5262.     if (equal(textmsg, "#Game_will_restart_in"))
  5263.     {
  5264.         logevent_round_end()
  5265.         g_scorehumans = 0
  5266.         g_scorezombies = 0
  5267.     }
  5268.     // Game commencing, reset scores only (round end is automatically triggered)
  5269.     else if (equal(textmsg, "#Game_Commencing"))
  5270.     {
  5271.         g_gamecommencing = true
  5272.         g_scorehumans = 0
  5273.         g_scorezombies = 0
  5274.     }
  5275.     // Block round end related messages
  5276.     else if (equal(textmsg, "#Hostages_Not_Rescued") || equal(textmsg, "#Round_Draw") || equal(textmsg, "#Terrorists_Win") || equal(textmsg, "#CTs_Win"))
  5277.     {
  5278.         return PLUGIN_HANDLED;
  5279.     }
  5280.    
  5281.     return PLUGIN_CONTINUE;
  5282. }
  5283.  
  5284. // Block CS round win audio messages, since we're playing our own instead
  5285. public message_sendaudio()
  5286. {
  5287.     static audio[17]
  5288.     get_msg_arg_string(2, audio, charsmax(audio))
  5289.    
  5290.     if(equal(audio[7], "terwin") || equal(audio[7], "ctwin") || equal(audio[7], "rounddraw"))
  5291.         return PLUGIN_HANDLED;
  5292.    
  5293.     return PLUGIN_CONTINUE;
  5294. }
  5295.  
  5296. // Send actual team scores (T = zombies // CT = humans)
  5297. public message_teamscore()
  5298. {
  5299.     static team[2]
  5300.     get_msg_arg_string(1, team, charsmax(team))
  5301.    
  5302.     switch (team[0])
  5303.     {
  5304.         // CT
  5305.         case 'C': set_msg_arg_int(2, get_msg_argtype(2), g_scorehumans)
  5306.         // Terrorist
  5307.         case 'T': set_msg_arg_int(2, get_msg_argtype(2), g_scorezombies)
  5308.     }
  5309. }
  5310.  
  5311. // Team Switch (or player joining a team for first time)
  5312. public message_teaminfo(msg_id, msg_dest)
  5313. {
  5314.     // Only hook global messages
  5315.     if (msg_dest != MSG_ALL && msg_dest != MSG_BROADCAST) return;
  5316.    
  5317.     // Don't pick up our own TeamInfo messages for this player (bugfix)
  5318.     if (g_switchingteam) return;
  5319.    
  5320.     // Get player's id
  5321.     static id
  5322.     id = get_msg_arg_int(1)
  5323.    
  5324.     // Invalid player id? (bugfix)
  5325.     if (!(1 <= id <= g_maxplayers)) return;
  5326.    
  5327.     // Enable spectators' nightvision if not spawning right away
  5328.     set_task(0.2, "spec_nvision", id)
  5329.    
  5330.     // Round didn't start yet, nothing to worry about
  5331.     if (g_newround) return;
  5332.    
  5333.     // Get his new team
  5334.     static team[2]
  5335.     get_msg_arg_string(2, team, charsmax(team))
  5336.    
  5337.     // Perform some checks to see if they should join a different team instead
  5338.     switch (team[0])
  5339.     {
  5340.         case 'C': // CT
  5341.         {
  5342.             if (g_survround && fnGetHumans()) // survivor alive --> switch to T and spawn as zombie
  5343.             {
  5344.                 g_respawn_as_zombie[id] = true;
  5345.                 remove_task(id+TASK_TEAM)
  5346.                 fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5347.                 set_msg_arg_string(2, "TERRORIST")
  5348.             }
  5349.             else if (!fnGetZombies()) // no zombies alive --> switch to T and spawn as zombie
  5350.             {
  5351.                 g_respawn_as_zombie[id] = true;
  5352.                 remove_task(id+TASK_TEAM)
  5353.                 fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5354.                 set_msg_arg_string(2, "TERRORIST")
  5355.             }
  5356.         }
  5357.         case 'T': // Terrorist
  5358.         {
  5359.             if ((g_swarmround || g_survround) && fnGetHumans()) // survivor alive or swarm round w/ humans --> spawn as zombie
  5360.             {
  5361.                 g_respawn_as_zombie[id] = true;
  5362.             }
  5363.             else if (fnGetZombies()) // zombies alive --> switch to CT
  5364.             {
  5365.                 remove_task(id+TASK_TEAM)
  5366.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5367.                 set_msg_arg_string(2, "CT")
  5368.             }
  5369.         }
  5370.     }
  5371. }
  5372.  
  5373. /*================================================================================
  5374.  [Main Functions]
  5375. =================================================================================*/
  5376.  
  5377. // Make Zombie Task
  5378. public make_zombie_task()
  5379. {
  5380.     // Call make a zombie with no specific mode
  5381.     make_a_zombie(MODE_NONE, 0)
  5382. }
  5383.  
  5384. // Make a Zombie Function
  5385. make_a_zombie(mode, id)
  5386. {
  5387.     // Get alive players count
  5388.     static iPlayersnum
  5389.     iPlayersnum = fnGetAlive()
  5390.    
  5391.     // Not enough players, come back later!
  5392.     if (iPlayersnum < 1)
  5393.     {
  5394.         set_task(2.0, "make_zombie_task", TASK_MAKEZOMBIE)
  5395.         return;
  5396.     }
  5397.    
  5398.     // Round started!
  5399.     g_newround = false
  5400.    
  5401.     // Set up some common vars
  5402.     static forward_id, sound[64], iZombies, iMaxZombies
  5403.    
  5404.     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)
  5405.     {
  5406.         // Survivor Mode
  5407.         g_survround = true
  5408.         g_lastmode = MODE_SURVIVOR
  5409.        
  5410.         // Choose player randomly?
  5411.         if (mode == MODE_NONE)
  5412.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5413.        
  5414.         // Remember id for calling our forward later
  5415.         forward_id = id
  5416.        
  5417.         // Turn player into a survivor
  5418.         humanme(id, 1, 0)
  5419.        
  5420.         // Turn the remaining players into zombies
  5421.         for (id = 1; id <= g_maxplayers; id++)
  5422.         {
  5423.             // Not alive
  5424.             if (!g_isalive[id])
  5425.                 continue;
  5426.            
  5427.             // Survivor or already a zombie
  5428.             if (g_survivor[id] || g_zombie[id])
  5429.                 continue;
  5430.            
  5431.             // Turn into a zombie
  5432.             zombieme(id, 0, 0, 1, 0)
  5433.         }
  5434.        
  5435.         // Play survivor sound
  5436.         ArrayGetString(sound_survivor, random_num(0, ArraySize(sound_survivor) - 1), sound, charsmax(sound))
  5437.         PlaySound(sound);
  5438.        
  5439.         // Show Survivor HUD notice
  5440.         set_hudmessage(20, 20, 255, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5441.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SURVIVOR", g_playername[forward_id])
  5442.        
  5443.         // Mode fully started!
  5444.         g_modestarted = true
  5445.        
  5446.         // Round start forward
  5447.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SURVIVOR, forward_id);
  5448.     }
  5449.     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)
  5450.     {      
  5451.         // Swarm Mode
  5452.         g_swarmround = true
  5453.         g_lastmode = MODE_SWARM
  5454.        
  5455.         // Make sure there are alive players on both teams (BUGFIX)
  5456.         if (!fnGetAliveTs())
  5457.         {
  5458.             // Move random player to T team
  5459.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5460.             remove_task(id+TASK_TEAM)
  5461.             fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5462.             fm_user_team_update(id)
  5463.         }
  5464.         else if (!fnGetAliveCTs())
  5465.         {
  5466.             // Move random player to CT team
  5467.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  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.         // Turn every T into a zombie
  5474.         for (id = 1; id <= g_maxplayers; id++)
  5475.         {
  5476.             // Not alive
  5477.             if (!g_isalive[id])
  5478.                 continue;
  5479.            
  5480.             // Not a Terrorist
  5481.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_T)
  5482.                 continue;
  5483.            
  5484.             // Turn into a zombie
  5485.             zombieme(id, 0, 0, 1, 0)
  5486.         }
  5487.        
  5488.         // Play swarm sound
  5489.         ArrayGetString(sound_swarm, random_num(0, ArraySize(sound_swarm) - 1), sound, charsmax(sound))
  5490.         PlaySound(sound);
  5491.        
  5492.         // Show Swarm HUD notice
  5493.         set_hudmessage(20, 255, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5494.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SWARM")
  5495.        
  5496.         // Mode fully started!
  5497.         g_modestarted = true
  5498.        
  5499.         // Round start forward
  5500.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SWARM, 0);
  5501.     }
  5502.     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)
  5503.     {
  5504.         // Multi Infection Mode
  5505.         g_lastmode = MODE_MULTI
  5506.        
  5507.         // iMaxZombies is rounded up, in case there aren't enough players
  5508.         iMaxZombies = floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil)
  5509.         iZombies = 0
  5510.        
  5511.         // Randomly turn iMaxZombies players into zombies
  5512.         while (iZombies < iMaxZombies)
  5513.         {
  5514.             // Keep looping through all players
  5515.             if (++id > g_maxplayers) id = 1
  5516.            
  5517.             // Dead or already a zombie
  5518.             if (!g_isalive[id] || g_zombie[id])
  5519.                 continue;
  5520.            
  5521.             // Random chance
  5522.             if (random_num(0, 1))
  5523.             {
  5524.                 // Turn into a zombie
  5525.                 zombieme(id, 0, 0, 1, 0)
  5526.                 iZombies++
  5527.             }
  5528.         }
  5529.        
  5530.         // Turn the remaining players into humans
  5531.         for (id = 1; id <= g_maxplayers; id++)
  5532.         {
  5533.             // Only those of them who aren't zombies
  5534.             if (!g_isalive[id] || g_zombie[id])
  5535.                 continue;
  5536.            
  5537.             // Switch to CT
  5538.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5539.             {
  5540.                 remove_task(id+TASK_TEAM)
  5541.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5542.                 fm_user_team_update(id)
  5543.             }
  5544.         }
  5545.        
  5546.         // Play multi infection sound
  5547.         ArrayGetString(sound_multi, random_num(0, ArraySize(sound_multi) - 1), sound, charsmax(sound))
  5548.         PlaySound(sound);
  5549.        
  5550.         // Show Multi Infection HUD notice
  5551.         set_hudmessage(200, 50, 0, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5552.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_MULTI")
  5553.        
  5554.         // Mode fully started!
  5555.         g_modestarted = true
  5556.        
  5557.         // Round start forward
  5558.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_MULTI, 0);
  5559.     }
  5560.     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
  5561.     && 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)
  5562.     {
  5563.         // Plague Mode
  5564.         g_plagueround = true
  5565.         g_lastmode = MODE_PLAGUE
  5566.        
  5567.         // Turn specified amount of players into Survivors
  5568.         static iSurvivors, iMaxSurvivors
  5569.         iMaxSurvivors = get_pcvar_num(cvar_plaguesurvnum)
  5570.         iSurvivors = 0
  5571.        
  5572.         while (iSurvivors < iMaxSurvivors)
  5573.         {
  5574.             // Choose random guy
  5575.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5576.            
  5577.             // Already a survivor?
  5578.             if (g_survivor[id])
  5579.                 continue;
  5580.            
  5581.             // If not, turn him into one
  5582.             humanme(id, 1, 0)
  5583.             iSurvivors++
  5584.            
  5585.             // Apply survivor health multiplier
  5586.             fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguesurvhpmulti)))
  5587.         }
  5588.        
  5589.         // Turn specified amount of players into Nemesis
  5590.         static iNemesis, iMaxNemesis
  5591.         iMaxNemesis = get_pcvar_num(cvar_plaguenemnum)
  5592.         iNemesis = 0
  5593.        
  5594.         while (iNemesis < iMaxNemesis)
  5595.         {
  5596.             // Choose random guy
  5597.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5598.            
  5599.             // Already a survivor or nemesis?
  5600.             if (g_survivor[id] || g_nemesis[id])
  5601.                 continue;
  5602.            
  5603.             // If not, turn him into one
  5604.             zombieme(id, 0, 1, 0, 0)
  5605.             iNemesis++
  5606.            
  5607.             // Apply nemesis health multiplier
  5608.             fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguenemhpmulti)))
  5609.         }
  5610.        
  5611.         // iMaxZombies is rounded up, in case there aren't enough players
  5612.         iMaxZombies = floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)
  5613.         iZombies = 0
  5614.        
  5615.         // Randomly turn iMaxZombies players into zombies
  5616.         while (iZombies < iMaxZombies)
  5617.         {
  5618.             // Keep looping through all players
  5619.             if (++id > g_maxplayers) id = 1
  5620.            
  5621.             // Dead or already a zombie or survivor
  5622.             if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  5623.                 continue;
  5624.            
  5625.             // Random chance
  5626.             if (random_num(0, 1))
  5627.             {
  5628.                 // Turn into a zombie
  5629.                 zombieme(id, 0, 0, 1, 0)
  5630.                 iZombies++
  5631.             }
  5632.         }
  5633.        
  5634.         // Turn the remaining players into humans
  5635.         for (id = 1; id <= g_maxplayers; id++)
  5636.         {
  5637.             // Only those of them who arent zombies or survivor
  5638.             if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  5639.                 continue;
  5640.            
  5641.             // Switch to CT
  5642.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5643.             {
  5644.                 remove_task(id+TASK_TEAM)
  5645.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5646.                 fm_user_team_update(id)
  5647.             }
  5648.         }
  5649.        
  5650.         // Play plague sound
  5651.         ArrayGetString(sound_plague, random_num(0, ArraySize(sound_plague) - 1), sound, charsmax(sound))
  5652.         PlaySound(sound);
  5653.        
  5654.         // Show Plague HUD notice
  5655.         set_hudmessage(0, 50, 200, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5656.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_PLAGUE")
  5657.        
  5658.         // Mode fully started!
  5659.         g_modestarted = true
  5660.        
  5661.         // Round start forward
  5662.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_PLAGUE, 0);
  5663.     }
  5664.     else
  5665.     {
  5666.         // Single Infection Mode or Nemesis Mode
  5667.        
  5668.         // Choose player randomly?
  5669.         if (mode == MODE_NONE)
  5670.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5671.        
  5672.         // Remember id for calling our forward later
  5673.         forward_id = id
  5674.        
  5675.         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)
  5676.         {
  5677.             // Nemesis Mode
  5678.             g_nemround = true
  5679.             g_lastmode = MODE_NEMESIS
  5680.            
  5681.             // Turn player into nemesis
  5682.             zombieme(id, 0, 1, 0, 0)
  5683.         }
  5684.         else
  5685.         {
  5686.             // Single Infection Mode
  5687.             g_lastmode = MODE_INFECTION
  5688.            
  5689.             // Turn player into the first zombie
  5690.             zombieme(id, 0, 0, 0, 0)
  5691.         }
  5692.        
  5693.         // Remaining players should be humans (CTs)
  5694.         for (id = 1; id <= g_maxplayers; id++)
  5695.         {
  5696.             // Not alive
  5697.             if (!g_isalive[id])
  5698.                 continue;
  5699.            
  5700.             // First zombie/nemesis
  5701.             if (g_zombie[id])
  5702.                 continue;
  5703.            
  5704.             // Switch to CT
  5705.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5706.             {
  5707.                 remove_task(id+TASK_TEAM)
  5708.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5709.                 fm_user_team_update(id)
  5710.             }
  5711.         }
  5712.        
  5713.         if (g_nemround)
  5714.         {
  5715.             // Play Nemesis sound
  5716.             ArrayGetString(sound_nemesis, random_num(0, ArraySize(sound_nemesis) - 1), sound, charsmax(sound))
  5717.             PlaySound(sound);
  5718.            
  5719.             // Show Nemesis HUD notice
  5720.             set_hudmessage(255, 20, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5721.             ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_NEMESIS", g_playername[forward_id])
  5722.            
  5723.             // Mode fully started!
  5724.             g_modestarted = true
  5725.            
  5726.             // Round start forward
  5727.             ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_NEMESIS, forward_id);
  5728.         }
  5729.         else
  5730.         {
  5731.             // Show First Zombie HUD notice
  5732.             set_hudmessage(255, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  5733.             ShowSyncHudMsg(0, g_MsgSync, "%L",LANG_PLAYER, "NOTICE_FIRST", g_playername[forward_id])
  5734.            
  5735.             // Mode fully started!
  5736.             g_modestarted = true
  5737.            
  5738.             // Round start forward
  5739.             ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_INFECTION, forward_id);
  5740.         }
  5741.     }
  5742.    
  5743.     // Start ambience sounds after a mode begins
  5744.     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))
  5745.     {
  5746.         remove_task(TASK_AMBIENCESOUNDS)
  5747.         set_task(2.0, "ambience_sound_effects", TASK_AMBIENCESOUNDS)
  5748.     }
  5749. }
  5750.  
  5751. // Zombie Me Function (player id, infector, turn into a nemesis, silent mode, deathmsg and rewards)
  5752. zombieme(id, infector, nemesis, silentmode, rewards)
  5753. {
  5754.     // User infect attempt forward
  5755.     ExecuteForward(g_fwUserInfect_attempt, g_fwDummyResult, id, infector, nemesis)
  5756.    
  5757.     // One or more plugins blocked the infection. Only allow this after making sure it's
  5758.     // not going to leave us with no zombies. Take into account a last player leaving case.
  5759.     // BUGFIX: only allow after a mode has started, to prevent blocking first zombie e.g.
  5760.     if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetZombies() > g_lastplayerleaving)
  5761.         return;
  5762.    
  5763.     // Pre user infect forward
  5764.     ExecuteForward(g_fwUserInfected_pre, g_fwDummyResult, id, infector, nemesis)
  5765.    
  5766.     // Show zombie class menu if they haven't chosen any (e.g. just connected)
  5767.     if (g_zombieclassnext[id] == ZCLASS_NONE && get_pcvar_num(cvar_zclasses))
  5768.         set_task(0.2, "show_menu_zclass", id)
  5769.    
  5770.     // Set selected zombie class
  5771.     g_zombieclass[id] = g_zombieclassnext[id]
  5772.     // If no class selected yet, use the first (default) one
  5773.     if (g_zombieclass[id] == ZCLASS_NONE) g_zombieclass[id] = 0
  5774.    
  5775.     // Way to go...
  5776.     g_zombie[id] = true
  5777.     g_nemesis[id] = false
  5778.     g_survivor[id] = false
  5779.     g_firstzombie[id] = false
  5780.    
  5781.     // Remove survivor's aura (bugfix)
  5782.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
  5783.    
  5784.     // Remove spawn protection (bugfix)
  5785.     g_nodamage[id] = false
  5786.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
  5787.    
  5788.     // Reset burning duration counter (bugfix)
  5789.     g_burning_duration[id] = 0
  5790.    
  5791.     // Show deathmsg and reward infector?
  5792.     if (rewards && infector)
  5793.     {
  5794.         // Send death notice and fix the "dead" attrib on scoreboard
  5795.         SendDeathMsg(infector, id)
  5796.         FixDeadAttrib(id)
  5797.        
  5798.         // Reward frags, deaths, health, and ammo packs
  5799.         UpdateFrags(infector, id, get_pcvar_num(cvar_fragsinfect), 1, 1)
  5800.         g_ammopacks[infector] += get_pcvar_num(cvar_ammoinfect)
  5801.         fm_set_user_health(infector, pev(infector, pev_health) + get_pcvar_num(cvar_zombiebonushp))
  5802.     }
  5803.    
  5804.     // Cache speed, knockback, and name for player's class
  5805.     g_zombie_spd[id] = float(ArrayGetCell(g_zclass_spd, g_zombieclass[id]))
  5806.     g_zombie_knockback[id] = Float:ArrayGetCell(g_zclass_kb, g_zombieclass[id])
  5807.     ArrayGetString(g_zclass_name, g_zombieclass[id], g_zombie_classname[id], charsmax(g_zombie_classname[]))
  5808.    
  5809.     // Set zombie attributes based on the mode
  5810.     static sound[64]
  5811.     if (!silentmode)
  5812.     {
  5813.         if (nemesis)
  5814.         {
  5815.             // Nemesis
  5816.             g_nemesis[id] = true
  5817.            
  5818.             // Set health [0 = auto]
  5819.             if (get_pcvar_num(cvar_nemhp) == 0)
  5820.             {
  5821.                 if (get_pcvar_num(cvar_nembasehp) == 0)
  5822.                     fm_set_user_health(id, ArrayGetCell(g_zclass_hp, 0) * fnGetAlive())
  5823.                 else
  5824.                     fm_set_user_health(id, get_pcvar_num(cvar_nembasehp) * fnGetAlive())
  5825.             }
  5826.             else
  5827.                 fm_set_user_health(id, get_pcvar_num(cvar_nemhp))
  5828.            
  5829.             // Set gravity, if frozen set the restore gravity value instead
  5830.             if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_nemgravity))
  5831.             else g_frozen_gravity[id] = get_pcvar_float(cvar_nemgravity)
  5832.            
  5833.             // Set nemesis maxspeed
  5834.             ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5835.         }
  5836.         else if (fnGetZombies() == 1)
  5837.         {
  5838.             // First zombie
  5839.             g_firstzombie[id] = true
  5840.            
  5841.             // Set health
  5842.             fm_set_user_health(id, floatround(float(ArrayGetCell(g_zclass_hp, g_zombieclass[id])) * get_pcvar_float(cvar_zombiefirsthp)))
  5843.            
  5844.             // Set gravity, if frozen set the restore gravity value instead
  5845.             if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5846.             else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
  5847.            
  5848.             // Set zombie maxspeed
  5849.             ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5850.            
  5851.             // Infection sound
  5852.             ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound))
  5853.             emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  5854.         }
  5855.         else
  5856.         {
  5857.             // Infected by someone
  5858.            
  5859.             // Set health
  5860.             fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
  5861.            
  5862.             // Set gravity, if frozen set the restore gravity value instead
  5863.             if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5864.             else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
  5865.            
  5866.             // Set zombie maxspeed
  5867.             ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5868.            
  5869.             // Infection sound
  5870.             ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound))
  5871.             emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  5872.            
  5873.             // Show Infection HUD notice
  5874.             set_hudmessage(255, 0, 0, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  5875.            
  5876.             if (infector) // infected by someone?
  5877.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT2", g_playername[id], g_playername[infector])
  5878.             else
  5879.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT", g_playername[id])
  5880.         }
  5881.     }
  5882.     else
  5883.     {
  5884.         // Silent mode, no HUD messages, no infection sounds
  5885.        
  5886.         // Set health
  5887.         fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
  5888.        
  5889.         // Set gravity, if frozen set the restore gravity value instead
  5890.         if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5891.         else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
  5892.        
  5893.         // Set zombie maxspeed
  5894.         ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5895.     }
  5896.    
  5897.     // Remove previous tasks
  5898.     remove_task(id+TASK_MODEL)
  5899.     remove_task(id+TASK_BLOOD)
  5900.     remove_task(id+TASK_AURA)
  5901.     remove_task(id+TASK_BURN)
  5902.    
  5903.     // Switch to T
  5904.     if (fm_cs_get_user_team(id) != FM_CS_TEAM_T) // need to change team?
  5905.     {
  5906.         remove_task(id+TASK_TEAM)
  5907.         fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5908.         fm_user_team_update(id)
  5909.     }
  5910.    
  5911.     // Custom models stuff
  5912.     static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  5913.     already_has_model = false
  5914.    
  5915.     if (g_handle_models_on_separate_ent)
  5916.     {
  5917.         // Set the right model
  5918.         if (g_nemesis[id])
  5919.         {
  5920.             iRand = random_num(0, ArraySize(model_nemesis) - 1)
  5921.             ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5922.             if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
  5923.         }
  5924.         else
  5925.         {
  5926.             if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  5927.             {
  5928.                 iRand = random_num(0, ArraySize(model_admin_zombie) - 1)
  5929.                 ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5930.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
  5931.             }
  5932.             else
  5933.             {
  5934.                 iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
  5935.                 ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5936.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
  5937.             }
  5938.         }
  5939.        
  5940.         // Set model on player model entity
  5941.         fm_set_playermodel_ent(id)
  5942.        
  5943.         // Nemesis glow / remove glow on player model entity, unless frozen
  5944.         if (!g_frozen[id])
  5945.         {
  5946.             if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  5947.                 fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  5948.             else
  5949.                 fm_set_rendering(g_ent_playermodel[id])
  5950.         }
  5951.     }
  5952.     else
  5953.     {
  5954.         // Get current model for comparing it with the current one
  5955.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  5956.        
  5957.         // Set the right model, after checking that we don't already have it
  5958.         if (g_nemesis[id])
  5959.         {
  5960.             size = ArraySize(model_nemesis)
  5961.             for (i = 0; i < size; i++)
  5962.             {
  5963.                 ArrayGetString(model_nemesis, i, tempmodel, charsmax(tempmodel))
  5964.                 if (equal(currentmodel, tempmodel)) already_has_model = true
  5965.             }
  5966.            
  5967.             if (!already_has_model)
  5968.             {
  5969.                 iRand = random_num(0, size - 1)
  5970.                 ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5971.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
  5972.             }
  5973.         }
  5974.         else
  5975.         {
  5976.             if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  5977.             {
  5978.                 size = ArraySize(model_admin_zombie)
  5979.                 for (i = 0; i < size; i++)
  5980.                 {
  5981.                     ArrayGetString(model_admin_zombie, i, tempmodel, charsmax(tempmodel))
  5982.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  5983.                 }
  5984.                
  5985.                 if (!already_has_model)
  5986.                 {
  5987.                     iRand = random_num(0, size - 1)
  5988.                     ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5989.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
  5990.                 }
  5991.             }
  5992.             else
  5993.             {
  5994.                 for (i = ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]); i < ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]); i++)
  5995.                 {
  5996.                     ArrayGetString(g_zclass_playermodel, i, tempmodel, charsmax(tempmodel))
  5997.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  5998.                 }
  5999.                
  6000.                 if (!already_has_model)
  6001.                 {
  6002.                     iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
  6003.                     ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6004.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
  6005.                 }
  6006.             }
  6007.         }
  6008.        
  6009.         // Need to change the model?
  6010.         if (!already_has_model)
  6011.         {
  6012.             // An additional delay is offset at round start
  6013.             // since SVC_BAD is more likely to be triggered there
  6014.             if (g_newround)
  6015.                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  6016.             else
  6017.                 fm_user_model_update(id+TASK_MODEL)
  6018.         }
  6019.        
  6020.         // Nemesis glow / remove glow, unless frozen
  6021.         if (!g_frozen[id])
  6022.         {
  6023.             if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  6024.                 fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  6025.             else
  6026.                 fm_set_rendering(id)
  6027.         }
  6028.     }
  6029.    
  6030.     // Remove any zoom (bugfix)
  6031.     cs_set_user_zoom(id, CS_RESET_ZOOM, 1)
  6032.    
  6033.     // Remove armor
  6034.     cs_set_user_armor(id, 0, CS_ARMOR_NONE)
  6035.    
  6036.     // Drop weapons when infected
  6037.     drop_weapons(id, 1)
  6038.     drop_weapons(id, 2)
  6039.    
  6040.     // Strip zombies from guns and give them a knife
  6041.     fm_strip_user_weapons(id)
  6042.     fm_give_item(id, "weapon_knife")
  6043.    
  6044.     // Fancy effects
  6045.     infection_effects(id)
  6046.    
  6047.     // Nemesis aura task
  6048.     if (g_nemesis[id] && get_pcvar_num(cvar_nemaura))
  6049.         set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
  6050.    
  6051.     // Remove CS nightvision if player owns one (bugfix)
  6052.     if (cs_get_user_nvg(id))
  6053.     {
  6054.         cs_set_user_nvg(id, 0)
  6055.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6056.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6057.     }
  6058.    
  6059.     // Give Zombies Night Vision?
  6060.     if (get_pcvar_num(cvar_nvggive))
  6061.     {
  6062.         g_nvision[id] = true
  6063.        
  6064.         if (!g_isbot[id])
  6065.         {
  6066.             // Turn on Night Vision automatically?
  6067.             if (get_pcvar_num(cvar_nvggive) == 1)
  6068.             {
  6069.                 g_nvisionenabled[id] = true
  6070.                
  6071.                 // Custom nvg?
  6072.                 if (get_pcvar_num(cvar_customnvg))
  6073.                 {
  6074.                     remove_task(id+TASK_NVISION)
  6075.                     set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  6076.                 }
  6077.                 else
  6078.                     set_user_gnvision(id, 1)
  6079.             }
  6080.             // Turn off nightvision when infected (bugfix)
  6081.             else if (g_nvisionenabled[id])
  6082.             {
  6083.                 if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6084.                 else set_user_gnvision(id, 0)
  6085.                 g_nvisionenabled[id] = false
  6086.             }
  6087.         }
  6088.         else
  6089.             cs_set_user_nvg(id, 1); // turn on NVG for bots
  6090.     }
  6091.     // Disable nightvision when infected (bugfix)
  6092.     else if (g_nvision[id])
  6093.     {
  6094.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6095.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6096.         g_nvision[id] = false
  6097.         g_nvisionenabled[id] = false
  6098.     }
  6099.    
  6100.     // Set custom FOV?
  6101.     if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
  6102.     {
  6103.         message_begin(MSG_ONE, g_msgSetFOV, _, id)
  6104.         write_byte(get_pcvar_num(cvar_zombiefov)) // fov angle
  6105.         message_end()
  6106.     }
  6107.    
  6108.     // Call the bloody task
  6109.     if (!g_nemesis[id] && get_pcvar_num(cvar_zombiebleeding))
  6110.         set_task(0.7, "make_blood", id+TASK_BLOOD, _, _, "b")
  6111.    
  6112.     // Idle sounds task
  6113.     if (!g_nemesis[id])
  6114.         set_task(random_float(50.0, 70.0), "zombie_play_idle", id+TASK_BLOOD, _, _, "b")
  6115.    
  6116.     // Turn off zombie's flashlight
  6117.     turn_off_flashlight(id)
  6118.    
  6119.     // Post user infect forward
  6120.     ExecuteForward(g_fwUserInfected_post, g_fwDummyResult, id, infector, nemesis)
  6121.    
  6122.     // Last Zombie Check
  6123.     fnCheckLastZombie()
  6124. }
  6125.  
  6126. // Function Human Me (player id, turn into a survivor, silent mode)
  6127. humanme(id, survivor, silentmode)
  6128. {
  6129.     // User humanize attempt forward
  6130.     ExecuteForward(g_fwUserHumanize_attempt, g_fwDummyResult, id, survivor)
  6131.    
  6132.     // One or more plugins blocked the "humanization". Only allow this after making sure it's
  6133.     // not going to leave us with no humans. Take into account a last player leaving case.
  6134.     // BUGFIX: only allow after a mode has started, to prevent blocking first survivor e.g.
  6135.     if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetHumans() > g_lastplayerleaving)
  6136.         return;
  6137.    
  6138.     // Pre user humanize forward
  6139.     ExecuteForward(g_fwUserHumanized_pre, g_fwDummyResult, id, survivor)
  6140.    
  6141.     // Remove previous tasks
  6142.     remove_task(id+TASK_MODEL)
  6143.     remove_task(id+TASK_BLOOD)
  6144.     remove_task(id+TASK_AURA)
  6145.     remove_task(id+TASK_BURN)
  6146.     remove_task(id+TASK_NVISION)
  6147.    
  6148.     // Reset some vars
  6149.     g_zombie[id] = false
  6150.     g_nemesis[id] = false
  6151.     g_survivor[id] = false
  6152.     g_firstzombie[id] = false
  6153.     g_canbuy[id] = true
  6154.     g_buytime[id] = get_gametime()
  6155.    
  6156.     // Remove survivor's aura (bugfix)
  6157.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
  6158.    
  6159.     // Remove spawn protection (bugfix)
  6160.     g_nodamage[id] = false
  6161.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
  6162.    
  6163.     // Reset burning duration counter (bugfix)
  6164.     g_burning_duration[id] = 0
  6165.    
  6166.     // Remove CS nightvision if player owns one (bugfix)
  6167.     if (cs_get_user_nvg(id))
  6168.     {
  6169.         cs_set_user_nvg(id, 0)
  6170.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6171.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6172.     }
  6173.    
  6174.     // Drop previous weapons
  6175.     drop_weapons(id, 1)
  6176.     drop_weapons(id, 2)
  6177.    
  6178.     // Strip off from weapons
  6179.     fm_strip_user_weapons(id)
  6180.     fm_give_item(id, "weapon_knife")
  6181.    
  6182.     // Set human attributes based on the mode
  6183.     if (survivor)
  6184.     {
  6185.         // Survivor
  6186.         g_survivor[id] = true
  6187.        
  6188.         // Set Health [0 = auto]
  6189.         if (get_pcvar_num(cvar_survhp) == 0)
  6190.         {
  6191.             if (get_pcvar_num(cvar_survbasehp) == 0)
  6192.                 fm_set_user_health(id, get_pcvar_num(cvar_humanhp) * fnGetAlive())
  6193.             else
  6194.                 fm_set_user_health(id, get_pcvar_num(cvar_survbasehp) * fnGetAlive())
  6195.         }
  6196.         else
  6197.             fm_set_user_health(id, get_pcvar_num(cvar_survhp))
  6198.        
  6199.         // Set gravity, if frozen set the restore gravity value instead
  6200.         if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_survgravity))
  6201.         else g_frozen_gravity[id] = get_pcvar_float(cvar_survgravity)
  6202.        
  6203.         // Set survivor maxspeed
  6204.         ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  6205.        
  6206.         // Give survivor his own weapon
  6207.         static survweapon[32]
  6208.         get_pcvar_string(cvar_survweapon, survweapon, charsmax(survweapon))
  6209.         fm_give_item(id, survweapon)
  6210.         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)])
  6211.        
  6212.         // Turn off his flashlight
  6213.         turn_off_flashlight(id)
  6214.        
  6215.         // Give the survivor a bright light
  6216.         if (get_pcvar_num(cvar_survaura)) set_pev(id, pev_effects, pev(id, pev_effects) | EF_BRIGHTLIGHT)
  6217.        
  6218.         // Survivor bots will also need nightvision to see in the dark
  6219.         if (g_isbot[id])
  6220.         {
  6221.             g_nvision[id] = true
  6222.             cs_set_user_nvg(id, 1)
  6223.         }
  6224.     }
  6225.     else
  6226.     {
  6227.         // Human taking an antidote
  6228.        
  6229.         // Set health
  6230.         fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
  6231.        
  6232.         // Set gravity, if frozen set the restore gravity value instead
  6233.         if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
  6234.         else g_frozen_gravity[id] = get_pcvar_float(cvar_humangravity)
  6235.        
  6236.         // Set human maxspeed
  6237.         ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  6238.        
  6239.         // Show custom buy menu?
  6240.         if (get_pcvar_num(cvar_buycustom))
  6241.             set_task(0.2, "show_menu_buy1", id+TASK_SPAWN)
  6242.        
  6243.         // Silent mode = no HUD messages, no antidote sound
  6244.         if (!silentmode)
  6245.         {
  6246.             // Antidote sound
  6247.             static sound[64]
  6248.             ArrayGetString(sound_antidote, random_num(0, ArraySize(sound_antidote) - 1), sound, charsmax(sound))
  6249.             emit_sound(id, CHAN_ITEM, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  6250.            
  6251.             // Show Antidote HUD notice
  6252.             set_hudmessage(0, 0, 255, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  6253.             ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_ANTIDOTE", g_playername[id])
  6254.         }
  6255.     }
  6256.    
  6257.     // Switch to CT
  6258.     if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  6259.     {
  6260.         remove_task(id+TASK_TEAM)
  6261.         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  6262.         fm_user_team_update(id)
  6263.     }
  6264.    
  6265.     // Custom models stuff
  6266.     static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  6267.     already_has_model = false
  6268.    
  6269.     if (g_handle_models_on_separate_ent)
  6270.     {
  6271.         // Set the right model
  6272.         if (g_survivor[id])
  6273.         {
  6274.             iRand = random_num(0, ArraySize(model_survivor) - 1)
  6275.             ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6276.             if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
  6277.         }
  6278.         else
  6279.         {
  6280.             if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  6281.             {
  6282.                 iRand = random_num(0, ArraySize(model_admin_human) - 1)
  6283.                 ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6284.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  6285.             }
  6286.             else
  6287.             {
  6288.                 iRand = random_num(0, ArraySize(model_human) - 1)
  6289.                 ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6290.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  6291.             }
  6292.         }
  6293.        
  6294.         // Set model on player model entity
  6295.         fm_set_playermodel_ent(id)
  6296.        
  6297.         // Set survivor glow / remove glow on player model entity, unless frozen
  6298.         if (!g_frozen[id])
  6299.         {
  6300.             if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  6301.                 fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  6302.             else
  6303.                 fm_set_rendering(g_ent_playermodel[id])
  6304.         }
  6305.     }
  6306.     else
  6307.     {
  6308.         // Get current model for comparing it with the current one
  6309.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  6310.        
  6311.         // Set the right model, after checking that we don't already have it
  6312.         if (g_survivor[id])
  6313.         {
  6314.             size = ArraySize(model_survivor)
  6315.             for (i = 0; i < size; i++)
  6316.             {
  6317.                 ArrayGetString(model_survivor, i, tempmodel, charsmax(tempmodel))
  6318.                 if (equal(currentmodel, tempmodel)) already_has_model = true
  6319.             }
  6320.            
  6321.             if (!already_has_model)
  6322.             {
  6323.                 iRand = random_num(0, size - 1)
  6324.                 ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6325.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
  6326.             }
  6327.         }
  6328.         else
  6329.         {
  6330.             if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  6331.             {
  6332.                 size = ArraySize(model_admin_human)
  6333.                 for (i = 0; i < size; i++)
  6334.                 {
  6335.                     ArrayGetString(model_admin_human, i, tempmodel, charsmax(tempmodel))
  6336.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  6337.                 }
  6338.                
  6339.                 if (!already_has_model)
  6340.                 {
  6341.                     iRand = random_num(0, size - 1)
  6342.                     ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6343.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  6344.                 }
  6345.             }
  6346.             else
  6347.             {
  6348.                 size = ArraySize(model_human)
  6349.                 for (i = 0; i < size; i++)
  6350.                 {
  6351.                     ArrayGetString(model_human, i, tempmodel, charsmax(tempmodel))
  6352.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  6353.                 }
  6354.                
  6355.                 if (!already_has_model)
  6356.                 {
  6357.                     iRand = random_num(0, size - 1)
  6358.                     ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6359.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  6360.                 }
  6361.             }
  6362.         }
  6363.        
  6364.         // Need to change the model?
  6365.         if (!already_has_model)
  6366.         {
  6367.             // An additional delay is offset at round start
  6368.             // since SVC_BAD is more likely to be triggered there
  6369.             if (g_newround)
  6370.                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  6371.             else
  6372.                 fm_user_model_update(id+TASK_MODEL)
  6373.         }
  6374.        
  6375.         // Set survivor glow / remove glow, unless frozen
  6376.         if (!g_frozen[id])
  6377.         {
  6378.             if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  6379.                 fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  6380.             else
  6381.                 fm_set_rendering(id)
  6382.         }
  6383.     }
  6384.    
  6385.     // Restore FOV?
  6386.     if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
  6387.     {
  6388.         message_begin(MSG_ONE, g_msgSetFOV, _, id)
  6389.         write_byte(90) // angle
  6390.         message_end()
  6391.     }
  6392.    
  6393.     // Disable nightvision when turning into human/survivor (bugfix)
  6394.     if (g_nvision[id])
  6395.     {
  6396.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6397.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6398.         g_nvision[id] = false
  6399.         g_nvisionenabled[id] = false
  6400.     }
  6401.    
  6402.     // Post user humanize forward
  6403.     ExecuteForward(g_fwUserHumanized_post, g_fwDummyResult, id, survivor)
  6404.    
  6405.     // Last Zombie Check
  6406.     fnCheckLastZombie()
  6407. }
  6408.  
  6409. /*================================================================================
  6410.  [Other Functions and Tasks]
  6411. =================================================================================*/
  6412.  
  6413. public cache_cvars()
  6414. {
  6415.     g_cached_zombiesilent = get_pcvar_num(cvar_zombiesilent)
  6416.     g_cached_customflash = get_pcvar_num(cvar_customflash)
  6417.     g_cached_leapzombies = get_pcvar_num(cvar_leapzombies)
  6418.     g_cached_leapzombiescooldown = get_pcvar_float(cvar_leapzombiescooldown)
  6419.     g_cached_leapnemesis = get_pcvar_num(cvar_leapnemesis)
  6420.     g_cached_leapnemesiscooldown = get_pcvar_float(cvar_leapnemesiscooldown)
  6421.     g_cached_leapsurvivor = get_pcvar_num(cvar_leapsurvivor)
  6422.     g_cached_leapsurvivorcooldown = get_pcvar_float(cvar_leapsurvivorcooldown)
  6423.     g_cached_buytime = get_pcvar_float(cvar_buyzonetime)
  6424. }
  6425.  
  6426. load_customization_from_files()
  6427. {
  6428.     // Build customization file path
  6429.     new path[64]
  6430.     get_configsdir(path, charsmax(path))
  6431.     format(path, charsmax(path), "%s/%s", path, ZP_CUSTOMIZATION_FILE)
  6432.    
  6433.     // File not present
  6434.     if (!file_exists(path))
  6435.     {
  6436.         new error[100]
  6437.         formatex(error, charsmax(error), "Cannot load customization file %s!", path)
  6438.         set_fail_state(error)
  6439.         return;
  6440.     }
  6441.    
  6442.     // Set up some vars to hold parsing info
  6443.     new linedata[1024], key[64], value[960], section, teams
  6444.    
  6445.     // Open customization file for reading
  6446.     new file = fopen(path, "rt")
  6447.    
  6448.     while (file && !feof(file))
  6449.     {
  6450.         // Read one line at a time
  6451.         fgets(file, linedata, charsmax(linedata))
  6452.        
  6453.         // Replace newlines with a null character to prevent headaches
  6454.         replace(linedata, charsmax(linedata), "^n", "")
  6455.        
  6456.         // Blank line or comment
  6457.         if (!linedata[0] || linedata[0] == ';') continue;
  6458.        
  6459.         // New section starting
  6460.         if (linedata[0] == '[')
  6461.         {
  6462.             section++
  6463.             continue;
  6464.         }
  6465.        
  6466.         // Get key and value(s)
  6467.         strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  6468.        
  6469.         // Trim spaces
  6470.         trim(key)
  6471.         trim(value)
  6472.        
  6473.         switch (section)
  6474.         {
  6475.             case SECTION_ACCESS_FLAGS:
  6476.             {
  6477.                 if (equal(key, "ENABLE/DISABLE MOD"))
  6478.                     g_access_flag[ACCESS_ENABLE_MOD] = read_flags(value)
  6479.                 else if (equal(key, "ADMIN MENU"))
  6480.                     g_access_flag[ACCESS_ADMIN_MENU] = read_flags(value)
  6481.                 else if (equal(key, "START MODE INFECTION"))
  6482.                     g_access_flag[ACCESS_MODE_INFECTION] = read_flags(value)
  6483.                 else if (equal(key, "START MODE NEMESIS"))
  6484.                     g_access_flag[ACCESS_MODE_NEMESIS] = read_flags(value)
  6485.                 else if (equal(key, "START MODE SURVIVOR"))
  6486.                     g_access_flag[ACCESS_MODE_SURVIVOR] = read_flags(value)
  6487.                 else if (equal(key, "START MODE SWARM"))
  6488.                     g_access_flag[ACCESS_MODE_SWARM] = read_flags(value)
  6489.                 else if (equal(key, "START MODE MULTI"))
  6490.                     g_access_flag[ACCESS_MODE_MULTI] = read_flags(value)
  6491.                 else if (equal(key, "START MODE PLAGUE"))
  6492.                     g_access_flag[ACCESS_MODE_PLAGUE] = read_flags(value)
  6493.                 else if (equal(key, "MAKE ZOMBIE"))
  6494.                     g_access_flag[ACCESS_MAKE_ZOMBIE] = read_flags(value)
  6495.                 else if (equal(key, "MAKE HUMAN"))
  6496.                     g_access_flag[ACCESS_MAKE_HUMAN] = read_flags(value)
  6497.                 else if (equal(key, "MAKE NEMESIS"))
  6498.                     g_access_flag[ACCESS_MAKE_NEMESIS] = read_flags(value)
  6499.                 else if (equal(key, "MAKE SURVIVOR"))
  6500.                     g_access_flag[ACCESS_MAKE_SURVIVOR] = read_flags(value)
  6501.                 else if (equal(key, "RESPAWN PLAYERS"))
  6502.                     g_access_flag[ACCESS_RESPAWN_PLAYERS] = read_flags(value)
  6503.                 else if (equal(key, "ADMIN MODELS"))
  6504.                     g_access_flag[ACCESS_ADMIN_MODELS] = read_flags(value)
  6505.             }
  6506.             case SECTION_PLAYER_MODELS:
  6507.             {
  6508.                 if (equal(key, "HUMAN"))
  6509.                 {
  6510.                     // Parse models
  6511.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6512.                     {
  6513.                         // Trim spaces
  6514.                         trim(key)
  6515.                         trim(value)
  6516.                        
  6517.                         // Add to models array
  6518.                         ArrayPushString(model_human, key)
  6519.                     }
  6520.                 }
  6521.                 else if (equal(key, "NEMESIS"))
  6522.                 {
  6523.                     // Parse models
  6524.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6525.                     {
  6526.                         // Trim spaces
  6527.                         trim(key)
  6528.                         trim(value)
  6529.                        
  6530.                         // Add to models array
  6531.                         ArrayPushString(model_nemesis, key)
  6532.                     }
  6533.                 }
  6534.                 else if (equal(key, "SURVIVOR"))
  6535.                 {
  6536.                     // Parse models
  6537.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6538.                     {
  6539.                         // Trim spaces
  6540.                         trim(key)
  6541.                         trim(value)
  6542.                        
  6543.                         // Add to models array
  6544.                         ArrayPushString(model_survivor, key)
  6545.                     }
  6546.                 }
  6547.                 else if (equal(key, "ADMIN ZOMBIE"))
  6548.                 {
  6549.                     // Parse models
  6550.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6551.                     {
  6552.                         // Trim spaces
  6553.                         trim(key)
  6554.                         trim(value)
  6555.                        
  6556.                         // Add to models array
  6557.                         ArrayPushString(model_admin_zombie, key)
  6558.                     }
  6559.                 }
  6560.                 else if (equal(key, "ADMIN HUMAN"))
  6561.                 {
  6562.                     // Parse models
  6563.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6564.                     {
  6565.                         // Trim spaces
  6566.                         trim(key)
  6567.                         trim(value)
  6568.                        
  6569.                         // Add to models array
  6570.                         ArrayPushString(model_admin_human, key)
  6571.                     }
  6572.                 }
  6573.                 else if (equal(key, "FORCE CONSISTENCY"))
  6574.                     g_force_consistency = str_to_num(value)
  6575.                 else if (equal(key, "SAME MODELS FOR ALL"))
  6576.                     g_same_models_for_all = str_to_num(value)
  6577.                 else if (g_same_models_for_all && equal(key, "ZOMBIE"))
  6578.                 {
  6579.                     // Parse models
  6580.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6581.                     {
  6582.                         // Trim spaces
  6583.                         trim(key)
  6584.                         trim(value)
  6585.                        
  6586.                         // Add to models array
  6587.                         ArrayPushString(g_zclass_playermodel, key)
  6588.                        
  6589.                         // Precache model and retrieve its modelindex
  6590.                         formatex(linedata, charsmax(linedata), "models/player/%s/%s.mdl", key, key)
  6591.                         ArrayPushCell(g_zclass_modelindex, engfunc(EngFunc_PrecacheModel, linedata))
  6592.                         if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, linedata)
  6593.                         if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, linedata)
  6594.                         // Precache modelT.mdl files too
  6595.                         copy(linedata[strlen(linedata)-4], charsmax(linedata) - (strlen(linedata)-4), "T.mdl")
  6596.                         if (file_exists(linedata)) engfunc(EngFunc_PrecacheModel, linedata)
  6597.                     }
  6598.                 }
  6599.             }
  6600.             case SECTION_WEAPON_MODELS:
  6601.             {
  6602.                 if (equal(key, "V_KNIFE HUMAN"))
  6603.                     copy(model_vknife_human, charsmax(model_vknife_human), value)
  6604.                 else if (equal(key, "V_KNIFE NEMESIS"))
  6605.                     copy(model_vknife_nemesis, charsmax(model_vknife_nemesis), value)
  6606.                 else if (equal(key, "V_M249 SURVIVOR")) // backwards compatibility with old configs
  6607.                     copy(model_vweapon_survivor, charsmax(model_vweapon_survivor), value)
  6608.                 else if (equal(key, "V_WEAPON SURVIVOR"))
  6609.                     copy(model_vweapon_survivor, charsmax(model_vweapon_survivor), value)
  6610.                 else if (equal(key, "GRENADE INFECT"))
  6611.                     copy(model_grenade_infect, charsmax(model_grenade_infect), value)
  6612.                 else if (equal(key, "GRENADE FIRE"))
  6613.                     copy(model_grenade_fire, charsmax(model_grenade_fire), value)
  6614.                 else if (equal(key, "GRENADE FROST"))
  6615.                     copy(model_grenade_frost, charsmax(model_grenade_frost), value)
  6616.                 else if (equal(key, "GRENADE FLARE"))
  6617.                     copy(model_grenade_flare, charsmax(model_grenade_flare), value)
  6618.                 else if (equal(key, "V_KNIFE ADMIN HUMAN"))
  6619.                     copy(model_vknife_admin_human, charsmax(model_vknife_admin_human), value)
  6620.                 else if (equal(key, "V_KNIFE ADMIN ZOMBIE"))
  6621.                     copy(model_vknife_admin_zombie, charsmax(model_vknife_admin_zombie), value)
  6622.             }
  6623.             case SECTION_GRENADE_SPRITES:
  6624.             {
  6625.                 if (equal(key, "TRAIL"))
  6626.                     copy(sprite_grenade_trail, charsmax(sprite_grenade_trail), value)
  6627.                 else if (equal(key, "RING"))
  6628.                     copy(sprite_grenade_ring, charsmax(sprite_grenade_ring), value)
  6629.                 else if (equal(key, "FIRE"))
  6630.                     copy(sprite_grenade_fire, charsmax(sprite_grenade_fire), value)
  6631.                 else if (equal(key, "SMOKE"))
  6632.                     copy(sprite_grenade_smoke, charsmax(sprite_grenade_smoke), value)
  6633.                 else if (equal(key, "GLASS"))
  6634.                     copy(sprite_grenade_glass, charsmax(sprite_grenade_glass), value)
  6635.             }
  6636.             case SECTION_SOUNDS:
  6637.             {
  6638.                 if (equal(key, "WIN ZOMBIES"))
  6639.                 {
  6640.                     // Parse sounds
  6641.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6642.                     {
  6643.                         // Trim spaces
  6644.                         trim(key)
  6645.                         trim(value)
  6646.                        
  6647.                         // Add to sounds array
  6648.                         ArrayPushString(sound_win_zombies, key)
  6649.                         ArrayPushCell(sound_win_zombies_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6650.                     }
  6651.                 }
  6652.                 else if (equal(key, "WIN HUMANS"))
  6653.                 {
  6654.                     // Parse sounds
  6655.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6656.                     {
  6657.                         // Trim spaces
  6658.                         trim(key)
  6659.                         trim(value)
  6660.                        
  6661.                         // Add to sounds array
  6662.                         ArrayPushString(sound_win_humans, key)
  6663.                         ArrayPushCell(sound_win_humans_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6664.                     }
  6665.                 }
  6666.                 else if (equal(key, "WIN NO ONE"))
  6667.                 {
  6668.                     // Parse sounds
  6669.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6670.                     {
  6671.                         // Trim spaces
  6672.                         trim(key)
  6673.                         trim(value)
  6674.                        
  6675.                         // Add to sounds array
  6676.                         ArrayPushString(sound_win_no_one, key)
  6677.                         ArrayPushCell(sound_win_no_one_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6678.                     }
  6679.                 }
  6680.                 else if (equal(key, "ZOMBIE INFECT"))
  6681.                 {
  6682.                     // Parse sounds
  6683.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6684.                     {
  6685.                         // Trim spaces
  6686.                         trim(key)
  6687.                         trim(value)
  6688.                        
  6689.                         // Add to sounds array
  6690.                         ArrayPushString(zombie_infect, key)
  6691.                     }
  6692.                 }
  6693.                 else if (equal(key, "ZOMBIE PAIN"))
  6694.                 {
  6695.                     // Parse sounds
  6696.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6697.                     {
  6698.                         // Trim spaces
  6699.                         trim(key)
  6700.                         trim(value)
  6701.                        
  6702.                         // Add to sounds array
  6703.                         ArrayPushString(zombie_pain, key)
  6704.                     }
  6705.                 }
  6706.                 else if (equal(key, "NEMESIS PAIN"))
  6707.                 {
  6708.                     // Parse sounds
  6709.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6710.                     {
  6711.                         // Trim spaces
  6712.                         trim(key)
  6713.                         trim(value)
  6714.                        
  6715.                         // Add to sounds array
  6716.                         ArrayPushString(nemesis_pain, key)
  6717.                     }
  6718.                 }
  6719.                 else if (equal(key, "ZOMBIE DIE"))
  6720.                 {
  6721.                     // Parse sounds
  6722.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6723.                     {
  6724.                         // Trim spaces
  6725.                         trim(key)
  6726.                         trim(value)
  6727.                        
  6728.                         // Add to sounds array
  6729.                         ArrayPushString(zombie_die, key)
  6730.                     }
  6731.                 }
  6732.                 else if (equal(key, "ZOMBIE FALL"))
  6733.                 {
  6734.                     // Parse sounds
  6735.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6736.                     {
  6737.                         // Trim spaces
  6738.                         trim(key)
  6739.                         trim(value)
  6740.                        
  6741.                         // Add to sounds array
  6742.                         ArrayPushString(zombie_fall, key)
  6743.                     }
  6744.                 }
  6745.                 else if (equal(key, "ZOMBIE MISS SLASH"))
  6746.                 {
  6747.                     // Parse sounds
  6748.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6749.                     {
  6750.                         // Trim spaces
  6751.                         trim(key)
  6752.                         trim(value)
  6753.                        
  6754.                         // Add to sounds array
  6755.                         ArrayPushString(zombie_miss_slash, key)
  6756.                     }
  6757.                 }
  6758.                 else if (equal(key, "ZOMBIE MISS WALL"))
  6759.                 {
  6760.                     // Parse sounds
  6761.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6762.                     {
  6763.                         // Trim spaces
  6764.                         trim(key)
  6765.                         trim(value)
  6766.                        
  6767.                         // Add to sounds array
  6768.                         ArrayPushString(zombie_miss_wall, key)
  6769.                     }
  6770.                 }
  6771.                 else if (equal(key, "ZOMBIE HIT NORMAL"))
  6772.                 {
  6773.                     // Parse sounds
  6774.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6775.                     {
  6776.                         // Trim spaces
  6777.                         trim(key)
  6778.                         trim(value)
  6779.                        
  6780.                         // Add to sounds array
  6781.                         ArrayPushString(zombie_hit_normal, key)
  6782.                     }
  6783.                 }
  6784.                 else if (equal(key, "ZOMBIE HIT STAB"))
  6785.                 {
  6786.                     // Parse sounds
  6787.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6788.                     {
  6789.                         // Trim spaces
  6790.                         trim(key)
  6791.                         trim(value)
  6792.                        
  6793.                         // Add to sounds array
  6794.                         ArrayPushString(zombie_hit_stab, key)
  6795.                     }
  6796.                 }
  6797.                 else if (equal(key, "ZOMBIE IDLE"))
  6798.                 {
  6799.                     // Parse sounds
  6800.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6801.                     {
  6802.                         // Trim spaces
  6803.                         trim(key)
  6804.                         trim(value)
  6805.                        
  6806.                         // Add to sounds array
  6807.                         ArrayPushString(zombie_idle, key)
  6808.                     }
  6809.                 }
  6810.                 else if (equal(key, "ZOMBIE IDLE LAST"))
  6811.                 {
  6812.                     // Parse sounds
  6813.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6814.                     {
  6815.                         // Trim spaces
  6816.                         trim(key)
  6817.                         trim(value)
  6818.                        
  6819.                         // Add to sounds array
  6820.                         ArrayPushString(zombie_idle_last, key)
  6821.                     }
  6822.                 }
  6823.                 else if (equal(key, "ZOMBIE MADNESS"))
  6824.                 {
  6825.                     // Parse sounds
  6826.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6827.                     {
  6828.                         // Trim spaces
  6829.                         trim(key)
  6830.                         trim(value)
  6831.                        
  6832.                         // Add to sounds array
  6833.                         ArrayPushString(zombie_madness, key)
  6834.                     }
  6835.                 }
  6836.                 else if (equal(key, "ROUND NEMESIS"))
  6837.                 {
  6838.                     // Parse sounds
  6839.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6840.                     {
  6841.                         // Trim spaces
  6842.                         trim(key)
  6843.                         trim(value)
  6844.                        
  6845.                         // Add to sounds array
  6846.                         ArrayPushString(sound_nemesis, key)
  6847.                     }
  6848.                 }
  6849.                 else if (equal(key, "ROUND SURVIVOR"))
  6850.                 {
  6851.                     // Parse sounds
  6852.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6853.                     {
  6854.                         // Trim spaces
  6855.                         trim(key)
  6856.                         trim(value)
  6857.                        
  6858.                         // Add to sounds array
  6859.                         ArrayPushString(sound_survivor, key)
  6860.                     }
  6861.                 }
  6862.                 else if (equal(key, "ROUND SWARM"))
  6863.                 {
  6864.                     // Parse sounds
  6865.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6866.                     {
  6867.                         // Trim spaces
  6868.                         trim(key)
  6869.                         trim(value)
  6870.                        
  6871.                         // Add to sounds array
  6872.                         ArrayPushString(sound_swarm, key)
  6873.                     }
  6874.                 }
  6875.                 else if (equal(key, "ROUND MULTI"))
  6876.                 {
  6877.                     // Parse sounds
  6878.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6879.                     {
  6880.                         // Trim spaces
  6881.                         trim(key)
  6882.                         trim(value)
  6883.                        
  6884.                         // Add to sounds array
  6885.                         ArrayPushString(sound_multi, key)
  6886.                     }
  6887.                 }
  6888.                 else if (equal(key, "ROUND PLAGUE"))
  6889.                 {
  6890.                     // Parse sounds
  6891.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6892.                     {
  6893.                         // Trim spaces
  6894.                         trim(key)
  6895.                         trim(value)
  6896.                        
  6897.                         // Add to sounds array
  6898.                         ArrayPushString(sound_plague, key)
  6899.                     }
  6900.                 }
  6901.                 else if (equal(key, "GRENADE INFECT EXPLODE"))
  6902.                 {
  6903.                     // Parse sounds
  6904.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6905.                     {
  6906.                         // Trim spaces
  6907.                         trim(key)
  6908.                         trim(value)
  6909.                        
  6910.                         // Add to sounds array
  6911.                         ArrayPushString(grenade_infect, key)
  6912.                     }
  6913.                 }
  6914.                 else if (equal(key, "GRENADE INFECT PLAYER"))
  6915.                 {
  6916.                     // Parse sounds
  6917.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6918.                     {
  6919.                         // Trim spaces
  6920.                         trim(key)
  6921.                         trim(value)
  6922.                        
  6923.                         // Add to sounds array
  6924.                         ArrayPushString(grenade_infect_player, key)
  6925.                     }
  6926.                 }
  6927.                 else if (equal(key, "GRENADE FIRE EXPLODE"))
  6928.                 {
  6929.                     // Parse sounds
  6930.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6931.                     {
  6932.                         // Trim spaces
  6933.                         trim(key)
  6934.                         trim(value)
  6935.                        
  6936.                         // Add to sounds array
  6937.                         ArrayPushString(grenade_fire, key)
  6938.                     }
  6939.                 }
  6940.                 else if (equal(key, "GRENADE FIRE PLAYER"))
  6941.                 {
  6942.                     // Parse sounds
  6943.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6944.                     {
  6945.                         // Trim spaces
  6946.                         trim(key)
  6947.                         trim(value)
  6948.                        
  6949.                         // Add to sounds array
  6950.                         ArrayPushString(grenade_fire_player, key)
  6951.                     }
  6952.                 }
  6953.                 else if (equal(key, "GRENADE FROST EXPLODE"))
  6954.                 {
  6955.                     // Parse sounds
  6956.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6957.                     {
  6958.                         // Trim spaces
  6959.                         trim(key)
  6960.                         trim(value)
  6961.                        
  6962.                         // Add to sounds array
  6963.                         ArrayPushString(grenade_frost, key)
  6964.                     }
  6965.                 }
  6966.                 else if (equal(key, "GRENADE FROST PLAYER"))
  6967.                 {
  6968.                     // Parse sounds
  6969.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6970.                     {
  6971.                         // Trim spaces
  6972.                         trim(key)
  6973.                         trim(value)
  6974.                        
  6975.                         // Add to sounds array
  6976.                         ArrayPushString(grenade_frost_player, key)
  6977.                     }
  6978.                 }
  6979.                 else if (equal(key, "GRENADE FROST BREAK"))
  6980.                 {
  6981.                     // Parse sounds
  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 sounds array
  6989.                         ArrayPushString(grenade_frost_break, key)
  6990.                     }
  6991.                 }
  6992.                 else if (equal(key, "GRENADE FLARE"))
  6993.                 {
  6994.                     // Parse sounds
  6995.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6996.                     {
  6997.                         // Trim spaces
  6998.                         trim(key)
  6999.                         trim(value)
  7000.                        
  7001.                         // Add to sounds array
  7002.                         ArrayPushString(grenade_flare, key)
  7003.                     }
  7004.                 }
  7005.                 else if (equal(key, "ANTIDOTE"))
  7006.                 {
  7007.                     // Parse sounds
  7008.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7009.                     {
  7010.                         // Trim spaces
  7011.                         trim(key)
  7012.                         trim(value)
  7013.                        
  7014.                         // Add to sounds array
  7015.                         ArrayPushString(sound_antidote, key)
  7016.                     }
  7017.                 }
  7018.                 else if (equal(key, "THUNDER"))
  7019.                 {
  7020.                     // Parse sounds
  7021.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7022.                     {
  7023.                         // Trim spaces
  7024.                         trim(key)
  7025.                         trim(value)
  7026.                        
  7027.                         // Add to sounds array
  7028.                         ArrayPushString(sound_thunder, key)
  7029.                     }
  7030.                 }
  7031.             }
  7032.             case SECTION_AMBIENCE_SOUNDS:
  7033.             {
  7034.                 if (equal(key, "INFECTION ENABLE"))
  7035.                     g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] = str_to_num(value)
  7036.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION SOUNDS"))
  7037.                 {
  7038.                     // Parse sounds
  7039.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7040.                     {
  7041.                         // Trim spaces
  7042.                         trim(key)
  7043.                         trim(value)
  7044.                        
  7045.                         // Add to sounds array
  7046.                         ArrayPushString(sound_ambience1, key)
  7047.                         ArrayPushCell(sound_ambience1_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7048.                     }
  7049.                 }
  7050.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION DURATIONS"))
  7051.                 {
  7052.                     // Parse sounds
  7053.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7054.                     {
  7055.                         // Trim spaces
  7056.                         trim(key)
  7057.                         trim(value)
  7058.                        
  7059.                         // Add to sounds array
  7060.                         ArrayPushCell(sound_ambience1_duration, str_to_num(key))
  7061.                     }
  7062.                 }
  7063.                 else if (equal(key, "NEMESIS ENABLE"))
  7064.                     g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] = str_to_num(value)
  7065.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS SOUNDS"))
  7066.                 {
  7067.                     // Parse sounds
  7068.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7069.                     {
  7070.                         // Trim spaces
  7071.                         trim(key)
  7072.                         trim(value)
  7073.                        
  7074.                         // Add to sounds array
  7075.                         ArrayPushString(sound_ambience2, key)
  7076.                         ArrayPushCell(sound_ambience2_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7077.                     }
  7078.                 }
  7079.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS DURATIONS"))
  7080.                 {
  7081.                     // Parse sounds
  7082.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7083.                     {
  7084.                         // Trim spaces
  7085.                         trim(key)
  7086.                         trim(value)
  7087.                        
  7088.                         // Add to sounds array
  7089.                         ArrayPushCell(sound_ambience2_duration, str_to_num(key))
  7090.                     }
  7091.                 }
  7092.                 else if (equal(key, "SURVIVOR ENABLE"))
  7093.                     g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] = str_to_num(value)
  7094.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR SOUNDS"))
  7095.                 {
  7096.                     // Parse sounds
  7097.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7098.                     {
  7099.                         // Trim spaces
  7100.                         trim(key)
  7101.                         trim(value)
  7102.                        
  7103.                         // Add to sounds array
  7104.                         ArrayPushString(sound_ambience3, key)
  7105.                         ArrayPushCell(sound_ambience3_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7106.                     }
  7107.                 }
  7108.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR DURATIONS"))
  7109.                 {
  7110.                     // Parse sounds
  7111.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7112.                     {
  7113.                         // Trim spaces
  7114.                         trim(key)
  7115.                         trim(value)
  7116.                        
  7117.                         // Add to sounds array
  7118.                         ArrayPushCell(sound_ambience3_duration, str_to_num(key))
  7119.                     }
  7120.                 }
  7121.                 else if (equal(key, "SWARM ENABLE"))
  7122.                     g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] = str_to_num(value)
  7123.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM SOUNDS"))
  7124.                 {
  7125.                     // Parse sounds
  7126.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7127.                     {
  7128.                         // Trim spaces
  7129.                         trim(key)
  7130.                         trim(value)
  7131.                        
  7132.                         // Add to sounds array
  7133.                         ArrayPushString(sound_ambience4, key)
  7134.                         ArrayPushCell(sound_ambience4_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7135.                     }
  7136.                 }
  7137.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM DURATIONS"))
  7138.                 {
  7139.                     // Parse sounds
  7140.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7141.                     {
  7142.                         // Trim spaces
  7143.                         trim(key)
  7144.                         trim(value)
  7145.                        
  7146.                         // Add to sounds array
  7147.                         ArrayPushCell(sound_ambience4_duration, str_to_num(key))
  7148.                     }
  7149.                 }
  7150.                 else if (equal(key, "PLAGUE ENABLE"))
  7151.                     g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] = str_to_num(value)
  7152.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE SOUNDS"))
  7153.                 {
  7154.                     // Parse sounds
  7155.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7156.                     {
  7157.                         // Trim spaces
  7158.                         trim(key)
  7159.                         trim(value)
  7160.                        
  7161.                         // Add to sounds array
  7162.                         ArrayPushString(sound_ambience5, key)
  7163.                         ArrayPushCell(sound_ambience5_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7164.                     }
  7165.                 }
  7166.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE DURATIONS"))
  7167.                 {
  7168.                     // Parse sounds
  7169.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7170.                     {
  7171.                         // Trim spaces
  7172.                         trim(key)
  7173.                         trim(value)
  7174.                        
  7175.                         // Add to sounds array
  7176.                         ArrayPushCell(sound_ambience5_duration, str_to_num(key))
  7177.                     }
  7178.                 }
  7179.             }
  7180.             case SECTION_BUY_MENU_WEAPONS:
  7181.             {
  7182.                 if (equal(key, "PRIMARY"))
  7183.                 {
  7184.                     // Parse weapons
  7185.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7186.                     {
  7187.                         // Trim spaces
  7188.                         trim(key)
  7189.                         trim(value)
  7190.                        
  7191.                         // Add to weapons array
  7192.                         ArrayPushString(g_primary_items, key)
  7193.                         ArrayPushCell(g_primary_weaponids, cs_weapon_name_to_id(key))
  7194.                     }
  7195.                 }
  7196.                 else if (equal(key, "SECONDARY"))
  7197.                 {
  7198.                     // Parse weapons
  7199.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7200.                     {
  7201.                         // Trim spaces
  7202.                         trim(key)
  7203.                         trim(value)
  7204.                        
  7205.                         // Add to weapons array
  7206.                         ArrayPushString(g_secondary_items, key)
  7207.                         ArrayPushCell(g_secondary_weaponids, cs_weapon_name_to_id(key))
  7208.                     }
  7209.                 }
  7210.                 else if (equal(key, "ADDITIONAL ITEMS"))
  7211.                 {
  7212.                     // Parse weapons
  7213.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7214.                     {
  7215.                         // Trim spaces
  7216.                         trim(key)
  7217.                         trim(value)
  7218.                        
  7219.                         // Add to weapons array
  7220.                         ArrayPushString(g_additional_items, key)
  7221.                     }
  7222.                 }
  7223.             }
  7224.             case SECTION_EXTRA_ITEMS_WEAPONS:
  7225.             {
  7226.                 if (equal(key, "NAMES"))
  7227.                 {
  7228.                     // Parse weapon items
  7229.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7230.                     {
  7231.                         // Trim spaces
  7232.                         trim(key)
  7233.                         trim(value)
  7234.                        
  7235.                         // Add to weapons array
  7236.                         ArrayPushString(g_extraweapon_names, key)
  7237.                     }
  7238.                 }
  7239.                 else if (equal(key, "ITEMS"))
  7240.                 {
  7241.                     // Parse weapon items
  7242.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7243.                     {
  7244.                         // Trim spaces
  7245.                         trim(key)
  7246.                         trim(value)
  7247.                        
  7248.                         // Add to weapons array
  7249.                         ArrayPushString(g_extraweapon_items, key)
  7250.                     }
  7251.                 }
  7252.                 else if (equal(key, "COSTS"))
  7253.                 {
  7254.                     // Parse weapon items
  7255.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7256.                     {
  7257.                         // Trim spaces
  7258.                         trim(key)
  7259.                         trim(value)
  7260.                        
  7261.                         // Add to weapons array
  7262.                         ArrayPushCell(g_extraweapon_costs, str_to_num(key))
  7263.                     }
  7264.                 }
  7265.             }
  7266.             case SECTION_HARD_CODED_ITEMS_COSTS:
  7267.             {
  7268.                 if (equal(key, "NIGHT VISION"))
  7269.                     g_extra_costs2[EXTRA_NVISION] = str_to_num(value)
  7270.                 else if (equal(key, "ANTIDOTE"))
  7271.                     g_extra_costs2[EXTRA_ANTIDOTE] = str_to_num(value)
  7272.                 else if (equal(key, "ZOMBIE MADNESS"))
  7273.                     g_extra_costs2[EXTRA_MADNESS] = str_to_num(value)
  7274.                 else if (equal(key, "INFECTION BOMB"))
  7275.                     g_extra_costs2[EXTRA_INFBOMB] = str_to_num(value)
  7276.             }
  7277.             case SECTION_WEATHER_EFFECTS:
  7278.             {
  7279.                 if (equal(key, "RAIN"))
  7280.                     g_ambience_rain = str_to_num(value)
  7281.                 else if (equal(key, "SNOW"))
  7282.                     g_ambience_snow = str_to_num(value)
  7283.                 else if (equal(key, "FOG"))
  7284.                     g_ambience_fog = str_to_num(value)
  7285.                 else if (equal(key, "FOG DENSITY"))
  7286.                     copy(g_fog_density, charsmax(g_fog_density), value)
  7287.                 else if (equal(key, "FOG COLOR"))
  7288.                     copy(g_fog_color, charsmax(g_fog_color), value)
  7289.             }
  7290.             case SECTION_SKY:
  7291.             {
  7292.                 if (equal(key, "ENABLE"))
  7293.                     g_sky_enable = str_to_num(value)
  7294.                 else if (equal(key, "SKY NAMES"))
  7295.                 {
  7296.                     // Parse sky names
  7297.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7298.                     {
  7299.                         // Trim spaces
  7300.                         trim(key)
  7301.                         trim(value)
  7302.                        
  7303.                         // Add to skies array
  7304.                         ArrayPushString(g_sky_names, key)
  7305.                        
  7306.                         // Preache custom sky files
  7307.                         formatex(linedata, charsmax(linedata), "gfx/env/%sbk.tga", key)
  7308.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7309.                         formatex(linedata, charsmax(linedata), "gfx/env/%sdn.tga", key)
  7310.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7311.                         formatex(linedata, charsmax(linedata), "gfx/env/%sft.tga", key)
  7312.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7313.                         formatex(linedata, charsmax(linedata), "gfx/env/%slf.tga", key)
  7314.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7315.                         formatex(linedata, charsmax(linedata), "gfx/env/%srt.tga", key)
  7316.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7317.                         formatex(linedata, charsmax(linedata), "gfx/env/%sup.tga", key)
  7318.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7319.                     }
  7320.                 }
  7321.             }
  7322.             case SECTION_LIGHTNING:
  7323.             {
  7324.                 if (equal(key, "LIGHTS"))
  7325.                 {
  7326.                     // Parse lights
  7327.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7328.                     {
  7329.                         // Trim spaces
  7330.                         trim(key)
  7331.                         trim(value)
  7332.                        
  7333.                         // Add to lightning array
  7334.                         ArrayPushString(lights_thunder, key)
  7335.                     }
  7336.                 }
  7337.             }
  7338.             case SECTION_ZOMBIE_DECALS:
  7339.             {
  7340.                 if (equal(key, "DECALS"))
  7341.                 {
  7342.                     // Parse decals
  7343.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7344.                     {
  7345.                         // Trim spaces
  7346.                         trim(key)
  7347.                         trim(value)
  7348.                        
  7349.                         // Add to zombie decals array
  7350.                         ArrayPushCell(zombie_decals, str_to_num(key))
  7351.                     }
  7352.                 }
  7353.             }
  7354.             case SECTION_KNOCKBACK:
  7355.             {
  7356.                 // Format weapon entity name
  7357.                 strtolower(key)
  7358.                 format(key, charsmax(key), "weapon_%s", key)
  7359.                
  7360.                 // Add value to knockback power array
  7361.                 kb_weapon_power[cs_weapon_name_to_id(key)] = str_to_float(value)
  7362.             }
  7363.             case SECTION_OBJECTIVE_ENTS:
  7364.             {
  7365.                 if (equal(key, "CLASSNAMES"))
  7366.                 {
  7367.                     // Parse classnames
  7368.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7369.                     {
  7370.                         // Trim spaces
  7371.                         trim(key)
  7372.                         trim(value)
  7373.                        
  7374.                         // Add to objective ents array
  7375.                         ArrayPushString(g_objective_ents, key)
  7376.                     }
  7377.                 }
  7378.             }
  7379.             case SECTION_SVC_BAD:
  7380.             {
  7381.                 if (equal(key, "MODELCHANGE DELAY"))
  7382.                     g_modelchange_delay = str_to_float(value)
  7383.                 else if (equal(key, "HANDLE MODELS ON SEPARATE ENT"))
  7384.                     g_handle_models_on_separate_ent = str_to_num(value)
  7385.                 else if (equal(key, "SET MODELINDEX OFFSET"))
  7386.                     g_set_modelindex_offset = str_to_num(value)
  7387.             }
  7388.         }
  7389.     }
  7390.     if (file) fclose(file)
  7391.    
  7392.     // Build zombie classes file path
  7393.     get_configsdir(path, charsmax(path))
  7394.     format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
  7395.    
  7396.     // Parse if present
  7397.     if (file_exists(path))
  7398.     {
  7399.         // Open zombie classes file for reading
  7400.         file = fopen(path, "rt")
  7401.        
  7402.         while (file && !feof(file))
  7403.         {
  7404.             // Read one line at a time
  7405.             fgets(file, linedata, charsmax(linedata))
  7406.            
  7407.             // Replace newlines with a null character to prevent headaches
  7408.             replace(linedata, charsmax(linedata), "^n", "")
  7409.            
  7410.             // Blank line or comment
  7411.             if (!linedata[0] || linedata[0] == ';') continue;
  7412.            
  7413.             // New class starting
  7414.             if (linedata[0] == '[')
  7415.             {
  7416.                 // Remove first and last characters (braces)
  7417.                 linedata[strlen(linedata) - 1] = 0
  7418.                 copy(linedata, charsmax(linedata), linedata[1])
  7419.                
  7420.                 // Store its real name for future reference
  7421.                 ArrayPushString(g_zclass2_realname, linedata)
  7422.                 continue;
  7423.             }
  7424.            
  7425.             // Get key and value(s)
  7426.             strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  7427.            
  7428.             // Trim spaces
  7429.             trim(key)
  7430.             trim(value)
  7431.            
  7432.             if (equal(key, "NAME"))
  7433.                 ArrayPushString(g_zclass2_name, value)
  7434.             else if (equal(key, "INFO"))
  7435.                 ArrayPushString(g_zclass2_info, value)
  7436.             else if (equal(key, "MODELS"))
  7437.             {
  7438.                 // Set models start index
  7439.                 ArrayPushCell(g_zclass2_modelsstart, ArraySize(g_zclass2_playermodel))
  7440.                
  7441.                 // Parse class models
  7442.                 while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7443.                 {
  7444.                     // Trim spaces
  7445.                     trim(key)
  7446.                     trim(value)
  7447.                    
  7448.                     // Add to class models array
  7449.                     ArrayPushString(g_zclass2_playermodel, key)
  7450.                     ArrayPushCell(g_zclass2_modelindex, -1)
  7451.                 }
  7452.                
  7453.                 // Set models end index
  7454.                 ArrayPushCell(g_zclass2_modelsend, ArraySize(g_zclass2_playermodel))
  7455.             }
  7456.             else if (equal(key, "CLAWMODEL"))
  7457.                 ArrayPushString(g_zclass2_clawmodel, value)
  7458.             else if (equal(key, "HEALTH"))
  7459.                 ArrayPushCell(g_zclass2_hp, str_to_num(value))
  7460.             else if (equal(key, "SPEED"))
  7461.                 ArrayPushCell(g_zclass2_spd, str_to_num(value))
  7462.             else if (equal(key, "GRAVITY"))
  7463.                 ArrayPushCell(g_zclass2_grav, str_to_float(value))
  7464.             else if (equal(key, "KNOCKBACK"))
  7465.                 ArrayPushCell(g_zclass2_kb, str_to_float(value))
  7466.         }
  7467.         if (file) fclose(file)
  7468.     }
  7469.    
  7470.     // Build extra items file path
  7471.     get_configsdir(path, charsmax(path))
  7472.     format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
  7473.    
  7474.     // Parse if present
  7475.     if (file_exists(path))
  7476.     {
  7477.         // Open extra items file for reading
  7478.         file = fopen(path, "rt")
  7479.        
  7480.         while (file && !feof(file))
  7481.         {
  7482.             // Read one line at a time
  7483.             fgets(file, linedata, charsmax(linedata))
  7484.            
  7485.             // Replace newlines with a null character to prevent headaches
  7486.             replace(linedata, charsmax(linedata), "^n", "")
  7487.            
  7488.             // Blank line or comment
  7489.             if (!linedata[0] || linedata[0] == ';') continue;
  7490.            
  7491.             // New item starting
  7492.             if (linedata[0] == '[')
  7493.             {
  7494.                 // Remove first and last characters (braces)
  7495.                 linedata[strlen(linedata) - 1] = 0
  7496.                 copy(linedata, charsmax(linedata), linedata[1])
  7497.                
  7498.                 // Store its real name for future reference
  7499.                 ArrayPushString(g_extraitem2_realname, linedata)
  7500.                 continue;
  7501.             }
  7502.            
  7503.             // Get key and value(s)
  7504.             strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  7505.            
  7506.             // Trim spaces
  7507.             trim(key)
  7508.             trim(value)
  7509.            
  7510.             if (equal(key, "NAME"))
  7511.                 ArrayPushString(g_extraitem2_name, value)
  7512.             else if (equal(key, "COST"))
  7513.                 ArrayPushCell(g_extraitem2_cost, str_to_num(value))
  7514.             else if (equal(key, "TEAMS"))
  7515.             {
  7516.                 // Clear teams bitsum
  7517.                 teams = 0
  7518.                
  7519.                 // Parse teams
  7520.                 while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7521.                 {
  7522.                     // Trim spaces
  7523.                     trim(key)
  7524.                     trim(value)
  7525.                    
  7526.                     if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_ZOMBIE]))
  7527.                         teams |= ZP_TEAM_ZOMBIE
  7528.                     else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_HUMAN]))
  7529.                         teams |= ZP_TEAM_HUMAN
  7530.                     else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_NEMESIS]))
  7531.                         teams |= ZP_TEAM_NEMESIS
  7532.                     else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_SURVIVOR]))
  7533.                         teams |= ZP_TEAM_SURVIVOR
  7534.                 }
  7535.                
  7536.                 // Add to teams array
  7537.                 ArrayPushCell(g_extraitem2_team, teams)
  7538.             }
  7539.         }
  7540.         if (file) fclose(file)
  7541.     }
  7542. }
  7543.  
  7544. save_customization()
  7545. {
  7546.     new i, k, buffer[512]
  7547.    
  7548.     // Build zombie classes file path
  7549.     new path[64]
  7550.     get_configsdir(path, charsmax(path))
  7551.     format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
  7552.    
  7553.     // Open zombie classes file for appending data
  7554.     new file = fopen(path, "at"), size = ArraySize(g_zclass_name)
  7555.    
  7556.     // Add any new zombie classes data at the end if needed
  7557.     for (i = 0; i < size; i++)
  7558.     {
  7559.         if (ArrayGetCell(g_zclass_new, i))
  7560.         {
  7561.             // Add real name
  7562.             ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
  7563.             format(buffer, charsmax(buffer), "^n[%s]", buffer)
  7564.             fputs(file, buffer)
  7565.            
  7566.             // Add caption
  7567.             ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
  7568.             format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
  7569.             fputs(file, buffer)
  7570.            
  7571.             // Add info
  7572.             ArrayGetString(g_zclass_info, i, buffer, charsmax(buffer))
  7573.             format(buffer, charsmax(buffer), "^nINFO = %s", buffer)
  7574.             fputs(file, buffer)
  7575.            
  7576.             // Add models
  7577.             for (k = ArrayGetCell(g_zclass_modelsstart, i); k < ArrayGetCell(g_zclass_modelsend, i); k++)
  7578.             {
  7579.                 if (k == ArrayGetCell(g_zclass_modelsstart, i))
  7580.                 {
  7581.                     // First model, overwrite buffer
  7582.                     ArrayGetString(g_zclass_playermodel, k, buffer, charsmax(buffer))
  7583.                 }
  7584.                 else
  7585.                 {
  7586.                     // Successive models, append to buffer
  7587.                     ArrayGetString(g_zclass_playermodel, k, path, charsmax(path))
  7588.                     format(buffer, charsmax(buffer), "%s , %s", buffer, path)
  7589.                 }
  7590.             }
  7591.             format(buffer, charsmax(buffer), "^nMODELS = %s", buffer)
  7592.             fputs(file, buffer)
  7593.            
  7594.             // Add clawmodel
  7595.             ArrayGetString(g_zclass_clawmodel, i, buffer, charsmax(buffer))
  7596.             format(buffer, charsmax(buffer), "^nCLAWMODEL = %s", buffer)
  7597.             fputs(file, buffer)
  7598.            
  7599.             // Add health
  7600.             formatex(buffer, charsmax(buffer), "^nHEALTH = %d", ArrayGetCell(g_zclass_hp, i))
  7601.             fputs(file, buffer)
  7602.            
  7603.             // Add speed
  7604.             formatex(buffer, charsmax(buffer), "^nSPEED = %d", ArrayGetCell(g_zclass_spd, i))
  7605.             fputs(file, buffer)
  7606.            
  7607.             // Add gravity
  7608.             formatex(buffer, charsmax(buffer), "^nGRAVITY = %.2f", Float:ArrayGetCell(g_zclass_grav, i))
  7609.             fputs(file, buffer)
  7610.            
  7611.             // Add knockback
  7612.             formatex(buffer, charsmax(buffer), "^nKNOCKBACK = %.2f^n", Float:ArrayGetCell(g_zclass_kb, i))
  7613.             fputs(file, buffer)
  7614.         }
  7615.     }
  7616.     fclose(file)
  7617.    
  7618.     // Build extra items file path
  7619.     get_configsdir(path, charsmax(path))
  7620.     format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
  7621.    
  7622.     // Open extra items file for appending data
  7623.     file = fopen(path, "at")
  7624.     size = ArraySize(g_extraitem_name)
  7625.    
  7626.     // Add any new extra items data at the end if needed
  7627.     for (i = EXTRAS_CUSTOM_STARTID; i < size; i++)
  7628.     {
  7629.         if (ArrayGetCell(g_extraitem_new, i))
  7630.         {
  7631.             // Add real name
  7632.             ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
  7633.             format(buffer, charsmax(buffer), "^n[%s]", buffer)
  7634.             fputs(file, buffer)
  7635.            
  7636.             // Add caption
  7637.             ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
  7638.             format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
  7639.             fputs(file, buffer)
  7640.            
  7641.             // Add cost
  7642.             formatex(buffer, charsmax(buffer), "^nCOST = %d", ArrayGetCell(g_extraitem_cost, i))
  7643.             fputs(file, buffer)
  7644.            
  7645.             // Add team
  7646.             formatex(buffer, charsmax(buffer), "^nTEAMS = %s^n", ZP_TEAM_NAMES[ArrayGetCell(g_extraitem_team, i)])
  7647.             fputs(file, buffer)
  7648.         }
  7649.     }
  7650.     fclose(file)
  7651.    
  7652.     // Free arrays containing class/item overrides
  7653.     ArrayDestroy(g_zclass2_realname)
  7654.     ArrayDestroy(g_zclass2_name)
  7655.     ArrayDestroy(g_zclass2_info)
  7656.     ArrayDestroy(g_zclass2_modelsstart)
  7657.     ArrayDestroy(g_zclass2_modelsend)
  7658.     ArrayDestroy(g_zclass2_playermodel)
  7659.     ArrayDestroy(g_zclass2_modelindex)
  7660.     ArrayDestroy(g_zclass2_clawmodel)
  7661.     ArrayDestroy(g_zclass2_hp)
  7662.     ArrayDestroy(g_zclass2_spd)
  7663.     ArrayDestroy(g_zclass2_grav)
  7664.     ArrayDestroy(g_zclass2_kb)
  7665.     ArrayDestroy(g_zclass_new)
  7666.     ArrayDestroy(g_extraitem2_realname)
  7667.     ArrayDestroy(g_extraitem2_name)
  7668.     ArrayDestroy(g_extraitem2_cost)
  7669.     ArrayDestroy(g_extraitem2_team)
  7670.     ArrayDestroy(g_extraitem_new)
  7671. }
  7672.  
  7673. // Register Ham Forwards for CZ bots
  7674. public register_ham_czbots(id)
  7675. {
  7676.     // Make sure it's a CZ bot and it's still connected
  7677.     if (g_hamczbots || !g_isconnected[id] || !get_pcvar_num(cvar_botquota))
  7678.         return;
  7679.    
  7680.     RegisterHamFromEntity(Ham_Spawn, id, "fw_PlayerSpawn_Post", 1)
  7681.     RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled")
  7682.     RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled_Post", 1)
  7683.     RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage")
  7684.     RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage_Post", 1)
  7685.     RegisterHamFromEntity(Ham_TraceAttack, id, "fw_TraceAttack")
  7686.     RegisterHamFromEntity(Ham_Player_ResetMaxSpeed, id, "fw_ResetMaxSpeed_Post", 1)
  7687.    
  7688.     // Ham forwards for CZ bots succesfully registered
  7689.     g_hamczbots = true
  7690.    
  7691.     // If the bot has already spawned, call the forward manually for him
  7692.     if (is_user_alive(id)) fw_PlayerSpawn_Post(id)
  7693. }
  7694.  
  7695. // Disable minmodels task
  7696. public disable_minmodels(id)
  7697. {
  7698.     if (!g_isconnected[id]) return;
  7699.     client_cmd(id, "cl_minmodels 0")
  7700. }
  7701.  
  7702. // Bots automatically buy extra items
  7703. public bot_buy_extras(taskid)
  7704. {
  7705.     // Nemesis or Survivor bots have nothing to buy by default
  7706.     if (!g_isalive[ID_SPAWN] || g_survivor[ID_SPAWN] || g_nemesis[ID_SPAWN])
  7707.         return;
  7708.    
  7709.     if (!g_zombie[ID_SPAWN]) // human bots
  7710.     {
  7711.         // Attempt to buy Night Vision
  7712.         buy_extra_item(ID_SPAWN, EXTRA_NVISION)
  7713.        
  7714.         // Attempt to buy a weapon
  7715.         buy_extra_item(ID_SPAWN, random_num(EXTRA_WEAPONS_STARTID, EXTRAS_CUSTOM_STARTID-1))
  7716.     }
  7717.     else // zombie bots
  7718.     {
  7719.         // Attempt to buy an Antidote
  7720.         buy_extra_item(ID_SPAWN, EXTRA_ANTIDOTE)
  7721.     }
  7722. }
  7723.  
  7724. // Refill BP Ammo Task
  7725. public refill_bpammo(const args[], id)
  7726. {
  7727.     // Player died or turned into a zombie
  7728.     if (!g_isalive[id] || g_zombie[id])
  7729.         return;
  7730.    
  7731.     set_msg_block(g_msgAmmoPickup, BLOCK_ONCE)
  7732.     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[REFILL_WEAPONID], AMMOTYPE[REFILL_WEAPONID], MAXBPAMMO[REFILL_WEAPONID])
  7733. }
  7734.  
  7735. // Balance Teams Task
  7736. balance_teams()
  7737. {
  7738.     // Get amount of users playing
  7739.     static iPlayersnum
  7740.     iPlayersnum = fnGetPlaying()
  7741.    
  7742.     // No players, don't bother
  7743.     if (iPlayersnum < 1) return;
  7744.    
  7745.     // Split players evenly
  7746.     static iTerrors, iMaxTerrors, id, team[33]
  7747.     iMaxTerrors = iPlayersnum/2
  7748.     iTerrors = 0
  7749.    
  7750.     // First, set everyone to CT
  7751.     for (id = 1; id <= g_maxplayers; id++)
  7752.     {
  7753.         // Skip if not connected
  7754.         if (!g_isconnected[id])
  7755.             continue;
  7756.        
  7757.         team[id] = fm_cs_get_user_team(id)
  7758.        
  7759.         // Skip if not playing
  7760.         if (team[id] == FM_CS_TEAM_SPECTATOR || team[id] == FM_CS_TEAM_UNASSIGNED)
  7761.             continue;
  7762.        
  7763.         // Set team
  7764.         remove_task(id+TASK_TEAM)
  7765.         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  7766.         team[id] = FM_CS_TEAM_CT
  7767.     }
  7768.    
  7769.     // Then randomly set half of the players to Terrorists
  7770.     while (iTerrors < iMaxTerrors)
  7771.     {
  7772.         // Keep looping through all players
  7773.         if (++id > g_maxplayers) id = 1
  7774.        
  7775.         // Skip if not connected
  7776.         if (!g_isconnected[id])
  7777.             continue;
  7778.        
  7779.         // Skip if not playing or already a Terrorist
  7780.         if (team[id] != FM_CS_TEAM_CT)
  7781.             continue;
  7782.        
  7783.         // Random chance
  7784.         if (random_num(0, 1))
  7785.         {
  7786.             fm_cs_set_user_team(id, FM_CS_TEAM_T)
  7787.             team[id] = FM_CS_TEAM_T
  7788.             iTerrors++
  7789.         }
  7790.     }
  7791. }
  7792.  
  7793. // Welcome Message Task
  7794. public welcome_msg()
  7795. {
  7796.     // Show mod info
  7797.     zp_colored_print(0, "^x01**** ^x04%s^x01 ****", g_modname)
  7798.     zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "NOTICE_INFO1")
  7799.     if (!get_pcvar_num(cvar_infammo)) zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "NOTICE_INFO2")
  7800.    
  7801.     // Show T-virus HUD notice
  7802.     set_hudmessage(0, 125, 200, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  7803.     ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_VIRUS_FREE")
  7804. }
  7805.  
  7806. // Respawn Player Task (deathmatch)
  7807. public respawn_player_task(taskid)
  7808. {
  7809.     // Already alive or round ended
  7810.     if (g_isalive[ID_SPAWN] || g_endround)
  7811.         return;
  7812.    
  7813.     // Get player's team
  7814.     static team
  7815.     team = fm_cs_get_user_team(ID_SPAWN)
  7816.    
  7817.     // Player moved to spectators
  7818.     if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  7819.         return;
  7820.    
  7821.     // Respawn player automatically if allowed on current round
  7822.     if ((!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)))
  7823.     {
  7824.         // Infection rounds = none of the above
  7825.         if (!get_pcvar_num(cvar_allowrespawninfection) && !g_survround && !g_nemround && !g_swarmround && !g_plagueround)
  7826.             return;
  7827.        
  7828.         // Respawn if only the last human is left? (ignore this setting on survivor rounds)
  7829.         if (!g_survround && !get_pcvar_num(cvar_respawnafterlast) && fnGetHumans() <= 1)
  7830.             return;
  7831.        
  7832.         // Respawn as zombie?
  7833.         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))
  7834.             g_respawn_as_zombie[ID_SPAWN] = true
  7835.        
  7836.         // Override respawn as zombie setting on nemesis and survivor rounds
  7837.         if (g_survround) g_respawn_as_zombie[ID_SPAWN] = true
  7838.         else if (g_nemround) g_respawn_as_zombie[ID_SPAWN] = false
  7839.        
  7840.         respawn_player_manually(ID_SPAWN)
  7841.     }
  7842. }
  7843.  
  7844. // Respawn Player Check Task (if killed by worldspawn)
  7845. public respawn_player_check_task(taskid)
  7846. {
  7847.     // Successfully spawned or round ended
  7848.     if (g_isalive[ID_SPAWN] || g_endround)
  7849.         return;
  7850.    
  7851.     // Get player's team
  7852.     static team
  7853.     team = fm_cs_get_user_team(ID_SPAWN)
  7854.    
  7855.     // Player moved to spectators
  7856.     if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  7857.         return;
  7858.    
  7859.     // If player was being spawned as a zombie, set the flag again
  7860.     if (g_zombie[ID_SPAWN]) g_respawn_as_zombie[ID_SPAWN] = true
  7861.     else g_respawn_as_zombie[ID_SPAWN] = false
  7862.    
  7863.     respawn_player_manually(ID_SPAWN)
  7864. }
  7865.  
  7866. // Respawn Player Manually (called after respawn checks are done)
  7867. respawn_player_manually(id)
  7868. {
  7869.     // Set proper team before respawning, so that the TeamInfo message that's sent doesn't confuse PODBots
  7870.     if (g_respawn_as_zombie[id])
  7871.         fm_cs_set_user_team(id, FM_CS_TEAM_T)
  7872.     else
  7873.         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  7874.    
  7875.     // Respawning a player has never been so easy
  7876.     ExecuteHamB(Ham_CS_RoundRespawn, id)
  7877. }
  7878.  
  7879. // Check Round Task -check that we still have both zombies and humans on a round-
  7880. check_round(leaving_player)
  7881. {
  7882.     // Round ended or make_a_zombie task still active
  7883.     if (g_endround || task_exists(TASK_MAKEZOMBIE))
  7884.         return;
  7885.    
  7886.     // Get alive players count
  7887.     static iPlayersnum, id
  7888.     iPlayersnum = fnGetAlive()
  7889.    
  7890.     // Last alive player, don't bother
  7891.     if (iPlayersnum < 2)
  7892.         return;
  7893.    
  7894.     // Last zombie disconnecting
  7895.     if (g_zombie[leaving_player] && fnGetZombies() == 1)
  7896.     {
  7897.         // Only one CT left, don't bother
  7898.         if (fnGetHumans() == 1 && fnGetCTs() == 1)
  7899.             return;
  7900.        
  7901.         // Pick a random one to take his place
  7902.         while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
  7903.        
  7904.         // Show last zombie left notice
  7905.         zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_ZOMBIE_LEFT", g_playername[id])
  7906.        
  7907.         // Set player leaving flag
  7908.         g_lastplayerleaving = true
  7909.        
  7910.         // Turn into a Nemesis or just a zombie?
  7911.         if (g_nemesis[leaving_player])
  7912.             zombieme(id, 0, 1, 0, 0)
  7913.         else
  7914.             zombieme(id, 0, 0, 0, 0)
  7915.        
  7916.         // Remove player leaving flag
  7917.         g_lastplayerleaving = false
  7918.        
  7919.         // If Nemesis, set chosen player's health to that of the one who's leaving
  7920.         if (get_pcvar_num(cvar_keephealthondisconnect) && g_nemesis[leaving_player])
  7921.             fm_set_user_health(id, pev(leaving_player, pev_health))
  7922.     }
  7923.    
  7924.     // Last human disconnecting
  7925.     else if (!g_zombie[leaving_player] && fnGetHumans() == 1)
  7926.     {
  7927.         // Only one T left, don't bother
  7928.         if (fnGetZombies() == 1 && fnGetTs() == 1)
  7929.             return;
  7930.        
  7931.         // Pick a random one to take his place
  7932.         while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
  7933.        
  7934.         // Show last human left notice
  7935.         zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_HUMAN_LEFT", g_playername[id])
  7936.        
  7937.         // Set player leaving flag
  7938.         g_lastplayerleaving = true
  7939.        
  7940.         // Turn into a Survivor or just a human?
  7941.         if (g_survivor[leaving_player])
  7942.             humanme(id, 1, 0)
  7943.         else
  7944.             humanme(id, 0, 0)
  7945.        
  7946.         // Remove player leaving flag
  7947.         g_lastplayerleaving = false
  7948.        
  7949.         // If Survivor, set chosen player's health to that of the one who's leaving
  7950.         if (get_pcvar_num(cvar_keephealthondisconnect) && g_survivor[leaving_player])
  7951.             fm_set_user_health(id, pev(leaving_player, pev_health))
  7952.     }
  7953. }
  7954.  
  7955. // Lighting Effects Task
  7956. public lighting_effects()
  7957. {
  7958.     // Cache some CVAR values at every 5 secs
  7959.     cache_cvars()
  7960.    
  7961.     // Get lighting style
  7962.     static lighting[2]
  7963.     get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
  7964.     strtolower(lighting)
  7965.    
  7966.     // Lighting disabled? ["0"]
  7967.     if (lighting[0] == '0')
  7968.         return;
  7969.    
  7970.     // Darkest light settings?
  7971.     if (lighting[0] >= 'a' && lighting[0] <= 'd')
  7972.     {
  7973.         static thunderclap_in_progress, Float:thunder
  7974.         thunderclap_in_progress = task_exists(TASK_THUNDER)
  7975.         thunder = get_pcvar_float(cvar_thunder)
  7976.        
  7977.         // Set thunderclap tasks if not existant
  7978.         if (thunder > 0.0 && !task_exists(TASK_THUNDER_PRE) && !thunderclap_in_progress)
  7979.         {
  7980.             g_lights_i = 0
  7981.             ArrayGetString(lights_thunder, random_num(0, ArraySize(lights_thunder) - 1), g_lights_cycle, charsmax(g_lights_cycle))
  7982.             g_lights_cycle_len = strlen(g_lights_cycle)
  7983.             set_task(thunder, "thunderclap", TASK_THUNDER_PRE)
  7984.         }
  7985.        
  7986.         // Set lighting only when no thunderclaps are going on
  7987.         if (!thunderclap_in_progress) engfunc(EngFunc_LightStyle, 0, lighting)
  7988.     }
  7989.     else
  7990.     {
  7991.         // Remove thunderclap tasks
  7992.         remove_task(TASK_THUNDER_PRE)
  7993.         remove_task(TASK_THUNDER)
  7994.        
  7995.         // Set lighting
  7996.         engfunc(EngFunc_LightStyle, 0, lighting)
  7997.     }
  7998. }
  7999.  
  8000. // Thunderclap task
  8001. public thunderclap()
  8002. {
  8003.     // Play thunder sound
  8004.     if (g_lights_i == 0)
  8005.     {
  8006.         static sound[64]
  8007.         ArrayGetString(sound_thunder, random_num(0, ArraySize(sound_thunder) - 1), sound, charsmax(sound))
  8008.         PlaySound(sound)
  8009.     }
  8010.    
  8011.     // Set lighting
  8012.     static light[2]
  8013.     light[0] = g_lights_cycle[g_lights_i]
  8014.     engfunc(EngFunc_LightStyle, 0, light)
  8015.    
  8016.     g_lights_i++
  8017.    
  8018.     // Lighting cycle end?
  8019.     if (g_lights_i >= g_lights_cycle_len)
  8020.     {
  8021.         remove_task(TASK_THUNDER)
  8022.         lighting_effects()
  8023.     }
  8024.     // Lighting cycle start?
  8025.     else if (!task_exists(TASK_THUNDER))
  8026.         set_task(0.1, "thunderclap", TASK_THUNDER, _, _, "b")
  8027. }
  8028.  
  8029. // Ambience Sound Effects Task
  8030. public ambience_sound_effects(taskid)
  8031. {
  8032.     // Play a random sound depending on the round
  8033.     static sound[64], iRand, duration
  8034.    
  8035.     if (g_nemround) // Nemesis Mode
  8036.     {
  8037.         iRand = random_num(0, ArraySize(sound_ambience2) - 1)
  8038.         ArrayGetString(sound_ambience2, iRand, sound, charsmax(sound))
  8039.         duration = ArrayGetCell(sound_ambience2_duration, iRand)
  8040.     }
  8041.     else if (g_survround) // Survivor Mode
  8042.     {
  8043.         iRand = random_num(0, ArraySize(sound_ambience3) - 1)
  8044.         ArrayGetString(sound_ambience3, iRand, sound, charsmax(sound))
  8045.         duration = ArrayGetCell(sound_ambience3_duration, iRand)
  8046.     }
  8047.     else if (g_swarmround) // Swarm Mode
  8048.     {
  8049.         iRand = random_num(0, ArraySize(sound_ambience4) - 1)
  8050.         ArrayGetString(sound_ambience4, iRand, sound, charsmax(sound))
  8051.         duration = ArrayGetCell(sound_ambience4_duration, iRand)
  8052.     }
  8053.     else if (g_plagueround) // Plague Mode
  8054.     {
  8055.         iRand = random_num(0, ArraySize(sound_ambience5) - 1)
  8056.         ArrayGetString(sound_ambience5, iRand, sound, charsmax(sound))
  8057.         duration = ArrayGetCell(sound_ambience5_duration, iRand)
  8058.     }
  8059.     else // Infection Mode
  8060.     {
  8061.         iRand = random_num(0, ArraySize(sound_ambience1) - 1)
  8062.         ArrayGetString(sound_ambience1, iRand, sound, charsmax(sound))
  8063.         duration = ArrayGetCell(sound_ambience1_duration, iRand)
  8064.     }
  8065.    
  8066.     // Play it on clients
  8067.     PlaySound(sound)
  8068.    
  8069.     // Set the task for when the sound is done playing
  8070.     set_task(float(duration), "ambience_sound_effects", TASK_AMBIENCESOUNDS)
  8071. }
  8072.  
  8073. // Ambience Sounds Stop Task
  8074. ambience_sound_stop()
  8075. {
  8076.     client_cmd(0, "mp3 stop; stopsound")
  8077. }
  8078.  
  8079. // Flashlight Charge Task
  8080. public flashlight_charge(taskid)
  8081. {
  8082.     // Drain or charge?
  8083.     if (g_flashlight[ID_CHARGE])
  8084.         g_flashbattery[ID_CHARGE] -= get_pcvar_num(cvar_flashdrain)
  8085.     else
  8086.         g_flashbattery[ID_CHARGE] += get_pcvar_num(cvar_flashcharge)
  8087.    
  8088.     // Battery fully charged
  8089.     if (g_flashbattery[ID_CHARGE] >= 100)
  8090.     {
  8091.         // Don't exceed 100%
  8092.         g_flashbattery[ID_CHARGE] = 100
  8093.        
  8094.         // Update flashlight battery on HUD
  8095.         message_begin(MSG_ONE, g_msgFlashBat, _, ID_CHARGE)
  8096.         write_byte(100) // battery
  8097.         message_end()
  8098.        
  8099.         // Task not needed anymore
  8100.         remove_task(taskid);
  8101.         return;
  8102.     }
  8103.    
  8104.     // Battery depleted
  8105.     if (g_flashbattery[ID_CHARGE] <= 0)
  8106.     {
  8107.         // Turn it off
  8108.         g_flashlight[ID_CHARGE] = false
  8109.         g_flashbattery[ID_CHARGE] = 0
  8110.        
  8111.         // Play flashlight toggle sound
  8112.         emit_sound(ID_CHARGE, CHAN_ITEM, sound_flashlight, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8113.        
  8114.         // Update flashlight status on HUD
  8115.         message_begin(MSG_ONE, g_msgFlashlight, _, ID_CHARGE)
  8116.         write_byte(0) // toggle
  8117.         write_byte(0) // battery
  8118.         message_end()
  8119.        
  8120.         // Remove flashlight task for this player
  8121.         remove_task(ID_CHARGE+TASK_FLASH)
  8122.     }
  8123.     else
  8124.     {
  8125.         // Update flashlight battery on HUD
  8126.         message_begin(MSG_ONE_UNRELIABLE, g_msgFlashBat, _, ID_CHARGE)
  8127.         write_byte(g_flashbattery[ID_CHARGE]) // battery
  8128.         message_end()
  8129.     }
  8130. }
  8131.  
  8132. // Remove Spawn Protection Task
  8133. public remove_spawn_protection(taskid)
  8134. {
  8135.     // Not alive
  8136.     if (!g_isalive[ID_SPAWN])
  8137.         return;
  8138.    
  8139.     // Remove spawn protection
  8140.     g_nodamage[ID_SPAWN] = false
  8141.     set_pev(ID_SPAWN, pev_effects, pev(ID_SPAWN, pev_effects) & ~EF_NODRAW)
  8142. }
  8143.  
  8144. // Hide Player's Money Task
  8145. public task_hide_money(taskid)
  8146. {
  8147.     // Not alive
  8148.     if (!g_isalive[ID_SPAWN])
  8149.         return;
  8150.    
  8151.     // Hide money
  8152.     message_begin(MSG_ONE, g_msgHideWeapon, _, ID_SPAWN)
  8153.     write_byte(HIDE_MONEY) // what to hide bitsum
  8154.     message_end()
  8155.    
  8156.     // Hide the HL crosshair that's drawn
  8157.     message_begin(MSG_ONE, g_msgCrosshair, _, ID_SPAWN)
  8158.     write_byte(0) // toggle
  8159.     message_end()
  8160. }
  8161.  
  8162. // Turn Off Flashlight and Restore Batteries
  8163. turn_off_flashlight(id)
  8164. {
  8165.     // Restore batteries for the next use
  8166.     fm_cs_set_user_batteries(id, 100)
  8167.    
  8168.     // Check if flashlight is on
  8169.     if (pev(id, pev_effects) & EF_DIMLIGHT)
  8170.     {
  8171.         // Turn it off
  8172.         set_pev(id, pev_impulse, IMPULSE_FLASHLIGHT)
  8173.     }
  8174.     else
  8175.     {
  8176.         // Clear any stored flashlight impulse (bugfix)
  8177.         set_pev(id, pev_impulse, 0)
  8178.     }
  8179.    
  8180.     // Turn off custom flashlight
  8181.     if (g_cached_customflash)
  8182.     {
  8183.         // Turn it off
  8184.         g_flashlight[id] = false
  8185.         g_flashbattery[id] = 100
  8186.        
  8187.         // Update flashlight HUD
  8188.         message_begin(MSG_ONE, g_msgFlashlight, _, id)
  8189.         write_byte(0) // toggle
  8190.         write_byte(100) // battery
  8191.         message_end()
  8192.        
  8193.         // Remove previous tasks
  8194.         remove_task(id+TASK_CHARGE)
  8195.         remove_task(id+TASK_FLASH)
  8196.     }
  8197. }
  8198.  
  8199. // Infection Bomb Explosion
  8200. infection_explode(ent)
  8201. {
  8202.     // Round ended (bugfix)
  8203.     if (g_endround) return;
  8204.    
  8205.     // Get origin
  8206.     static Float:originF[3]
  8207.     pev(ent, pev_origin, originF)
  8208.    
  8209.     // Make the explosion
  8210.     create_blast(originF)
  8211.    
  8212.     // Infection nade explode sound
  8213.     static sound[64]
  8214.     ArrayGetString(grenade_infect, random_num(0, ArraySize(grenade_infect) - 1), sound, charsmax(sound))
  8215.     emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8216.    
  8217.     // Get attacker
  8218.     static attacker
  8219.     attacker = pev(ent, pev_owner)
  8220.    
  8221.     // Infection bomb owner disconnected? (bugfix)
  8222.     if (!is_user_valid_connected(attacker))
  8223.     {
  8224.         // Get rid of the grenade
  8225.         engfunc(EngFunc_RemoveEntity, ent)
  8226.         return;
  8227.     }
  8228.    
  8229.     // Collisions
  8230.     static victim
  8231.     victim = -1
  8232.    
  8233.     while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
  8234.     {
  8235.         // Only effect alive non-spawnprotected humans
  8236.         if (!is_user_valid_alive(victim) || g_zombie[victim] || g_nodamage[victim])
  8237.             continue;
  8238.        
  8239.         // Last human is killed
  8240.         if (fnGetHumans() == 1)
  8241.         {
  8242.             ExecuteHamB(Ham_Killed, victim, attacker, 0)
  8243.             continue;
  8244.         }
  8245.        
  8246.         // Infected victim's sound
  8247.         ArrayGetString(grenade_infect_player, random_num(0, ArraySize(grenade_infect_player) - 1), sound, charsmax(sound))
  8248.         emit_sound(victim, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8249.        
  8250.         // Turn into zombie
  8251.         zombieme(victim, attacker, 0, 1, 1)
  8252.     }
  8253.    
  8254.     // Get rid of the grenade
  8255.     engfunc(EngFunc_RemoveEntity, ent)
  8256. }
  8257.  
  8258. // Fire Grenade Explosion
  8259. fire_explode(ent)
  8260. {
  8261.     // Get origin
  8262.     static Float:originF[3]
  8263.     pev(ent, pev_origin, originF)
  8264.    
  8265.     // Make the explosion
  8266.     create_blast2(originF)
  8267.    
  8268.     // Fire nade explode sound
  8269.     static sound[64]
  8270.     ArrayGetString(grenade_fire, random_num(0, ArraySize(grenade_fire) - 1), sound, charsmax(sound))
  8271.     emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8272.    
  8273.     // Collisions
  8274.     static victim
  8275.     victim = -1
  8276.    
  8277.     while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
  8278.     {
  8279.         // Only effect alive zombies
  8280.         if (!is_user_valid_alive(victim) || !g_zombie[victim] || g_nodamage[victim])
  8281.             continue;
  8282.        
  8283.         // Heat icon?
  8284.         if (get_pcvar_num(cvar_hudicons))
  8285.         {
  8286.             message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, victim)
  8287.             write_byte(0) // damage save
  8288.             write_byte(0) // damage take
  8289.             write_long(DMG_BURN) // damage type
  8290.             write_coord(0) // x
  8291.             write_coord(0) // y
  8292.             write_coord(0) // z
  8293.             message_end()
  8294.         }
  8295.        
  8296.         if (g_nemesis[victim]) // fire duration (nemesis is fire resistant)
  8297.             g_burning_duration[victim] += get_pcvar_num(cvar_fireduration)
  8298.         else
  8299.             g_burning_duration[victim] += get_pcvar_num(cvar_fireduration) * 5
  8300.        
  8301.         // Set burning task on victim if not present
  8302.         if (!task_exists(victim+TASK_BURN))
  8303.             set_task(0.2, "burning_flame", victim+TASK_BURN, _, _, "b")
  8304.     }
  8305.    
  8306.     // Get rid of the grenade
  8307.     engfunc(EngFunc_RemoveEntity, ent)
  8308. }
  8309.  
  8310. // Frost Grenade Explosion
  8311. frost_explode(ent)
  8312. {
  8313.     // Get origin
  8314.     static Float:originF[3]
  8315.     pev(ent, pev_origin, originF)
  8316.    
  8317.     // Make the explosion
  8318.     create_blast3(originF)
  8319.    
  8320.     // Frost nade explode sound
  8321.     static sound[64]
  8322.     ArrayGetString(grenade_frost, random_num(0, ArraySize(grenade_frost) - 1), sound, charsmax(sound))
  8323.     emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8324.    
  8325.     // Collisions
  8326.     static victim
  8327.     victim = -1
  8328.    
  8329.     while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
  8330.     {
  8331.         // Only effect alive unfrozen zombies
  8332.         if (!is_user_valid_alive(victim) || !g_zombie[victim] || g_frozen[victim] || g_nodamage[victim])
  8333.             continue;
  8334.        
  8335.         // Nemesis shouldn't be frozen
  8336.         if (g_nemesis[victim])
  8337.         {
  8338.             // Get player's origin
  8339.             static origin2[3]
  8340.             get_user_origin(victim, origin2)
  8341.            
  8342.             // Broken glass sound
  8343.             ArrayGetString(grenade_frost_break, random_num(0, ArraySize(grenade_frost_break) - 1), sound, charsmax(sound))
  8344.             emit_sound(victim, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8345.            
  8346.             // Glass shatter
  8347.             message_begin(MSG_PVS, SVC_TEMPENTITY, origin2)
  8348.             write_byte(TE_BREAKMODEL) // TE id
  8349.             write_coord(origin2[0]) // x
  8350.             write_coord(origin2[1]) // y
  8351.             write_coord(origin2[2]+24) // z
  8352.             write_coord(16) // size x
  8353.             write_coord(16) // size y
  8354.             write_coord(16) // size z
  8355.             write_coord(random_num(-50, 50)) // velocity x
  8356.             write_coord(random_num(-50, 50)) // velocity y
  8357.             write_coord(25) // velocity z
  8358.             write_byte(10) // random velocity
  8359.             write_short(g_glassSpr) // model
  8360.             write_byte(10) // count
  8361.             write_byte(25) // life
  8362.             write_byte(BREAK_GLASS) // flags
  8363.             message_end()
  8364.            
  8365.             continue;
  8366.         }
  8367.        
  8368.         // Freeze icon?
  8369.         if (get_pcvar_num(cvar_hudicons))
  8370.         {
  8371.             message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, victim)
  8372.             write_byte(0) // damage save
  8373.             write_byte(0) // damage take
  8374.             write_long(DMG_DROWN) // damage type - DMG_FREEZE
  8375.             write_coord(0) // x
  8376.             write_coord(0) // y
  8377.             write_coord(0) // z
  8378.             message_end()
  8379.         }
  8380.        
  8381.         // Light blue glow while frozen
  8382.         if (g_handle_models_on_separate_ent)
  8383.             fm_set_rendering(g_ent_playermodel[victim], kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)
  8384.         else
  8385.             fm_set_rendering(victim, kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)
  8386.        
  8387.         // Freeze sound
  8388.         ArrayGetString(grenade_frost_player, random_num(0, ArraySize(grenade_frost_player) - 1), sound, charsmax(sound))
  8389.         emit_sound(victim, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8390.        
  8391.         // Add a blue tint to their screen
  8392.         message_begin(MSG_ONE, g_msgScreenFade, _, victim)
  8393.         write_short(0) // duration
  8394.         write_short(0) // hold time
  8395.         write_short(FFADE_STAYOUT) // fade type
  8396.         write_byte(0) // red
  8397.         write_byte(50) // green
  8398.         write_byte(200) // blue
  8399.         write_byte(100) // alpha
  8400.         message_end()
  8401.        
  8402.         // Set the frozen flag
  8403.         g_frozen[victim] = true
  8404.        
  8405.         // Save player's old gravity (bugfix)
  8406.         pev(victim, pev_gravity, g_frozen_gravity[victim])
  8407.        
  8408.         // Prevent from jumping
  8409.         if (pev(victim, pev_flags) & FL_ONGROUND)
  8410.             set_pev(victim, pev_gravity, 999999.9) // set really high
  8411.         else
  8412.             set_pev(victim, pev_gravity, 0.000001) // no gravity
  8413.        
  8414.         // Prevent from moving
  8415.         ExecuteHamB(Ham_Player_ResetMaxSpeed, victim)
  8416.        
  8417.         // Set a task to remove the freeze
  8418.         set_task(get_pcvar_float(cvar_freezeduration), "remove_freeze", victim)
  8419.     }
  8420.    
  8421.     // Get rid of the grenade
  8422.     engfunc(EngFunc_RemoveEntity, ent)
  8423. }
  8424.  
  8425. // Remove freeze task
  8426. public remove_freeze(id)
  8427. {
  8428.     // Not alive or not frozen anymore
  8429.     if (!g_isalive[id] || !g_frozen[id])
  8430.         return;
  8431.    
  8432.     // Unfreeze
  8433.     g_frozen[id] = false;
  8434.    
  8435.     // Restore gravity and maxspeed (bugfix)
  8436.     set_pev(id, pev_gravity, g_frozen_gravity[id])
  8437.     ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  8438.    
  8439.     // Restore rendering
  8440.     if (g_handle_models_on_separate_ent)
  8441.     {
  8442.         // Nemesis or Survivor glow / remove glow on player model entity
  8443.         if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  8444.             fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  8445.         else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  8446.             fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  8447.         else
  8448.             fm_set_rendering(g_ent_playermodel[id])
  8449.     }
  8450.     else
  8451.     {
  8452.         // Nemesis or Survivor glow / remove glow
  8453.         if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  8454.             fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  8455.         else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  8456.             fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  8457.         else
  8458.             fm_set_rendering(id)
  8459.     }
  8460.    
  8461.     // Gradually remove screen's blue tint
  8462.     message_begin(MSG_ONE, g_msgScreenFade, _, id)
  8463.     write_short(UNIT_SECOND) // duration
  8464.     write_short(0) // hold time
  8465.     write_short(FFADE_IN) // fade type
  8466.     write_byte(0) // red
  8467.     write_byte(50) // green
  8468.     write_byte(200) // blue
  8469.     write_byte(100) // alpha
  8470.     message_end()
  8471.    
  8472.     // Broken glass sound
  8473.     static sound[64]
  8474.     ArrayGetString(grenade_frost_break, random_num(0, ArraySize(grenade_frost_break) - 1), sound, charsmax(sound))
  8475.     emit_sound(id, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8476.    
  8477.     // Get player's origin
  8478.     static origin2[3]
  8479.     get_user_origin(id, origin2)
  8480.    
  8481.     // Glass shatter
  8482.     message_begin(MSG_PVS, SVC_TEMPENTITY, origin2)
  8483.     write_byte(TE_BREAKMODEL) // TE id
  8484.     write_coord(origin2[0]) // x
  8485.     write_coord(origin2[1]) // y
  8486.     write_coord(origin2[2]+24) // z
  8487.     write_coord(16) // size x
  8488.     write_coord(16) // size y
  8489.     write_coord(16) // size z
  8490.     write_coord(random_num(-50, 50)) // velocity x
  8491.     write_coord(random_num(-50, 50)) // velocity y
  8492.     write_coord(25) // velocity z
  8493.     write_byte(10) // random velocity
  8494.     write_short(g_glassSpr) // model
  8495.     write_byte(10) // count
  8496.     write_byte(25) // life
  8497.     write_byte(BREAK_GLASS) // flags
  8498.     message_end()
  8499.    
  8500.     ExecuteForward(g_fwUserUnfrozen, g_fwDummyResult, id);
  8501. }
  8502.  
  8503. // Remove Stuff Task
  8504. public remove_stuff()
  8505. {
  8506.     static ent
  8507.    
  8508.     // Remove rotating doors
  8509.     if (get_pcvar_num(cvar_removedoors) > 0)
  8510.     {
  8511.         ent = -1;
  8512.         while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "func_door_rotating")) != 0)
  8513.             engfunc(EngFunc_SetOrigin, ent, Float:{8192.0 ,8192.0 ,8192.0})
  8514.     }
  8515.    
  8516.     // Remove all doors
  8517.     if (get_pcvar_num(cvar_removedoors) > 1)
  8518.     {
  8519.         ent = -1;
  8520.         while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "func_door")) != 0)
  8521.             engfunc(EngFunc_SetOrigin, ent, Float:{8192.0 ,8192.0 ,8192.0})
  8522.     }
  8523.    
  8524.     // Triggered lights
  8525.     if (!get_pcvar_num(cvar_triggered))
  8526.     {
  8527.         ent = -1
  8528.         while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "light")) != 0)
  8529.         {
  8530.             dllfunc(DLLFunc_Use, ent, 0); // turn off the light
  8531.             set_pev(ent, pev_targetname, 0) // prevent it from being triggered
  8532.         }
  8533.     }
  8534. }
  8535.  
  8536. // Set Custom Weapon Models
  8537. replace_weapon_models(id, weaponid)
  8538. {
  8539.     switch (weaponid)
  8540.     {
  8541.         case CSW_KNIFE: // Custom knife models
  8542.         {
  8543.             if (g_zombie[id])
  8544.             {
  8545.                 if (g_nemesis[id]) // Nemesis
  8546.                 {
  8547.                     set_pev(id, pev_viewmodel2, model_vknife_nemesis)
  8548.                     set_pev(id, pev_weaponmodel2, "")
  8549.                 }
  8550.                 else // Zombies
  8551.                 {
  8552.                     // Admin knife models?
  8553.                     if (get_pcvar_num(cvar_adminknifemodelszombie) && get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS])
  8554.                     {
  8555.                         set_pev(id, pev_viewmodel2, model_vknife_admin_zombie)
  8556.                         set_pev(id, pev_weaponmodel2, "")
  8557.                     }
  8558.                     else
  8559.                     {
  8560.                         static clawmodel[100]
  8561.                         ArrayGetString(g_zclass_clawmodel, g_zombieclass[id], clawmodel, charsmax(clawmodel))
  8562.                         format(clawmodel, charsmax(clawmodel), "models/zombie_plague/%s", clawmodel)
  8563.                         set_pev(id, pev_viewmodel2, clawmodel)
  8564.                         set_pev(id, pev_weaponmodel2, "")
  8565.                     }
  8566.                 }
  8567.             }
  8568.             else // Humans
  8569.             {
  8570.                 // Admin knife models?
  8571.                 if (get_pcvar_num(cvar_adminknifemodelshuman) && get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS])
  8572.                 {
  8573.                     set_pev(id, pev_viewmodel2, model_vknife_admin_human)
  8574.                     set_pev(id, pev_weaponmodel2, "models/p_knife.mdl")
  8575.                 }
  8576.                 else
  8577.                 {
  8578.                     set_pev(id, pev_viewmodel2, model_vknife_human)
  8579.                     set_pev(id, pev_weaponmodel2, "models/p_knife.mdl")
  8580.                 }
  8581.             }
  8582.         }
  8583.         case CSW_HEGRENADE: // Infection bomb or fire grenade
  8584.         {
  8585.             if (g_zombie[id])
  8586.                 set_pev(id, pev_viewmodel2, model_grenade_infect)
  8587.             else
  8588.                 set_pev(id, pev_viewmodel2, model_grenade_fire)
  8589.         }
  8590.         case CSW_FLASHBANG: // Frost grenade
  8591.         {
  8592.             set_pev(id, pev_viewmodel2, model_grenade_frost)
  8593.         }
  8594.         case CSW_SMOKEGRENADE: // Flare grenade
  8595.         {
  8596.             set_pev(id, pev_viewmodel2, model_grenade_flare)
  8597.         }
  8598.     }
  8599.    
  8600.     // Survivor's custom weapon model
  8601.     static survweaponname[32]
  8602.     get_pcvar_string(cvar_survweapon, survweaponname, charsmax(survweaponname))
  8603.     if (g_survivor[id] && weaponid == cs_weapon_name_to_id(survweaponname))
  8604.         set_pev(id, pev_viewmodel2, model_vweapon_survivor)
  8605.    
  8606.     // Update model on weaponmodel ent
  8607.     if (g_handle_models_on_separate_ent) fm_set_weaponmodel_ent(id)
  8608. }
  8609.  
  8610. // Reset Player Vars
  8611. reset_vars(id, resetall)
  8612. {
  8613.     g_zombie[id] = false
  8614.     g_nemesis[id] = false
  8615.     g_survivor[id] = false
  8616.     g_firstzombie[id] = false
  8617.     g_lastzombie[id] = false
  8618.     g_lasthuman[id] = false
  8619.     g_frozen[id] = false
  8620.     g_nodamage[id] = false
  8621.     g_respawn_as_zombie[id] = false
  8622.     g_nvision[id] = false
  8623.     g_nvisionenabled[id] = false
  8624.     g_flashlight[id] = false
  8625.     g_flashbattery[id] = 100
  8626.     g_canbuy[id] = true
  8627.     g_burning_duration[id] = 0
  8628.    
  8629.     if (resetall)
  8630.     {
  8631.         g_ammopacks[id] = get_pcvar_num(cvar_startammopacks)
  8632.         g_zombieclass[id] = ZCLASS_NONE
  8633.         g_zombieclassnext[id] = ZCLASS_NONE
  8634.         g_damagedealt_human[id] = 0
  8635.         g_damagedealt_zombie[id] = 0
  8636.         WPN_AUTO_ON = 0
  8637.         WPN_STARTID = 0
  8638.         PL_ACTION = 0
  8639.         MENU_PAGE_ZCLASS = 0
  8640.         MENU_PAGE_EXTRAS = 0
  8641.         MENU_PAGE_PLAYERS = 0
  8642.     }
  8643. }
  8644.  
  8645. // Set spectators nightvision
  8646. public spec_nvision(id)
  8647. {
  8648.     // Not connected, alive, or bot
  8649.     if (!g_isconnected[id] || g_isalive[id] || g_isbot[id])
  8650.         return;
  8651.    
  8652.     // Give Night Vision?
  8653.     if (get_pcvar_num(cvar_nvggive))
  8654.     {
  8655.         g_nvision[id] = true
  8656.        
  8657.         // Turn on Night Vision automatically?
  8658.         if (get_pcvar_num(cvar_nvggive) == 1)
  8659.         {
  8660.             g_nvisionenabled[id] = true
  8661.            
  8662.             // Custom nvg?
  8663.             if (get_pcvar_num(cvar_customnvg))
  8664.             {
  8665.                 remove_task(id+TASK_NVISION)
  8666.                 set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  8667.             }
  8668.             else
  8669.                 set_user_gnvision(id, 1)
  8670.         }
  8671.     }
  8672. }
  8673.  
  8674. // Show HUD Task
  8675. public ShowHUD(taskid)
  8676. {
  8677.     static id
  8678.     id = ID_SHOWHUD;
  8679.    
  8680.     // Player died?
  8681.     if (!g_isalive[id])
  8682.     {
  8683.         // Get spectating target
  8684.         id = pev(id, PEV_SPEC_TARGET)
  8685.        
  8686.         // Target not alive
  8687.         if (!g_isalive[id]) return;
  8688.     }
  8689.    
  8690.     // Format classname
  8691.     static class[32], red, green, blue
  8692.    
  8693.     if (g_zombie[id]) // zombies
  8694.     {
  8695.         red = 200
  8696.         green = 250
  8697.         blue = 0
  8698.        
  8699.         if (g_nemesis[id])
  8700.             formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_NEMESIS")
  8701.         else
  8702.             copy(class, charsmax(class), g_zombie_classname[id])
  8703.     }
  8704.     else // humans
  8705.     {
  8706.         red = 0
  8707.         green = 0
  8708.         blue = 255
  8709.        
  8710.         if (g_survivor[id])
  8711.             formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_SURVIVOR")
  8712.         else
  8713.             formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_HUMAN")
  8714.     }
  8715.    
  8716.     // Spectating someone else?
  8717.     if (id != ID_SHOWHUD)
  8718.     {
  8719.         // Show name, health, class, and ammo packs
  8720.         set_hudmessage(255, 255, 255, HUD_SPECT_X, HUD_SPECT_Y, 0, 6.0, 1.1, 0.0, 0.0, -1)
  8721.         ShowSyncHudMsg(ID_SHOWHUD, g_MsgSync2, "%L %s^nHP: %d - %L %s - %L %d", ID_SHOWHUD, "SPECTATING", g_playername[id], pev(id, pev_health), ID_SHOWHUD, "CLASS_CLASS", class, ID_SHOWHUD, "AMMO_PACKS1", g_ammopacks[id])
  8722.     }
  8723.     else
  8724.     {
  8725.         // Show health, class and ammo packs
  8726.         set_hudmessage(red, green, blue, HUD_STATS_X, HUD_STATS_Y, 0, 6.0, 1.1, 0.0, 0.0, -1)
  8727.         ShowSyncHudMsg(ID_SHOWHUD, g_MsgSync2, "%L: %d - %L %s - %L %d", id, "ZOMBIE_ATTRIB1", pev(ID_SHOWHUD, pev_health), ID_SHOWHUD, "CLASS_CLASS", class, ID_SHOWHUD, "AMMO_PACKS1", g_ammopacks[ID_SHOWHUD])
  8728.     }
  8729. }
  8730.  
  8731. // Play idle zombie sounds
  8732. public zombie_play_idle(taskid)
  8733. {
  8734.     // Round ended/new one starting
  8735.     if (g_endround || g_newround)
  8736.         return;
  8737.    
  8738.     static sound[64]
  8739.    
  8740.     // Last zombie?
  8741.     if (g_lastzombie[ID_BLOOD])
  8742.     {
  8743.         ArrayGetString(zombie_idle_last, random_num(0, ArraySize(zombie_idle_last) - 1), sound, charsmax(sound))
  8744.         emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8745.     }
  8746.     else
  8747.     {
  8748.         ArrayGetString(zombie_idle, random_num(0, ArraySize(zombie_idle) - 1), sound, charsmax(sound))
  8749.         emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8750.     }
  8751. }
  8752.  
  8753. // Madness Over Task
  8754. public madness_over(taskid)
  8755. {
  8756.     g_nodamage[ID_BLOOD] = false
  8757. }
  8758.  
  8759. // Place user at a random spawn
  8760. do_random_spawn(id, regularspawns = 0)
  8761. {
  8762.     static hull, sp_index, i
  8763.    
  8764.     // Get whether the player is crouching
  8765.     hull = (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN
  8766.    
  8767.     // Use regular spawns?
  8768.     if (!regularspawns)
  8769.     {
  8770.         // No spawns?
  8771.         if (!g_spawnCount)
  8772.             return;
  8773.        
  8774.         // Choose random spawn to start looping at
  8775.         sp_index = random_num(0, g_spawnCount - 1)
  8776.        
  8777.         // Try to find a clear spawn
  8778.         for (i = sp_index + 1; /*no condition*/; i++)
  8779.         {
  8780.             // Start over when we reach the end
  8781.             if (i >= g_spawnCount) i = 0
  8782.            
  8783.             // Free spawn space?
  8784.             if (is_hull_vacant(g_spawns[i], hull))
  8785.             {
  8786.                 // Engfunc_SetOrigin is used so ent's mins and maxs get updated instantly
  8787.                 engfunc(EngFunc_SetOrigin, id, g_spawns[i])
  8788.                 break;
  8789.             }
  8790.            
  8791.             // Loop completed, no free space found
  8792.             if (i == sp_index) break;
  8793.         }
  8794.     }
  8795.     else
  8796.     {
  8797.         // No spawns?
  8798.         if (!g_spawnCount2)
  8799.             return;
  8800.        
  8801.         // Choose random spawn to start looping at
  8802.         sp_index = random_num(0, g_spawnCount2 - 1)
  8803.        
  8804.         // Try to find a clear spawn
  8805.         for (i = sp_index + 1; /*no condition*/; i++)
  8806.         {
  8807.             // Start over when we reach the end
  8808.             if (i >= g_spawnCount2) i = 0
  8809.            
  8810.             // Free spawn space?
  8811.             if (is_hull_vacant(g_spawns2[i], hull))
  8812.             {
  8813.                 // Engfunc_SetOrigin is used so ent's mins and maxs get updated instantly
  8814.                 engfunc(EngFunc_SetOrigin, id, g_spawns2[i])
  8815.                 break;
  8816.             }
  8817.            
  8818.             // Loop completed, no free space found
  8819.             if (i == sp_index) break;
  8820.         }
  8821.     }
  8822. }
  8823.  
  8824. // Get Zombies -returns alive zombies number-
  8825. fnGetZombies()
  8826. {
  8827.     static iZombies, id
  8828.     iZombies = 0
  8829.    
  8830.     for (id = 1; id <= g_maxplayers; id++)
  8831.     {
  8832.         if (g_isalive[id] && g_zombie[id])
  8833.             iZombies++
  8834.     }
  8835.    
  8836.     return iZombies;
  8837. }
  8838.  
  8839. // Get Humans -returns alive humans number-
  8840. fnGetHumans()
  8841. {
  8842.     static iHumans, id
  8843.     iHumans = 0
  8844.    
  8845.     for (id = 1; id <= g_maxplayers; id++)
  8846.     {
  8847.         if (g_isalive[id] && !g_zombie[id])
  8848.             iHumans++
  8849.     }
  8850.    
  8851.     return iHumans;
  8852. }
  8853.  
  8854. // Get Nemesis -returns alive nemesis number-
  8855. fnGetNemesis()
  8856. {
  8857.     static iNemesis, id
  8858.     iNemesis = 0
  8859.    
  8860.     for (id = 1; id <= g_maxplayers; id++)
  8861.     {
  8862.         if (g_isalive[id] && g_nemesis[id])
  8863.             iNemesis++
  8864.     }
  8865.    
  8866.     return iNemesis;
  8867. }
  8868.  
  8869. // Get Survivors -returns alive survivors number-
  8870. fnGetSurvivors()
  8871. {
  8872.     static iSurvivors, id
  8873.     iSurvivors = 0
  8874.    
  8875.     for (id = 1; id <= g_maxplayers; id++)
  8876.     {
  8877.         if (g_isalive[id] && g_survivor[id])
  8878.             iSurvivors++
  8879.     }
  8880.    
  8881.     return iSurvivors;
  8882. }
  8883.  
  8884. // Get Alive -returns alive players number-
  8885. fnGetAlive()
  8886. {
  8887.     static iAlive, id
  8888.     iAlive = 0
  8889.    
  8890.     for (id = 1; id <= g_maxplayers; id++)
  8891.     {
  8892.         if (g_isalive[id])
  8893.             iAlive++
  8894.     }
  8895.    
  8896.     return iAlive;
  8897. }
  8898.  
  8899. // Get Random Alive -returns index of alive player number n -
  8900. fnGetRandomAlive(n)
  8901. {
  8902.     static iAlive, id
  8903.     iAlive = 0
  8904.    
  8905.     for (id = 1; id <= g_maxplayers; id++)
  8906.     {
  8907.         if (g_isalive[id])
  8908.             iAlive++
  8909.        
  8910.         if (iAlive == n)
  8911.             return id;
  8912.     }
  8913.    
  8914.     return -1;
  8915. }
  8916.  
  8917. // Get Playing -returns number of users playing-
  8918. fnGetPlaying()
  8919. {
  8920.     static iPlaying, id, team
  8921.     iPlaying = 0
  8922.    
  8923.     for (id = 1; id <= g_maxplayers; id++)
  8924.     {
  8925.         if (g_isconnected[id])
  8926.         {
  8927.             team = fm_cs_get_user_team(id)
  8928.            
  8929.             if (team != FM_CS_TEAM_SPECTATOR && team != FM_CS_TEAM_UNASSIGNED)
  8930.                 iPlaying++
  8931.         }
  8932.     }
  8933.    
  8934.     return iPlaying;
  8935. }
  8936.  
  8937. // Get CTs -returns number of CTs connected-
  8938. fnGetCTs()
  8939. {
  8940.     static iCTs, id
  8941.     iCTs = 0
  8942.    
  8943.     for (id = 1; id <= g_maxplayers; id++)
  8944.     {
  8945.         if (g_isconnected[id])
  8946.         {          
  8947.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_CT)
  8948.                 iCTs++
  8949.         }
  8950.     }
  8951.    
  8952.     return iCTs;
  8953. }
  8954.  
  8955. // Get Ts -returns number of Ts connected-
  8956. fnGetTs()
  8957. {
  8958.     static iTs, id
  8959.     iTs = 0
  8960.    
  8961.     for (id = 1; id <= g_maxplayers; id++)
  8962.     {
  8963.         if (g_isconnected[id])
  8964.         {          
  8965.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_T)
  8966.                 iTs++
  8967.         }
  8968.     }
  8969.    
  8970.     return iTs;
  8971. }
  8972.  
  8973. // Get Alive CTs -returns number of CTs alive-
  8974. fnGetAliveCTs()
  8975. {
  8976.     static iCTs, id
  8977.     iCTs = 0
  8978.    
  8979.     for (id = 1; id <= g_maxplayers; id++)
  8980.     {
  8981.         if (g_isalive[id])
  8982.         {          
  8983.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_CT)
  8984.                 iCTs++
  8985.         }
  8986.     }
  8987.    
  8988.     return iCTs;
  8989. }
  8990.  
  8991. // Get Alive Ts -returns number of Ts alive-
  8992. fnGetAliveTs()
  8993. {
  8994.     static iTs, id
  8995.     iTs = 0
  8996.    
  8997.     for (id = 1; id <= g_maxplayers; id++)
  8998.     {
  8999.         if (g_isalive[id])
  9000.         {          
  9001.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_T)
  9002.                 iTs++
  9003.         }
  9004.     }
  9005.    
  9006.     return iTs;
  9007. }
  9008.  
  9009. // Last Zombie Check -check for last zombie and set its flag-
  9010. fnCheckLastZombie()
  9011. {
  9012.     static id
  9013.     for (id = 1; id <= g_maxplayers; id++)
  9014.     {
  9015.         // Last zombie
  9016.         if (g_isalive[id] && g_zombie[id] && !g_nemesis[id] && fnGetZombies() == 1)
  9017.         {
  9018.             if (!g_lastzombie[id])
  9019.             {
  9020.                 // Last zombie forward
  9021.                 ExecuteForward(g_fwUserLastZombie, g_fwDummyResult, id);
  9022.             }
  9023.             g_lastzombie[id] = true
  9024.         }
  9025.         else
  9026.             g_lastzombie[id] = false
  9027.        
  9028.         // Last human
  9029.         if (g_isalive[id] && !g_zombie[id] && !g_survivor[id] && fnGetHumans() == 1)
  9030.         {
  9031.             if (!g_lasthuman[id])
  9032.             {
  9033.                 // Last human forward
  9034.                 ExecuteForward(g_fwUserLastHuman, g_fwDummyResult, id);
  9035.                
  9036.                 // Reward extra hp
  9037.                 fm_set_user_health(id, pev(id, pev_health) + get_pcvar_num(cvar_humanlasthp))
  9038.             }
  9039.             g_lasthuman[id] = true
  9040.         }
  9041.         else
  9042.             g_lasthuman[id] = false
  9043.     }
  9044. }
  9045.  
  9046. // Save player's stats to database
  9047. save_stats(id)
  9048. {
  9049.     // Check whether there is another record already in that slot
  9050.     if (db_name[id][0] && !equal(g_playername[id], db_name[id]))
  9051.     {
  9052.         // If DB size is exceeded, write over old records
  9053.         if (db_slot_i >= sizeof db_name)
  9054.             db_slot_i = g_maxplayers+1
  9055.        
  9056.         // Move previous record onto an additional save slot
  9057.         copy(db_name[db_slot_i], charsmax(db_name[]), db_name[id])
  9058.         db_ammopacks[db_slot_i] = db_ammopacks[id]
  9059.         db_zombieclass[db_slot_i] = db_zombieclass[id]
  9060.         db_slot_i++
  9061.     }
  9062.    
  9063.     // Now save the current player stats
  9064.     copy(db_name[id], charsmax(db_name[]), g_playername[id]) // name
  9065.     db_ammopacks[id] = g_ammopacks[id]  // ammo packs
  9066.     db_zombieclass[id] = g_zombieclassnext[id] // zombie class
  9067. }
  9068.  
  9069. // Load player's stats from database (if a record is found)
  9070. load_stats(id)
  9071. {
  9072.     // Look for a matching record
  9073.     static i
  9074.     for (i = 0; i < sizeof db_name; i++)
  9075.     {
  9076.         if (equal(g_playername[id], db_name[i]))
  9077.         {
  9078.             // Bingo!
  9079.             g_ammopacks[id] = db_ammopacks[i]
  9080.             g_zombieclass[id] = db_zombieclass[i]
  9081.             g_zombieclassnext[id] = db_zombieclass[i]
  9082.             return;
  9083.         }
  9084.     }
  9085. }
  9086.  
  9087. // Checks if a player is allowed to be zombie
  9088. allowed_zombie(id)
  9089. {
  9090.     if ((g_zombie[id] && !g_nemesis[id]) || g_endround || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && !g_zombie[id] && fnGetHumans() == 1))
  9091.         return false;
  9092.    
  9093.     return true;
  9094. }
  9095.  
  9096. // Checks if a player is allowed to be human
  9097. allowed_human(id)
  9098. {
  9099.     if ((!g_zombie[id] && !g_survivor[id]) || g_endround || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && g_zombie[id] && fnGetZombies() == 1))
  9100.         return false;
  9101.    
  9102.     return true;
  9103. }
  9104.  
  9105. // Checks if a player is allowed to be survivor
  9106. allowed_survivor(id)
  9107. {
  9108.     if (g_endround || g_survivor[id] || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && g_zombie[id] && fnGetZombies() == 1))
  9109.         return false;
  9110.    
  9111.     return true;
  9112. }
  9113.  
  9114. // Checks if a player is allowed to be nemesis
  9115. allowed_nemesis(id)
  9116. {
  9117.     if (g_endround || g_nemesis[id] || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && !g_zombie[id] && fnGetHumans() == 1))
  9118.         return false;
  9119.    
  9120.     return true;
  9121. }
  9122.  
  9123. // Checks if a player is allowed to respawn
  9124. allowed_respawn(id)
  9125. {
  9126.     static team
  9127.     team = fm_cs_get_user_team(id)
  9128.    
  9129.     if (g_endround || team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED || g_isalive[id])
  9130.         return false;
  9131.    
  9132.     return true;
  9133. }
  9134.  
  9135. // Checks if swarm mode is allowed
  9136. allowed_swarm()
  9137. {
  9138.     if (g_endround || !g_newround || task_exists(TASK_WELCOMEMSG))
  9139.         return false;
  9140.    
  9141.     return true;
  9142. }
  9143.  
  9144. // Checks if multi infection mode is allowed
  9145. allowed_multi()
  9146. {
  9147.     if (g_endround || !g_newround || task_exists(TASK_WELCOMEMSG) || floatround(fnGetAlive()*get_pcvar_float(cvar_multiratio), floatround_ceil) < 2 || floatround(fnGetAlive()*get_pcvar_float(cvar_multiratio), floatround_ceil) >= fnGetAlive())
  9148.         return false;
  9149.    
  9150.     return true;
  9151. }
  9152.  
  9153. // Checks if plague mode is allowed
  9154. allowed_plague()
  9155. {
  9156.     if (g_endround || !g_newround || task_exists(TASK_WELCOMEMSG) || floatround((fnGetAlive()-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil) < 1
  9157.     || fnGetAlive()-(get_pcvar_num(cvar_plaguesurvnum)+get_pcvar_num(cvar_plaguenemnum)+floatround((fnGetAlive()-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)) < 1)
  9158.         return false;
  9159.    
  9160.     return true;
  9161. }
  9162.  
  9163. // Admin Command. zp_zombie
  9164. command_zombie(id, player)
  9165. {
  9166.     // Show activity?
  9167.     switch (get_pcvar_num(cvar_showactivity))
  9168.     {
  9169.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_INFECT")
  9170.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_INFECT")
  9171.     }
  9172.    
  9173.     // Log to Zombie Plague log file?
  9174.     if (get_pcvar_num(cvar_logcommands))
  9175.     {
  9176.         static logdata[100], authid[32], ip[16]
  9177.         get_user_authid(id, authid, charsmax(authid))
  9178.         get_user_ip(id, ip, charsmax(ip), 1)
  9179.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER, "CMD_INFECT", fnGetPlaying(), g_maxplayers)
  9180.         log_to_file("zombieplague.log", logdata)
  9181.     }
  9182.    
  9183.     // New round?
  9184.     if (g_newround)
  9185.     {
  9186.         // Set as first zombie
  9187.         remove_task(TASK_MAKEZOMBIE)
  9188.         make_a_zombie(MODE_INFECTION, player)
  9189.     }
  9190.     else
  9191.     {
  9192.         // Just infect
  9193.         zombieme(player, 0, 0, 0, 0)
  9194.     }
  9195. }
  9196.  
  9197. // Admin Command. zp_human
  9198. command_human(id, player)
  9199. {
  9200.     // Show activity?
  9201.     switch (get_pcvar_num(cvar_showactivity))
  9202.     {
  9203.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_DISINFECT")
  9204.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_DISINFECT")
  9205.     }
  9206.    
  9207.     // Log to Zombie Plague log file?
  9208.     if (get_pcvar_num(cvar_logcommands))
  9209.     {
  9210.         static logdata[100], authid[32], ip[16]
  9211.         get_user_authid(id, authid, charsmax(authid))
  9212.         get_user_ip(id, ip, charsmax(ip), 1)
  9213.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER,"CMD_DISINFECT", fnGetPlaying(), g_maxplayers)
  9214.         log_to_file("zombieplague.log", logdata)
  9215.     }
  9216.    
  9217.     // Turn to human
  9218.     humanme(player, 0, 0)
  9219. }
  9220.  
  9221. // Admin Command. zp_survivor
  9222. command_survivor(id, player)
  9223. {
  9224.     // Show activity?
  9225.     switch (get_pcvar_num(cvar_showactivity))
  9226.     {
  9227.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_SURVIVAL")
  9228.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_SURVIVAL")
  9229.     }
  9230.    
  9231.      // Log to Zombie Plague log file?
  9232.     if (get_pcvar_num(cvar_logcommands))
  9233.     {
  9234.         static logdata[100], authid[32], ip[16]
  9235.         get_user_authid(id, authid, charsmax(authid))
  9236.         get_user_ip(id, ip, charsmax(ip), 1)
  9237.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER,"CMD_SURVIVAL", fnGetPlaying(), g_maxplayers)
  9238.         log_to_file("zombieplague.log", logdata)
  9239.     }
  9240.    
  9241.     // New round?
  9242.     if (g_newround)
  9243.     {
  9244.         // Set as first survivor
  9245.         remove_task(TASK_MAKEZOMBIE)
  9246.         make_a_zombie(MODE_SURVIVOR, player)
  9247.     }
  9248.     else
  9249.     {
  9250.         // Turn player into a Survivor
  9251.         humanme(player, 1, 0)
  9252.     }
  9253. }
  9254.  
  9255. // Admin Command. zp_nemesis
  9256. command_nemesis(id, player)
  9257. {
  9258.     // Show activity?
  9259.     switch (get_pcvar_num(cvar_showactivity))
  9260.     {
  9261.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_NEMESIS")
  9262.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_NEMESIS")
  9263.     }
  9264.    
  9265.     // Log to Zombie Plague log file?
  9266.     if (get_pcvar_num(cvar_logcommands))
  9267.     {
  9268.         static logdata[100], authid[32], ip[16]
  9269.         get_user_authid(id, authid, charsmax(authid))
  9270.         get_user_ip(id, ip, charsmax(ip), 1)
  9271.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER,"CMD_NEMESIS", fnGetPlaying(), g_maxplayers)
  9272.         log_to_file("zombieplague.log", logdata)
  9273.     }
  9274.    
  9275.     // New round?
  9276.     if (g_newround)
  9277.     {
  9278.         // Set as first nemesis
  9279.         remove_task(TASK_MAKEZOMBIE)
  9280.         make_a_zombie(MODE_NEMESIS, player)
  9281.     }
  9282.     else
  9283.     {
  9284.         // Turn player into a Nemesis
  9285.         zombieme(player, 0, 1, 0, 0)
  9286.     }
  9287. }
  9288.  
  9289. // Admin Command. zp_respawn
  9290. command_respawn(id, player)
  9291. {
  9292.     // Show activity?
  9293.     switch (get_pcvar_num(cvar_showactivity))
  9294.     {
  9295.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_RESPAWN")
  9296.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_RESPAWN")
  9297.     }
  9298.    
  9299.     // Log to Zombie Plague log file?
  9300.     if (get_pcvar_num(cvar_logcommands))
  9301.     {
  9302.         static logdata[100], authid[32], ip[16]
  9303.         get_user_authid(id, authid, charsmax(authid))
  9304.         get_user_ip(id, ip, charsmax(ip), 1)
  9305.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER, "CMD_RESPAWN", fnGetPlaying(), g_maxplayers)
  9306.         log_to_file("zombieplague.log", logdata)
  9307.     }
  9308.    
  9309.     // Respawn as zombie?
  9310.     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))
  9311.         g_respawn_as_zombie[player] = true
  9312.    
  9313.     // Override respawn as zombie setting on nemesis and survivor rounds
  9314.     if (g_survround) g_respawn_as_zombie[player] = true
  9315.     else if (g_nemround) g_respawn_as_zombie[player] = false
  9316.    
  9317.     respawn_player_manually(player);
  9318. }
  9319.  
  9320. // Admin Command. zp_swarm
  9321. command_swarm(id)
  9322. {
  9323.     // Show activity?
  9324.     switch (get_pcvar_num(cvar_showactivity))
  9325.     {
  9326.         case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_SWARM")
  9327.         case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_SWARM")
  9328.     }
  9329.    
  9330.     // Log to Zombie Plague log file?
  9331.     if (get_pcvar_num(cvar_logcommands))
  9332.     {
  9333.         static logdata[100], authid[32], ip[16]
  9334.         get_user_authid(id, authid, charsmax(authid))
  9335.         get_user_ip(id, ip, charsmax(ip), 1)
  9336.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER, "CMD_SWARM", fnGetPlaying(), g_maxplayers)
  9337.         log_to_file("zombieplague.log", logdata)
  9338.     }
  9339.    
  9340.     // Call Swarm Mode
  9341.     remove_task(TASK_MAKEZOMBIE)
  9342.     make_a_zombie(MODE_SWARM, 0)
  9343. }
  9344.  
  9345. // Admin Command. zp_multi
  9346. command_multi(id)
  9347. {
  9348.     // Show activity?
  9349.     switch (get_pcvar_num(cvar_showactivity))
  9350.     {
  9351.         case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_MULTI")
  9352.         case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_MULTI")
  9353.     }
  9354.    
  9355.     // Log to Zombie Plague log file?
  9356.     if (get_pcvar_num(cvar_logcommands))
  9357.     {
  9358.         static logdata[100], authid[32], ip[16]
  9359.         get_user_authid(id, authid, charsmax(authid))
  9360.         get_user_ip(id, ip, charsmax(ip), 1)
  9361.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER,"CMD_MULTI", fnGetPlaying(), g_maxplayers)
  9362.         log_to_file("zombieplague.log", logdata)
  9363.     }
  9364.    
  9365.     // Call Multi Infection
  9366.     remove_task(TASK_MAKEZOMBIE)
  9367.     make_a_zombie(MODE_MULTI, 0)
  9368. }
  9369.  
  9370. // Admin Command. zp_plague
  9371. command_plague(id)
  9372. {
  9373.     // Show activity?
  9374.     switch (get_pcvar_num(cvar_showactivity))
  9375.     {
  9376.         case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_PLAGUE")
  9377.         case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_PLAGUE")
  9378.     }
  9379.    
  9380.     // Log to Zombie Plague log file?
  9381.     if (get_pcvar_num(cvar_logcommands))
  9382.     {
  9383.         static logdata[100], authid[32], ip[16]
  9384.         get_user_authid(id, authid, charsmax(authid))
  9385.         get_user_ip(id, ip, charsmax(ip), 1)
  9386.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER,"CMD_PLAGUE", fnGetPlaying(), g_maxplayers)
  9387.         log_to_file("zombieplague.log", logdata)
  9388.     }
  9389.    
  9390.     // Call Plague Mode
  9391.     remove_task(TASK_MAKEZOMBIE)
  9392.     make_a_zombie(MODE_PLAGUE, 0)
  9393. }
  9394.  
  9395. // Set proper maxspeed for player
  9396. set_player_maxspeed(id)
  9397. {
  9398.     // If frozen, prevent from moving
  9399.     if (g_frozen[id])
  9400.     {
  9401.         set_pev(id, pev_maxspeed, 1.0)
  9402.     }
  9403.     // Otherwise, set maxspeed directly
  9404.     else
  9405.     {
  9406.         if (g_zombie[id])
  9407.         {
  9408.             if (g_nemesis[id])
  9409.                 set_pev(id, pev_maxspeed, get_pcvar_float(cvar_nemspd))
  9410.             else
  9411.                 set_pev(id, pev_maxspeed, g_zombie_spd[id])
  9412.         }
  9413.         else
  9414.         {
  9415.             if (g_survivor[id])
  9416.                 set_pev(id, pev_maxspeed, get_pcvar_float(cvar_survspd))
  9417.             else if (get_pcvar_float(cvar_humanspd) > 0.0)
  9418.                 set_pev(id, pev_maxspeed, get_pcvar_float(cvar_humanspd))
  9419.         }
  9420.     }
  9421. }
  9422.  
  9423. /*================================================================================
  9424.  [Custom Natives]
  9425. =================================================================================*/
  9426.  
  9427. // Native: zp_get_user_zombie
  9428. public native_get_user_zombie(id)
  9429. {
  9430.     if (!is_user_valid(id))
  9431.     {
  9432.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9433.         return -1;
  9434.     }
  9435.    
  9436.     return g_zombie[id];
  9437. }
  9438.  
  9439. // Native: zp_get_user_nemesis
  9440. public native_get_user_nemesis(id)
  9441. {
  9442.     if (!is_user_valid(id))
  9443.     {
  9444.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9445.         return -1;
  9446.     }
  9447.    
  9448.     return g_nemesis[id];
  9449. }
  9450.  
  9451. // Native: zp_get_user_survivor
  9452. public native_get_user_survivor(id)
  9453. {
  9454.     if (!is_user_valid(id))
  9455.     {
  9456.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9457.         return -1;
  9458.     }
  9459.    
  9460.     return g_survivor[id];
  9461. }
  9462.  
  9463. public native_get_user_first_zombie(id)
  9464. {
  9465.     if (!is_user_valid(id))
  9466.     {
  9467.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9468.         return -1;
  9469.     }
  9470.    
  9471.     return g_firstzombie[id];
  9472. }
  9473.  
  9474. // Native: zp_get_user_last_zombie
  9475. public native_get_user_last_zombie(id)
  9476. {
  9477.     if (!is_user_valid(id))
  9478.     {
  9479.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9480.         return -1;
  9481.     }
  9482.    
  9483.     return g_lastzombie[id];
  9484. }
  9485.  
  9486. // Native: zp_get_user_last_human
  9487. public native_get_user_last_human(id)
  9488. {
  9489.     if (!is_user_valid(id))
  9490.     {
  9491.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9492.         return -1;
  9493.     }
  9494.    
  9495.     return g_lasthuman[id];
  9496. }
  9497.  
  9498. // Native: zp_get_user_zombie_class
  9499. public native_get_user_zombie_class(id)
  9500. {
  9501.     if (!is_user_valid(id))
  9502.     {
  9503.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9504.         return -1;
  9505.     }
  9506.    
  9507.     return g_zombieclass[id];
  9508. }
  9509.  
  9510. // Native: zp_get_user_next_class
  9511. public native_get_user_next_class(id)
  9512. {
  9513.     if (!is_user_valid(id))
  9514.     {
  9515.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9516.         return -1;
  9517.     }
  9518.    
  9519.     return g_zombieclassnext[id];
  9520. }
  9521.  
  9522. // Native: zp_set_user_zombie_class
  9523. public native_set_user_zombie_class(id, classid)
  9524. {
  9525.     if (!is_user_valid(id))
  9526.     {
  9527.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9528.         return false;
  9529.     }
  9530.    
  9531.     if (classid < 0 || classid >= g_zclass_i)
  9532.     {
  9533.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid zombie class id (%d)", classid)
  9534.         return false;
  9535.     }
  9536.    
  9537.     g_zombieclassnext[id] = classid
  9538.     return true;
  9539. }
  9540.  
  9541. // Native: zp_get_user_ammo_packs
  9542. public native_get_user_ammo_packs(id)
  9543. {
  9544.     if (!is_user_valid(id))
  9545.     {
  9546.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9547.         return -1;
  9548.     }
  9549.    
  9550.     return g_ammopacks[id];
  9551. }
  9552.  
  9553. // Native: zp_set_user_ammo_packs
  9554. public native_set_user_ammo_packs(id, amount)
  9555. {
  9556.     if (!is_user_valid(id))
  9557.     {
  9558.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9559.         return false;
  9560.     }
  9561.    
  9562.     g_ammopacks[id] = amount;
  9563.     return true;
  9564. }
  9565.  
  9566. // Native: zp_get_zombie_maxhealth
  9567. public native_get_zombie_maxhealth(id)
  9568. {
  9569.     // ZP disabled
  9570.     if (!g_pluginenabled)
  9571.         return -1;
  9572.    
  9573.     if (!is_user_valid(id))
  9574.     {
  9575.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9576.         return -1;
  9577.     }
  9578.    
  9579.     if (!g_zombie[id] || g_nemesis[id])
  9580.     {
  9581.         log_error(AMX_ERR_NATIVE, "[ZP] Player not a normal zombie (%d)", id)
  9582.         return -1;
  9583.     }
  9584.    
  9585.     if (g_firstzombie[id])
  9586.         return floatround(float(ArrayGetCell(g_zclass_hp, g_zombieclass[id])) * get_pcvar_float(cvar_zombiefirsthp));
  9587.    
  9588.     return ArrayGetCell(g_zclass_hp, g_zombieclass[id]);
  9589. }
  9590.  
  9591. // Native: zp_get_user_batteries
  9592. public native_get_user_batteries(id)
  9593. {
  9594.     if (!is_user_valid(id))
  9595.     {
  9596.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9597.         return -1;
  9598.     }
  9599.    
  9600.     return g_flashbattery[id];
  9601. }
  9602.  
  9603. // Native: zp_set_user_batteries
  9604. public native_set_user_batteries(id, value)
  9605. {
  9606.     // ZP disabled
  9607.     if (!g_pluginenabled)
  9608.         return false;
  9609.    
  9610.     if (!is_user_valid_connected(id))
  9611.     {
  9612.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9613.         return false;
  9614.     }
  9615.    
  9616.     g_flashbattery[id] = clamp(value, 0, 100);
  9617.    
  9618.     if (g_cached_customflash)
  9619.     {
  9620.         // Set the flashlight charge task to update battery status
  9621.         remove_task(id+TASK_CHARGE)
  9622.         set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
  9623.     }
  9624.     return true;
  9625. }
  9626.  
  9627. // Native: zp_get_user_nightvision
  9628. public native_get_user_nightvision(id)
  9629. {
  9630.     if (!is_user_valid(id))
  9631.     {
  9632.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9633.         return -1;
  9634.     }
  9635.    
  9636.     return g_nvision[id];
  9637. }
  9638.  
  9639. // Native: zp_set_user_nightvision
  9640. public native_set_user_nightvision(id, set)
  9641. {
  9642.     // ZP disabled
  9643.     if (!g_pluginenabled)
  9644.         return false;
  9645.    
  9646.     if (!is_user_valid_connected(id))
  9647.     {
  9648.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9649.         return false;
  9650.     }
  9651.    
  9652.     if (set)
  9653.     {
  9654.         g_nvision[id] = true
  9655.        
  9656.         if (!g_isbot[id])
  9657.         {
  9658.             g_nvisionenabled[id] = true
  9659.            
  9660.             // Custom nvg?
  9661.             if (get_pcvar_num(cvar_customnvg))
  9662.             {
  9663.                 remove_task(id+TASK_NVISION)
  9664.                 set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  9665.             }
  9666.             else
  9667.                 set_user_gnvision(id, 1)
  9668.         }
  9669.         else
  9670.             cs_set_user_nvg(id, 1)
  9671.     }
  9672.     else
  9673.     {
  9674.         // Remove CS nightvision if player owns one (bugfix)
  9675.         cs_set_user_nvg(id, 0)
  9676.        
  9677.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  9678.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  9679.         g_nvision[id] = false
  9680.         g_nvisionenabled[id] = false
  9681.     }
  9682.     return true;
  9683. }
  9684.  
  9685. // Native: zp_infect_user
  9686. public native_infect_user(id, infector, silent, rewards)
  9687. {
  9688.     // ZP disabled
  9689.     if (!g_pluginenabled)
  9690.         return false;
  9691.    
  9692.     if (!is_user_valid_alive(id))
  9693.     {
  9694.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9695.         return false;
  9696.     }
  9697.    
  9698.     // Not allowed to be zombie
  9699.     if (!allowed_zombie(id))
  9700.         return false;
  9701.    
  9702.     // New round?
  9703.     if (g_newround)
  9704.     {
  9705.         // Set as first zombie
  9706.         remove_task(TASK_MAKEZOMBIE)
  9707.         make_a_zombie(MODE_INFECTION, id)
  9708.     }
  9709.     else
  9710.     {
  9711.         // Just infect (plus some checks)
  9712.         zombieme(id, is_user_valid_alive(infector) ? infector : 0, 0, (silent == 1) ? 1 : 0, (rewards == 1) ? 1 : 0)
  9713.     }
  9714.     return true;
  9715. }
  9716.  
  9717. // Native: zp_disinfect_user
  9718. public native_disinfect_user(id, silent)
  9719. {
  9720.     // ZP disabled
  9721.     if (!g_pluginenabled)
  9722.         return false;
  9723.    
  9724.     if (!is_user_valid_alive(id))
  9725.     {
  9726.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9727.         return false;
  9728.     }
  9729.    
  9730.     // Not allowed to be human
  9731.     if (!allowed_human(id))
  9732.         return false;
  9733.    
  9734.     // Turn to human
  9735.     humanme(id, 0, (silent == 1) ? 1 : 0)
  9736.     return true;
  9737. }
  9738.  
  9739. // Native: zp_make_user_nemesis
  9740. public native_make_user_nemesis(id)
  9741. {
  9742.     // ZP disabled
  9743.     if (!g_pluginenabled)
  9744.         return false;
  9745.    
  9746.     if (!is_user_valid_alive(id))
  9747.     {
  9748.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9749.         return false;
  9750.     }
  9751.    
  9752.     // Not allowed to be nemesis
  9753.     if (!allowed_nemesis(id))
  9754.         return false;
  9755.    
  9756.     // New round?
  9757.     if (g_newround)
  9758.     {
  9759.         // Set as first nemesis
  9760.         remove_task(TASK_MAKEZOMBIE)
  9761.         make_a_zombie(MODE_NEMESIS, id)
  9762.     }
  9763.     else
  9764.     {
  9765.         // Turn player into a Nemesis
  9766.         zombieme(id, 0, 1, 0, 0)
  9767.     }
  9768.     return true;
  9769. }
  9770.  
  9771. // Native: zp_make_user_survivor
  9772. public native_make_user_survivor(id)
  9773. {
  9774.     // ZP disabled
  9775.     if (!g_pluginenabled)
  9776.         return false;
  9777.    
  9778.     if (!is_user_valid_alive(id))
  9779.     {
  9780.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9781.         return false;
  9782.     }
  9783.    
  9784.     // Not allowed to be survivor
  9785.     if (!allowed_survivor(id))
  9786.         return false;
  9787.    
  9788.     // New round?
  9789.     if (g_newround)
  9790.     {
  9791.         // Set as first survivor
  9792.         remove_task(TASK_MAKEZOMBIE)
  9793.         make_a_zombie(MODE_SURVIVOR, id)
  9794.     }
  9795.     else
  9796.     {
  9797.         // Turn player into a Survivor
  9798.         humanme(id, 1, 0)
  9799.     }
  9800.    
  9801.     return true;
  9802. }
  9803.  
  9804. // Native: zp_respawn_user
  9805. public native_respawn_user(id, team)
  9806. {
  9807.     // ZP disabled
  9808.     if (!g_pluginenabled)
  9809.         return false;
  9810.    
  9811.     if (!is_user_valid_connected(id))
  9812.     {
  9813.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9814.         return false;
  9815.     }
  9816.    
  9817.     // Respawn not allowed
  9818.     if (!allowed_respawn(id))
  9819.         return false;
  9820.    
  9821.     // Respawn as zombie?
  9822.     g_respawn_as_zombie[id] = (team == ZP_TEAM_ZOMBIE) ? true : false
  9823.    
  9824.     // Respawnish!
  9825.     respawn_player_manually(id)
  9826.     return true;
  9827. }
  9828.  
  9829. // Native: zp_force_buy_extra_item
  9830. public native_force_buy_extra_item(id, itemid, ignorecost)
  9831. {
  9832.     // ZP disabled
  9833.     if (!g_pluginenabled)
  9834.         return false;
  9835.    
  9836.     if (!is_user_valid_alive(id))
  9837.     {
  9838.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9839.         return false;
  9840.     }
  9841.    
  9842.     if (itemid < 0 || itemid >= g_extraitem_i)
  9843.     {
  9844.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid extra item id (%d)", itemid)
  9845.         return false;
  9846.     }
  9847.    
  9848.     buy_extra_item(id, itemid, ignorecost)
  9849.     return true;
  9850. }
  9851.  
  9852. // Native: zp_override_user_model
  9853. public native_override_user_model(id, const newmodel[], modelindex)
  9854. {
  9855.     // ZP disabled
  9856.     if (!g_pluginenabled)
  9857.         return false;
  9858.    
  9859.     if (!is_user_valid_connected(id))
  9860.     {
  9861.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9862.         return false;
  9863.     }
  9864.    
  9865.     // Strings passed byref
  9866.     param_convert(2)
  9867.    
  9868.     // Remove previous tasks
  9869.     remove_task(id+TASK_MODEL)
  9870.    
  9871.     // Custom models stuff
  9872.     static currentmodel[32]
  9873.    
  9874.     if (g_handle_models_on_separate_ent)
  9875.     {
  9876.         // Set the right model
  9877.         copy(g_playermodel[id], charsmax(g_playermodel[]), newmodel)
  9878.         if (g_set_modelindex_offset && modelindex) fm_cs_set_user_model_index(id, modelindex)
  9879.        
  9880.         // Set model on player model entity
  9881.         fm_set_playermodel_ent(id)
  9882.     }
  9883.     else
  9884.     {
  9885.         // Get current model for comparing it with the current one
  9886.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  9887.        
  9888.         // Set the right model, after checking that we don't already have it
  9889.         if (!equal(currentmodel, newmodel))
  9890.         {
  9891.             copy(g_playermodel[id], charsmax(g_playermodel[]), newmodel)
  9892.             if (g_set_modelindex_offset && modelindex) fm_cs_set_user_model_index(id, modelindex)
  9893.            
  9894.             // An additional delay is offset at round start
  9895.             // since SVC_BAD is more likely to be triggered there
  9896.             if (g_newround)
  9897.                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  9898.             else
  9899.                 fm_user_model_update(id+TASK_MODEL)
  9900.         }
  9901.     }
  9902.     return true;
  9903. }
  9904.  
  9905. // Native: zp_has_round_started
  9906. public native_has_round_started()
  9907. {
  9908.     if (g_newround) return 0; // not started
  9909.     if (g_modestarted) return 1; // started
  9910.     return 2; // starting
  9911. }
  9912.  
  9913. // Native: zp_is_nemesis_round
  9914. public native_is_nemesis_round()
  9915. {
  9916.     return g_nemround;
  9917. }
  9918.  
  9919. // Native: zp_is_survivor_round
  9920. public native_is_survivor_round()
  9921. {
  9922.     return g_survround;
  9923. }
  9924.  
  9925. // Native: zp_is_swarm_round
  9926. public native_is_swarm_round()
  9927. {
  9928.     return g_swarmround;
  9929. }
  9930.  
  9931. // Native: zp_is_plague_round
  9932. public native_is_plague_round()
  9933. {
  9934.     return g_plagueround;
  9935. }
  9936.  
  9937. // Native: zp_get_zombie_count
  9938. public native_get_zombie_count()
  9939. {
  9940.     return fnGetZombies();
  9941. }
  9942.  
  9943. // Native: zp_get_human_count
  9944. public native_get_human_count()
  9945. {
  9946.     return fnGetHumans();
  9947. }
  9948.  
  9949. // Native: zp_get_nemesis_count
  9950. public native_get_nemesis_count()
  9951. {
  9952.     return fnGetNemesis();
  9953. }
  9954.  
  9955. // Native: zp_get_survivor_count
  9956. public native_get_survivor_count()
  9957. {
  9958.     return fnGetSurvivors();
  9959. }
  9960.  
  9961. // Native: zp_register_extra_item
  9962. public native_register_extra_item(const name[], cost, team)
  9963. {
  9964.     // ZP disabled
  9965.     if (!g_pluginenabled)
  9966.         return -1;
  9967.    
  9968.     // Strings passed byref
  9969.     param_convert(1)
  9970.    
  9971.     // Arrays not yet initialized
  9972.     if (!g_arrays_created)
  9973.     {
  9974.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register extra item yet (%s)", name)
  9975.         return -1;
  9976.     }
  9977.    
  9978.     if (strlen(name) < 1)
  9979.     {
  9980.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register extra item with an empty name")
  9981.         return -1;
  9982.     }
  9983.    
  9984.     new index, extraitem_name[32]
  9985.     for (index = 0; index < g_extraitem_i; index++)
  9986.     {
  9987.         ArrayGetString(g_extraitem_name, index, extraitem_name, charsmax(extraitem_name))
  9988.         if (equali(name, extraitem_name))
  9989.         {
  9990.             log_error(AMX_ERR_NATIVE, "[ZP] Extra item already registered (%s)", name)
  9991.             return -1;
  9992.         }
  9993.     }
  9994.    
  9995.     // For backwards compatibility
  9996.     if (team == ZP_TEAM_ANY)
  9997.         team = (ZP_TEAM_ZOMBIE|ZP_TEAM_HUMAN)
  9998.    
  9999.     // Add the item
  10000.     ArrayPushString(g_extraitem_name, name)
  10001.     ArrayPushCell(g_extraitem_cost, cost)
  10002.     ArrayPushCell(g_extraitem_team, team)
  10003.    
  10004.     // Set temporary new item flag
  10005.     ArrayPushCell(g_extraitem_new, 1)
  10006.    
  10007.     // Override extra items data with our customizations
  10008.     new i, buffer[32], size = ArraySize(g_extraitem2_realname)
  10009.     for (i = 0; i < size; i++)
  10010.     {
  10011.         ArrayGetString(g_extraitem2_realname, i, buffer, charsmax(buffer))
  10012.        
  10013.         // Check if this is the intended item to override
  10014.         if (!equal(name, buffer))
  10015.             continue;
  10016.        
  10017.         // Remove new item flag
  10018.         ArraySetCell(g_extraitem_new, g_extraitem_i, 0)
  10019.        
  10020.         // Replace caption
  10021.         ArrayGetString(g_extraitem2_name, i, buffer, charsmax(buffer))
  10022.         ArraySetString(g_extraitem_name, g_extraitem_i, buffer)
  10023.        
  10024.         // Replace cost
  10025.         buffer[0] = ArrayGetCell(g_extraitem2_cost, i)
  10026.         ArraySetCell(g_extraitem_cost, g_extraitem_i, buffer[0])
  10027.        
  10028.         // Replace team
  10029.         buffer[0] = ArrayGetCell(g_extraitem2_team, i)
  10030.         ArraySetCell(g_extraitem_team, g_extraitem_i, buffer[0])
  10031.     }
  10032.    
  10033.     // Increase registered items counter
  10034.     g_extraitem_i++
  10035.    
  10036.     // Return id under which we registered the item
  10037.     return g_extraitem_i-1;
  10038. }
  10039.  
  10040. // Function: zp_register_extra_item (to be used within this plugin only)
  10041. native_register_extra_item2(const name[], cost, team)
  10042. {
  10043.     // Add the item
  10044.     ArrayPushString(g_extraitem_name, name)
  10045.     ArrayPushCell(g_extraitem_cost, cost)
  10046.     ArrayPushCell(g_extraitem_team, team)
  10047.    
  10048.     // Set temporary new item flag
  10049.     ArrayPushCell(g_extraitem_new, 1)
  10050.    
  10051.     // Increase registered items counter
  10052.     g_extraitem_i++
  10053. }
  10054.  
  10055. // Native: zp_register_zombie_class
  10056. public native_register_zombie_class(const name[], const info[], const model[], const clawmodel[], hp, speed, Float:gravity, Float:knockback)
  10057. {
  10058.     // ZP disabled
  10059.     if (!g_pluginenabled)
  10060.         return -1;
  10061.    
  10062.     // Strings passed byref
  10063.     param_convert(1)
  10064.     param_convert(2)
  10065.     param_convert(3)
  10066.     param_convert(4)
  10067.    
  10068.     // Arrays not yet initialized
  10069.     if (!g_arrays_created)
  10070.     {
  10071.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register zombie class yet (%s)", name)
  10072.         return -1;
  10073.     }
  10074.    
  10075.     if (strlen(name) < 1)
  10076.     {
  10077.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register zombie class with an empty name")
  10078.         return -1;
  10079.     }
  10080.    
  10081.     new index, zombieclass_name[32]
  10082.     for (index = 0; index < g_zclass_i; index++)
  10083.     {
  10084.         ArrayGetString(g_zclass_name, index, zombieclass_name, charsmax(zombieclass_name))
  10085.         if (equali(name, zombieclass_name))
  10086.         {
  10087.             log_error(AMX_ERR_NATIVE, "[ZP] Zombie class already registered (%s)", name)
  10088.             return -1;
  10089.         }
  10090.     }
  10091.    
  10092.     // Add the class
  10093.     ArrayPushString(g_zclass_name, name)
  10094.     ArrayPushString(g_zclass_info, info)
  10095.    
  10096.     // Using same zombie models for all classes?
  10097.     if (g_same_models_for_all)
  10098.     {
  10099.         ArrayPushCell(g_zclass_modelsstart, 0)
  10100.         ArrayPushCell(g_zclass_modelsend, ArraySize(g_zclass_playermodel))
  10101.     }
  10102.     else
  10103.     {
  10104.         ArrayPushCell(g_zclass_modelsstart, ArraySize(g_zclass_playermodel))
  10105.         ArrayPushString(g_zclass_playermodel, model)
  10106.         ArrayPushCell(g_zclass_modelsend, ArraySize(g_zclass_playermodel))
  10107.         ArrayPushCell(g_zclass_modelindex, -1)
  10108.     }
  10109.    
  10110.     ArrayPushString(g_zclass_clawmodel, clawmodel)
  10111.     ArrayPushCell(g_zclass_hp, hp)
  10112.     ArrayPushCell(g_zclass_spd, speed)
  10113.     ArrayPushCell(g_zclass_grav, gravity)
  10114.     ArrayPushCell(g_zclass_kb, knockback)
  10115.    
  10116.     // Set temporary new class flag
  10117.     ArrayPushCell(g_zclass_new, 1)
  10118.    
  10119.     // Override zombie classes data with our customizations
  10120.     new i, k, buffer[32], Float:buffer2, nummodels_custom, nummodels_default, prec_mdl[100], size = ArraySize(g_zclass2_realname)
  10121.     for (i = 0; i < size; i++)
  10122.     {
  10123.         ArrayGetString(g_zclass2_realname, i, buffer, charsmax(buffer))
  10124.        
  10125.         // Check if this is the intended class to override
  10126.         if (!equal(name, buffer))
  10127.             continue;
  10128.        
  10129.         // Remove new class flag
  10130.         ArraySetCell(g_zclass_new, g_zclass_i, 0)
  10131.        
  10132.         // Replace caption
  10133.         ArrayGetString(g_zclass2_name, i, buffer, charsmax(buffer))
  10134.         ArraySetString(g_zclass_name, g_zclass_i, buffer)
  10135.        
  10136.         // Replace info
  10137.         ArrayGetString(g_zclass2_info, i, buffer, charsmax(buffer))
  10138.         ArraySetString(g_zclass_info, g_zclass_i, buffer)
  10139.        
  10140.         // Replace models, unless using same models for all classes
  10141.         if (!g_same_models_for_all)
  10142.         {
  10143.             nummodels_custom = ArrayGetCell(g_zclass2_modelsend, i) - ArrayGetCell(g_zclass2_modelsstart, i)
  10144.             nummodels_default = ArrayGetCell(g_zclass_modelsend, g_zclass_i) - ArrayGetCell(g_zclass_modelsstart, g_zclass_i)
  10145.            
  10146.             // Replace each player model and model index
  10147.             for (k = 0; k < min(nummodels_custom, nummodels_default); k++)
  10148.             {
  10149.                 ArrayGetString(g_zclass2_playermodel, ArrayGetCell(g_zclass2_modelsstart, i) + k, buffer, charsmax(buffer))
  10150.                 ArraySetString(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k, buffer)
  10151.                
  10152.                 // Precache player model and replace its modelindex with the real one
  10153.                 formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", buffer, buffer)
  10154.                 ArraySetCell(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k, engfunc(EngFunc_PrecacheModel, prec_mdl))
  10155.                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
  10156.                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
  10157.                 // Precache modelT.mdl files too
  10158.                 copy(prec_mdl[strlen(prec_mdl)-4], charsmax(prec_mdl) - (strlen(prec_mdl)-4), "T.mdl")
  10159.                 if (file_exists(prec_mdl)) engfunc(EngFunc_PrecacheModel, prec_mdl)
  10160.             }
  10161.            
  10162.             // We have more custom models than what we can accommodate,
  10163.             // Let's make some space...
  10164.             if (nummodels_custom > nummodels_default)
  10165.             {
  10166.                 for (k = nummodels_default; k < nummodels_custom; k++)
  10167.                 {
  10168.                     ArrayGetString(g_zclass2_playermodel, ArrayGetCell(g_zclass2_modelsstart, i) + k, buffer, charsmax(buffer))
  10169.                     ArrayInsertStringAfter(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k - 1, buffer)
  10170.                    
  10171.                     // Precache player model and retrieve its modelindex
  10172.                     formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", buffer, buffer)
  10173.                     ArrayInsertCellAfter(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k - 1, engfunc(EngFunc_PrecacheModel, prec_mdl))
  10174.                     if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
  10175.                     if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
  10176.                     // Precache modelT.mdl files too
  10177.                     copy(prec_mdl[strlen(prec_mdl)-4], charsmax(prec_mdl) - (strlen(prec_mdl)-4), "T.mdl")
  10178.                     if (file_exists(prec_mdl)) engfunc(EngFunc_PrecacheModel, prec_mdl)
  10179.                 }
  10180.                
  10181.                 // Fix models end index for this class
  10182.                 ArraySetCell(g_zclass_modelsend, g_zclass_i, ArrayGetCell(g_zclass_modelsend, g_zclass_i) + (nummodels_custom - nummodels_default))
  10183.             }
  10184.            
  10185.             /* --- Not needed since classes can't have more than 1 default model for now ---
  10186.             // We have less custom models than what this class has by default,
  10187.             // Get rid of those extra entries...
  10188.             if (nummodels_custom < nummodels_default)
  10189.             {
  10190.                 for (k = nummodels_custom; k < nummodels_default; k++)
  10191.                 {
  10192.                     ArrayDeleteItem(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + nummodels_custom)
  10193.                 }
  10194.                
  10195.                 // Fix models end index for this class
  10196.                 ArraySetCell(g_zclass_modelsend, g_zclass_i, ArrayGetCell(g_zclass_modelsend, g_zclass_i) - (nummodels_default - nummodels_custom))
  10197.             }
  10198.             */
  10199.         }
  10200.        
  10201.         // Replace clawmodel
  10202.         ArrayGetString(g_zclass2_clawmodel, i, buffer, charsmax(buffer))
  10203.         ArraySetString(g_zclass_clawmodel, g_zclass_i, buffer)
  10204.        
  10205.         // Precache clawmodel
  10206.         formatex(prec_mdl, charsmax(prec_mdl), "models/zombie_plague/%s", buffer)
  10207.         engfunc(EngFunc_PrecacheModel, prec_mdl)
  10208.        
  10209.         // Replace health
  10210.         buffer[0] = ArrayGetCell(g_zclass2_hp, i)
  10211.         ArraySetCell(g_zclass_hp, g_zclass_i, buffer[0])
  10212.        
  10213.         // Replace speed
  10214.         buffer[0] = ArrayGetCell(g_zclass2_spd, i)
  10215.         ArraySetCell(g_zclass_spd, g_zclass_i, buffer[0])
  10216.        
  10217.         // Replace gravity
  10218.         buffer2 = Float:ArrayGetCell(g_zclass2_grav, i)
  10219.         ArraySetCell(g_zclass_grav, g_zclass_i, buffer2)
  10220.        
  10221.         // Replace knockback
  10222.         buffer2 = Float:ArrayGetCell(g_zclass2_kb, i)
  10223.         ArraySetCell(g_zclass_kb, g_zclass_i, buffer2)
  10224.     }
  10225.    
  10226.     // If class was not overriden with customization data
  10227.     if (ArrayGetCell(g_zclass_new, g_zclass_i))
  10228.     {
  10229.         // If not using same models for all classes
  10230.         if (!g_same_models_for_all)
  10231.         {
  10232.             // Precache default class model and replace modelindex with the real one
  10233.             formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", model, model)
  10234.             ArraySetCell(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i), engfunc(EngFunc_PrecacheModel, prec_mdl))
  10235.             if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
  10236.             if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
  10237.             // Precache modelT.mdl files too
  10238.             copy(prec_mdl[strlen(prec_mdl)-4], charsmax(prec_mdl) - (strlen(prec_mdl)-4), "T.mdl")
  10239.             if (file_exists(prec_mdl)) engfunc(EngFunc_PrecacheModel, prec_mdl)
  10240.         }
  10241.        
  10242.         // Precache default clawmodel
  10243.         formatex(prec_mdl, charsmax(prec_mdl), "models/zombie_plague/%s", clawmodel)
  10244.         engfunc(EngFunc_PrecacheModel, prec_mdl)
  10245.     }
  10246.    
  10247.     // Increase registered classes counter
  10248.     g_zclass_i++
  10249.    
  10250.     // Return id under which we registered the class
  10251.     return g_zclass_i-1;
  10252. }
  10253.  
  10254. // Native: zp_get_extra_item_id
  10255. public native_get_extra_item_id(const name[])
  10256. {
  10257.     // ZP disabled
  10258.     if (!g_pluginenabled)
  10259.         return -1;
  10260.    
  10261.     // Strings passed byref
  10262.     param_convert(1)
  10263.    
  10264.     // Loop through every item (not using Tries since ZP should work on AMXX 1.8.0)
  10265.     static i, item_name[32]
  10266.     for (i = 0; i < g_extraitem_i; i++)
  10267.     {
  10268.         ArrayGetString(g_extraitem_name, i, item_name, charsmax(item_name))
  10269.        
  10270.         // Check if this is the item to retrieve
  10271.         if (equali(name, item_name))
  10272.             return i;
  10273.     }
  10274.    
  10275.     return -1;
  10276. }
  10277.  
  10278. // Native: zp_get_zombie_class_id
  10279. public native_get_zombie_class_id(const name[])
  10280. {
  10281.     // ZP disabled
  10282.     if (!g_pluginenabled)
  10283.         return -1;
  10284.    
  10285.     // Strings passed byref
  10286.     param_convert(1)
  10287.    
  10288.     // Loop through every class (not using Tries since ZP should work on AMXX 1.8.0)
  10289.     static i, class_name[32]
  10290.     for (i = 0; i < g_zclass_i; i++)
  10291.     {
  10292.         ArrayGetString(g_zclass_name, i, class_name, charsmax(class_name))
  10293.        
  10294.         // Check if this is the class to retrieve
  10295.         if (equali(name, class_name))
  10296.             return i;
  10297.     }
  10298.    
  10299.     return -1;
  10300. }
  10301.  
  10302. // Native: zp_get_zombie_class_info
  10303. public native_get_zombie_class_info(classid, info[], len)
  10304. {
  10305.     // ZP disabled
  10306.     if (!g_pluginenabled)
  10307.         return false;
  10308.    
  10309.     // Invalid class
  10310.     if (classid < 0 || classid >= g_zclass_i)
  10311.     {
  10312.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid zombie class id (%d)", classid)
  10313.         return false;
  10314.     }
  10315.    
  10316.     // Strings passed byref
  10317.     param_convert(2)
  10318.    
  10319.     // Fetch zombie class info
  10320.     ArrayGetString(g_zclass_info, classid, info, len)
  10321.     return true;
  10322. }
  10323.  
  10324. /*================================================================================
  10325.  [Custom Messages]
  10326. =================================================================================*/
  10327.  
  10328. // Custom Night Vision
  10329. public set_user_nvision(taskid)
  10330. {
  10331.     // Get player's origin
  10332.     static origin[3]
  10333.     get_user_origin(ID_NVISION, origin)
  10334.    
  10335.     // Nightvision message
  10336.     message_begin(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, _, ID_NVISION)
  10337.     write_byte(TE_DLIGHT) // TE id
  10338.     write_coord(origin[0]) // x
  10339.     write_coord(origin[1]) // y
  10340.     write_coord(origin[2]) // z
  10341.     write_byte(get_pcvar_num(cvar_nvgsize)) // radius
  10342.    
  10343.     // Nemesis / Madness / Spectator in nemesis round
  10344.     if (g_nemesis[ID_NVISION] || (g_zombie[ID_NVISION] && g_nodamage[ID_NVISION]) || (!g_isalive[ID_NVISION] && g_nemround))
  10345.     {
  10346.         write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
  10347.         write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
  10348.         write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
  10349.     }
  10350.     // Human / Spectator in normal round
  10351.     else if (!g_zombie[ID_NVISION] || !g_isalive[ID_NVISION])
  10352.     {
  10353.         write_byte(get_pcvar_num(cvar_humnvgcolor[0])) // r
  10354.         write_byte(get_pcvar_num(cvar_humnvgcolor[1])) // g
  10355.         write_byte(get_pcvar_num(cvar_humnvgcolor[2])) // b
  10356.     }
  10357.     // Zombie
  10358.     else
  10359.     {
  10360.         write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
  10361.         write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
  10362.         write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
  10363.     }
  10364.    
  10365.     write_byte(2) // life
  10366.     write_byte(0) // decay rate
  10367.     message_end()
  10368. }
  10369.  
  10370. // Game Nightvision
  10371. set_user_gnvision(id, toggle)
  10372. {
  10373.     // Toggle NVG message
  10374.     message_begin(MSG_ONE, g_msgNVGToggle, _, id)
  10375.     write_byte(toggle) // toggle
  10376.     message_end()
  10377. }
  10378.  
  10379. // Custom Flashlight
  10380. public set_user_flashlight(taskid)
  10381. {
  10382.     // Get player and aiming origins
  10383.     static Float:originF[3], Float:destoriginF[3]
  10384.     pev(ID_FLASH, pev_origin, originF)
  10385.     fm_get_aim_origin(ID_FLASH, destoriginF)
  10386.    
  10387.     // Max distance check
  10388.     if (get_distance_f(originF, destoriginF) > get_pcvar_float(cvar_flashdist))
  10389.         return;
  10390.    
  10391.     // Send to all players?
  10392.     if (get_pcvar_num(cvar_flashshowall))
  10393.         engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, destoriginF, 0)
  10394.     else
  10395.         message_begin(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, _, ID_FLASH)
  10396.    
  10397.     // Flashlight
  10398.     write_byte(TE_DLIGHT) // TE id
  10399.     engfunc(EngFunc_WriteCoord, destoriginF[0]) // x
  10400.     engfunc(EngFunc_WriteCoord, destoriginF[1]) // y
  10401.     engfunc(EngFunc_WriteCoord, destoriginF[2]) // z
  10402.     write_byte(get_pcvar_num(cvar_flashsize)) // radius
  10403.     write_byte(get_pcvar_num(cvar_flashcolor[0])) // r
  10404.     write_byte(get_pcvar_num(cvar_flashcolor[1])) // g
  10405.     write_byte(get_pcvar_num(cvar_flashcolor[2])) // b
  10406.     write_byte(3) // life
  10407.     write_byte(0) // decay rate
  10408.     message_end()
  10409. }
  10410.  
  10411. // Infection special effects
  10412. infection_effects(id)
  10413. {
  10414.     // Screen fade? (unless frozen)
  10415.     if (!g_frozen[id] && get_pcvar_num(cvar_infectionscreenfade))
  10416.     {
  10417.         message_begin(MSG_ONE_UNRELIABLE, g_msgScreenFade, _, id)
  10418.         write_short(UNIT_SECOND) // duration
  10419.         write_short(0) // hold time
  10420.         write_short(FFADE_IN) // fade type
  10421.         if (g_nemesis[id])
  10422.         {
  10423.             write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
  10424.             write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
  10425.             write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
  10426.         }
  10427.         else
  10428.         {
  10429.             write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
  10430.             write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
  10431.             write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
  10432.         }
  10433.         write_byte (255) // alpha
  10434.         message_end()
  10435.     }
  10436.    
  10437.     // Screen shake?
  10438.     if (get_pcvar_num(cvar_infectionscreenshake))
  10439.     {
  10440.         message_begin(MSG_ONE_UNRELIABLE, g_msgScreenShake, _, id)
  10441.         write_short(UNIT_SECOND*4) // amplitude
  10442.         write_short(UNIT_SECOND*2) // duration
  10443.         write_short(UNIT_SECOND*10) // frequency
  10444.         message_end()
  10445.     }
  10446.    
  10447.     // Infection icon?
  10448.     if (get_pcvar_num(cvar_hudicons))
  10449.     {
  10450.         message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, id)
  10451.         write_byte(0) // damage save
  10452.         write_byte(0) // damage take
  10453.         write_long(DMG_NERVEGAS) // damage type - DMG_RADIATION
  10454.         write_coord(0) // x
  10455.         write_coord(0) // y
  10456.         write_coord(0) // z
  10457.         message_end()
  10458.     }
  10459.    
  10460.     // Get player's origin
  10461.     static origin[3]
  10462.     get_user_origin(id, origin)
  10463.    
  10464.     // Tracers?
  10465.     if (get_pcvar_num(cvar_infectiontracers))
  10466.     {
  10467.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10468.         write_byte(TE_IMPLOSION) // TE id
  10469.         write_coord(origin[0]) // x
  10470.         write_coord(origin[1]) // y
  10471.         write_coord(origin[2]) // z
  10472.         write_byte(128) // radius
  10473.         write_byte(20) // count
  10474.         write_byte(3) // duration
  10475.         message_end()
  10476.     }
  10477.    
  10478.     // Particle burst?
  10479.     if (get_pcvar_num(cvar_infectionparticles))
  10480.     {
  10481.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10482.         write_byte(TE_PARTICLEBURST) // TE id
  10483.         write_coord(origin[0]) // x
  10484.         write_coord(origin[1]) // y
  10485.         write_coord(origin[2]) // z
  10486.         write_short(50) // radius
  10487.         write_byte(70) // color
  10488.         write_byte(3) // duration (will be randomized a bit)
  10489.         message_end()
  10490.     }
  10491.    
  10492.     // Light sparkle?
  10493.     if (get_pcvar_num(cvar_infectionsparkle))
  10494.     {
  10495.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10496.         write_byte(TE_DLIGHT) // TE id
  10497.         write_coord(origin[0]) // x
  10498.         write_coord(origin[1]) // y
  10499.         write_coord(origin[2]) // z
  10500.         write_byte(20) // radius
  10501.         write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
  10502.         write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
  10503.         write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
  10504.         write_byte(2) // life
  10505.         write_byte(0) // decay rate
  10506.         message_end()
  10507.     }
  10508. }
  10509.  
  10510. // Nemesis/madness aura task
  10511. public zombie_aura(taskid)
  10512. {
  10513.     // Not nemesis, not in zombie madness
  10514.     if (!g_nemesis[ID_AURA] && !g_nodamage[ID_AURA])
  10515.     {
  10516.         // Task not needed anymore
  10517.         remove_task(taskid);
  10518.         return;
  10519.     }
  10520.    
  10521.     // Get player's origin
  10522.     static origin[3]
  10523.     get_user_origin(ID_AURA, origin)
  10524.    
  10525.     // Colored Aura
  10526.     message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10527.     write_byte(TE_DLIGHT) // TE id
  10528.     write_coord(origin[0]) // x
  10529.     write_coord(origin[1]) // y
  10530.     write_coord(origin[2]) // z
  10531.     write_byte(20) // radius
  10532.     write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
  10533.     write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
  10534.     write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
  10535.     write_byte(2) // life
  10536.     write_byte(0) // decay rate
  10537.     message_end()
  10538. }
  10539.  
  10540. // Make zombies leave footsteps and bloodstains on the floor
  10541. public make_blood(taskid)
  10542. {
  10543.     // Only bleed when moving on ground
  10544.     if (!(pev(ID_BLOOD, pev_flags) & FL_ONGROUND) || fm_get_speed(ID_BLOOD) < 80)
  10545.         return;
  10546.    
  10547.     // Get user origin
  10548.     static Float:originF[3]
  10549.     pev(ID_BLOOD, pev_origin, originF)
  10550.    
  10551.     // If ducking set a little lower
  10552.     if (pev(ID_BLOOD, pev_bInDuck))
  10553.         originF[2] -= 18.0
  10554.     else
  10555.         originF[2] -= 36.0
  10556.    
  10557.     // Send the decal message
  10558.     engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, originF, 0)
  10559.     write_byte(TE_WORLDDECAL) // TE id
  10560.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10561.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10562.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10563.     write_byte(ArrayGetCell(zombie_decals, random_num(0, ArraySize(zombie_decals) - 1)) + (g_czero * 12)) // random decal number (offsets +12 for CZ)
  10564.     message_end()
  10565. }
  10566.  
  10567. // Flare Lighting Effects
  10568. flare_lighting(entity, duration)
  10569. {
  10570.     // Get origin and color
  10571.     static Float:originF[3], color[3]
  10572.     pev(entity, pev_origin, originF)
  10573.     pev(entity, PEV_FLARE_COLOR, color)
  10574.    
  10575.     // Lighting
  10576.     engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, originF, 0)
  10577.     write_byte(TE_DLIGHT) // TE id
  10578.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10579.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10580.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10581.     write_byte(get_pcvar_num(cvar_flaresize)) // radius
  10582.     write_byte(color[0]) // r
  10583.     write_byte(color[1]) // g
  10584.     write_byte(color[2]) // b
  10585.     write_byte(21) //life
  10586.     write_byte((duration < 2) ? 3 : 0) //decay rate
  10587.     message_end()
  10588.    
  10589.     // Sparks
  10590.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10591.     write_byte(TE_SPARKS) // TE id
  10592.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10593.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10594.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10595.     message_end()
  10596. }
  10597.  
  10598. // Burning Flames
  10599. public burning_flame(taskid)
  10600. {
  10601.     // Get player origin and flags
  10602.     static origin[3], flags
  10603.     get_user_origin(ID_BURN, origin)
  10604.     flags = pev(ID_BURN, pev_flags)
  10605.    
  10606.     // Madness mode - in water - burning stopped
  10607.     if (g_nodamage[ID_BURN] || (flags & FL_INWATER) || g_burning_duration[ID_BURN] < 1)
  10608.     {
  10609.         // Smoke sprite
  10610.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10611.         write_byte(TE_SMOKE) // TE id
  10612.         write_coord(origin[0]) // x
  10613.         write_coord(origin[1]) // y
  10614.         write_coord(origin[2]-50) // z
  10615.         write_short(g_smokeSpr) // sprite
  10616.         write_byte(random_num(15, 20)) // scale
  10617.         write_byte(random_num(10, 20)) // framerate
  10618.         message_end()
  10619.        
  10620.         // Task not needed anymore
  10621.         remove_task(taskid);
  10622.         return;
  10623.     }
  10624.    
  10625.     // Randomly play burning zombie scream sounds (not for nemesis)
  10626.     if (!g_nemesis[ID_BURN] && !random_num(0, 20))
  10627.     {
  10628.         static sound[64]
  10629.         ArrayGetString(grenade_fire_player, random_num(0, ArraySize(grenade_fire_player) - 1), sound, charsmax(sound))
  10630.         emit_sound(ID_BURN, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  10631.     }
  10632.    
  10633.     // Fire slow down, unless nemesis
  10634.     if (!g_nemesis[ID_BURN] && (flags & FL_ONGROUND) && get_pcvar_float(cvar_fireslowdown) > 0.0)
  10635.     {
  10636.         static Float:velocity[3]
  10637.         pev(ID_BURN, pev_velocity, velocity)
  10638.         xs_vec_mul_scalar(velocity, get_pcvar_float(cvar_fireslowdown), velocity)
  10639.         set_pev(ID_BURN, pev_velocity, velocity)
  10640.     }
  10641.    
  10642.     // Get player's health
  10643.     static health
  10644.     health = pev(ID_BURN, pev_health)
  10645.    
  10646.     // Take damage from the fire
  10647.     if (health - floatround(get_pcvar_float(cvar_firedamage), floatround_ceil) > 0)
  10648.         fm_set_user_health(ID_BURN, health - floatround(get_pcvar_float(cvar_firedamage), floatround_ceil))
  10649.    
  10650.     // Flame sprite
  10651.     message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10652.     write_byte(TE_SPRITE) // TE id
  10653.     write_coord(origin[0]+random_num(-5, 5)) // x
  10654.     write_coord(origin[1]+random_num(-5, 5)) // y
  10655.     write_coord(origin[2]+random_num(-10, 10)) // z
  10656.     write_short(g_flameSpr) // sprite
  10657.     write_byte(random_num(5, 10)) // scale
  10658.     write_byte(200) // brightness
  10659.     message_end()
  10660.    
  10661.     // Decrease burning duration counter
  10662.     g_burning_duration[ID_BURN]--
  10663. }
  10664.  
  10665. // Infection Bomb: Green Blast
  10666. create_blast(const Float:originF[3])
  10667. {
  10668.     // Smallest ring
  10669.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10670.     write_byte(TE_BEAMCYLINDER) // TE id
  10671.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10672.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10673.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10674.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10675.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10676.     engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
  10677.     write_short(g_exploSpr) // sprite
  10678.     write_byte(0) // startframe
  10679.     write_byte(0) // framerate
  10680.     write_byte(4) // life
  10681.     write_byte(60) // width
  10682.     write_byte(0) // noise
  10683.     write_byte(0) // red
  10684.     write_byte(200) // green
  10685.     write_byte(0) // blue
  10686.     write_byte(200) // brightness
  10687.     write_byte(0) // speed
  10688.     message_end()
  10689.    
  10690.     // Medium ring
  10691.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10692.     write_byte(TE_BEAMCYLINDER) // TE id
  10693.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10694.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10695.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10696.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10697.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10698.     engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
  10699.     write_short(g_exploSpr) // sprite
  10700.     write_byte(0) // startframe
  10701.     write_byte(0) // framerate
  10702.     write_byte(4) // life
  10703.     write_byte(60) // width
  10704.     write_byte(0) // noise
  10705.     write_byte(0) // red
  10706.     write_byte(200) // green
  10707.     write_byte(0) // blue
  10708.     write_byte(200) // brightness
  10709.     write_byte(0) // speed
  10710.     message_end()
  10711.    
  10712.     // Largest ring
  10713.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10714.     write_byte(TE_BEAMCYLINDER) // TE id
  10715.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10716.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10717.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10718.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10719.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10720.     engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
  10721.     write_short(g_exploSpr) // sprite
  10722.     write_byte(0) // startframe
  10723.     write_byte(0) // framerate
  10724.     write_byte(4) // life
  10725.     write_byte(60) // width
  10726.     write_byte(0) // noise
  10727.     write_byte(0) // red
  10728.     write_byte(200) // green
  10729.     write_byte(0) // blue
  10730.     write_byte(200) // brightness
  10731.     write_byte(0) // speed
  10732.     message_end()
  10733. }
  10734.  
  10735. // Fire Grenade: Fire Blast
  10736. create_blast2(const Float:originF[3])
  10737. {
  10738.     // Smallest ring
  10739.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10740.     write_byte(TE_BEAMCYLINDER) // TE id
  10741.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10742.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10743.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10744.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10745.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10746.     engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
  10747.     write_short(g_exploSpr) // sprite
  10748.     write_byte(0) // startframe
  10749.     write_byte(0) // framerate
  10750.     write_byte(4) // life
  10751.     write_byte(60) // width
  10752.     write_byte(0) // noise
  10753.     write_byte(200) // red
  10754.     write_byte(100) // green
  10755.     write_byte(0) // blue
  10756.     write_byte(200) // brightness
  10757.     write_byte(0) // speed
  10758.     message_end()
  10759.    
  10760.     // Medium ring
  10761.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10762.     write_byte(TE_BEAMCYLINDER) // TE id
  10763.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10764.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10765.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10766.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10767.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10768.     engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
  10769.     write_short(g_exploSpr) // sprite
  10770.     write_byte(0) // startframe
  10771.     write_byte(0) // framerate
  10772.     write_byte(4) // life
  10773.     write_byte(60) // width
  10774.     write_byte(0) // noise
  10775.     write_byte(200) // red
  10776.     write_byte(50) // green
  10777.     write_byte(0) // blue
  10778.     write_byte(200) // brightness
  10779.     write_byte(0) // speed
  10780.     message_end()
  10781.    
  10782.     // Largest ring
  10783.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10784.     write_byte(TE_BEAMCYLINDER) // TE id
  10785.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10786.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10787.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10788.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10789.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10790.     engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
  10791.     write_short(g_exploSpr) // sprite
  10792.     write_byte(0) // startframe
  10793.     write_byte(0) // framerate
  10794.     write_byte(4) // life
  10795.     write_byte(60) // width
  10796.     write_byte(0) // noise
  10797.     write_byte(200) // red
  10798.     write_byte(0) // green
  10799.     write_byte(0) // blue
  10800.     write_byte(200) // brightness
  10801.     write_byte(0) // speed
  10802.     message_end()
  10803. }
  10804.  
  10805. // Frost Grenade: Freeze Blast
  10806. create_blast3(const Float:originF[3])
  10807. {
  10808.     // Smallest ring
  10809.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10810.     write_byte(TE_BEAMCYLINDER) // TE id
  10811.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10812.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10813.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10814.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10815.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10816.     engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
  10817.     write_short(g_exploSpr) // sprite
  10818.     write_byte(0) // startframe
  10819.     write_byte(0) // framerate
  10820.     write_byte(4) // life
  10821.     write_byte(60) // width
  10822.     write_byte(0) // noise
  10823.     write_byte(0) // red
  10824.     write_byte(100) // green
  10825.     write_byte(200) // blue
  10826.     write_byte(200) // brightness
  10827.     write_byte(0) // speed
  10828.     message_end()
  10829.    
  10830.     // Medium ring
  10831.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10832.     write_byte(TE_BEAMCYLINDER) // TE id
  10833.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10834.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10835.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10836.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10837.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10838.     engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
  10839.     write_short(g_exploSpr) // sprite
  10840.     write_byte(0) // startframe
  10841.     write_byte(0) // framerate
  10842.     write_byte(4) // life
  10843.     write_byte(60) // width
  10844.     write_byte(0) // noise
  10845.     write_byte(0) // red
  10846.     write_byte(100) // green
  10847.     write_byte(200) // blue
  10848.     write_byte(200) // brightness
  10849.     write_byte(0) // speed
  10850.     message_end()
  10851.    
  10852.     // Largest ring
  10853.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10854.     write_byte(TE_BEAMCYLINDER) // TE id
  10855.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10856.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10857.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10858.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10859.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10860.     engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
  10861.     write_short(g_exploSpr) // sprite
  10862.     write_byte(0) // startframe
  10863.     write_byte(0) // framerate
  10864.     write_byte(4) // life
  10865.     write_byte(60) // width
  10866.     write_byte(0) // noise
  10867.     write_byte(0) // red
  10868.     write_byte(100) // green
  10869.     write_byte(200) // blue
  10870.     write_byte(200) // brightness
  10871.     write_byte(0) // speed
  10872.     message_end()
  10873. }
  10874.  
  10875. // Fix Dead Attrib on scoreboard
  10876. FixDeadAttrib(id)
  10877. {
  10878.     message_begin(MSG_BROADCAST, g_msgScoreAttrib)
  10879.     write_byte(id) // id
  10880.     write_byte(0) // attrib
  10881.     message_end()
  10882. }
  10883.  
  10884. // Send Death Message for infections
  10885. SendDeathMsg(attacker, victim)
  10886. {
  10887.     message_begin(MSG_BROADCAST, g_msgDeathMsg)
  10888.     write_byte(attacker) // killer
  10889.     write_byte(victim) // victim
  10890.     write_byte(1) // headshot flag
  10891.     write_string("infection") // killer's weapon
  10892.     message_end()
  10893. }
  10894.  
  10895. // Update Player Frags and Deaths
  10896. UpdateFrags(attacker, victim, frags, deaths, scoreboard)
  10897. {
  10898.     // Set attacker frags
  10899.     set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) + frags))
  10900.    
  10901.     // Set victim deaths
  10902.     fm_cs_set_user_deaths(victim, cs_get_user_deaths(victim) + deaths)
  10903.    
  10904.     // Update scoreboard with attacker and victim info
  10905.     if (scoreboard)
  10906.     {
  10907.         message_begin(MSG_BROADCAST, g_msgScoreInfo)
  10908.         write_byte(attacker) // id
  10909.         write_short(pev(attacker, pev_frags)) // frags
  10910.         write_short(cs_get_user_deaths(attacker)) // deaths
  10911.         write_short(0) // class?
  10912.         write_short(fm_cs_get_user_team(attacker)) // team
  10913.         message_end()
  10914.        
  10915.         message_begin(MSG_BROADCAST, g_msgScoreInfo)
  10916.         write_byte(victim) // id
  10917.         write_short(pev(victim, pev_frags)) // frags
  10918.         write_short(cs_get_user_deaths(victim)) // deaths
  10919.         write_short(0) // class?
  10920.         write_short(fm_cs_get_user_team(victim)) // team
  10921.         message_end()
  10922.     }
  10923. }
  10924.  
  10925. // Remove Player Frags (when Nemesis/Survivor ignore_frags cvar is enabled)
  10926. RemoveFrags(attacker, victim)
  10927. {
  10928.     // Remove attacker frags
  10929.     set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) - 1))
  10930.    
  10931.     // Remove victim deaths
  10932.     fm_cs_set_user_deaths(victim, cs_get_user_deaths(victim) - 1)
  10933. }
  10934.  
  10935. // Plays a sound on clients
  10936. PlaySound(const sound[])
  10937. {
  10938.     if (equal(sound[strlen(sound)-4], ".mp3"))
  10939.         client_cmd(0, "mp3 play ^"sound/%s^"", sound)
  10940.     else
  10941.         client_cmd(0, "spk ^"%s^"", sound)
  10942. }
  10943.  
  10944. // Prints a colored message to target (use 0 for everyone), supports ML formatting.
  10945. // Note: I still need to make something like gungame's LANG_PLAYER_C to avoid unintended
  10946. // argument replacement when a function passes -1 (it will be considered a LANG_PLAYER)
  10947. zp_colored_print(target, const message[], any:...)
  10948. {
  10949.     static buffer[512], i, argscount
  10950.     argscount = numargs()
  10951.    
  10952.     // Send to everyone
  10953.     if (!target)
  10954.     {
  10955.         static player
  10956.         for (player = 1; player <= g_maxplayers; player++)
  10957.         {
  10958.             // Not connected
  10959.             if (!g_isconnected[player])
  10960.                 continue;
  10961.            
  10962.             // Remember changed arguments
  10963.             static changed[5], changedcount // [5] = max LANG_PLAYER occurencies
  10964.             changedcount = 0
  10965.            
  10966.             // Replace LANG_PLAYER with player id
  10967.             for (i = 2; i < argscount; i++)
  10968.             {
  10969.                 if (getarg(i) == LANG_PLAYER)
  10970.                 {
  10971.                     setarg(i, 0, player)
  10972.                     changed[changedcount] = i
  10973.                     changedcount++
  10974.                 }
  10975.             }
  10976.            
  10977.             // Format message for player
  10978.             vformat(buffer, charsmax(buffer), message, 3)
  10979.            
  10980.             // Send it
  10981.             message_begin(MSG_ONE_UNRELIABLE, g_msgSayText, _, player)
  10982.             write_byte(player)
  10983.             write_string(buffer)
  10984.             message_end()
  10985.            
  10986.             // Replace back player id's with LANG_PLAYER
  10987.             for (i = 0; i < changedcount; i++)
  10988.                 setarg(changed[i], 0, LANG_PLAYER)
  10989.         }
  10990.     }
  10991.     // Send to specific target
  10992.     else
  10993.     {
  10994.         /*
  10995.         // Not needed since you should set the ML argument
  10996.         // to the player's id for a targeted print message
  10997.        
  10998.         // Replace LANG_PLAYER with player id
  10999.         for (i = 2; i < argscount; i++)
  11000.         {
  11001.             if (getarg(i) == LANG_PLAYER)
  11002.                 setarg(i, 0, target)
  11003.         }
  11004.         */
  11005.        
  11006.         // Format message for player
  11007.         vformat(buffer, charsmax(buffer), message, 3)
  11008.        
  11009.         // Send it
  11010.         message_begin(MSG_ONE, g_msgSayText, _, target)
  11011.         write_byte(target)
  11012.         write_string(buffer)
  11013.         message_end()
  11014.     }
  11015. }
  11016.  
  11017. /*================================================================================
  11018.  [Stocks]
  11019. =================================================================================*/
  11020.  
  11021. // Set an entity's key value (from fakemeta_util)
  11022. stock fm_set_kvd(entity, const key[], const value[], const classname[])
  11023. {
  11024.     set_kvd(0, KV_ClassName, classname)
  11025.     set_kvd(0, KV_KeyName, key)
  11026.     set_kvd(0, KV_Value, value)
  11027.     set_kvd(0, KV_fHandled, 0)
  11028.  
  11029.     dllfunc(DLLFunc_KeyValue, entity, 0)
  11030. }
  11031.  
  11032. // Set entity's rendering type (from fakemeta_util)
  11033. stock fm_set_rendering(entity, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16)
  11034. {
  11035.     static Float:color[3]
  11036.     color[0] = float(r)
  11037.     color[1] = float(g)
  11038.     color[2] = float(b)
  11039.    
  11040.     set_pev(entity, pev_renderfx, fx)
  11041.     set_pev(entity, pev_rendercolor, color)
  11042.     set_pev(entity, pev_rendermode, render)
  11043.     set_pev(entity, pev_renderamt, float(amount))
  11044. }
  11045.  
  11046. // Get entity's speed (from fakemeta_util)
  11047. stock fm_get_speed(entity)
  11048. {
  11049.     static Float:velocity[3]
  11050.     pev(entity, pev_velocity, velocity)
  11051.    
  11052.     return floatround(vector_length(velocity));
  11053. }
  11054.  
  11055. // Get entity's aim origins (from fakemeta_util)
  11056. stock fm_get_aim_origin(id, Float:origin[3])
  11057. {
  11058.     static Float:origin1F[3], Float:origin2F[3]
  11059.     pev(id, pev_origin, origin1F)
  11060.     pev(id, pev_view_ofs, origin2F)
  11061.     xs_vec_add(origin1F, origin2F, origin1F)
  11062.  
  11063.     pev(id, pev_v_angle, origin2F);
  11064.     engfunc(EngFunc_MakeVectors, origin2F)
  11065.     global_get(glb_v_forward, origin2F)
  11066.     xs_vec_mul_scalar(origin2F, 9999.0, origin2F)
  11067.     xs_vec_add(origin1F, origin2F, origin2F)
  11068.  
  11069.     engfunc(EngFunc_TraceLine, origin1F, origin2F, 0, id, 0)
  11070.     get_tr2(0, TR_vecEndPos, origin)
  11071. }
  11072.  
  11073. // Find entity by its owner (from fakemeta_util)
  11074. stock fm_find_ent_by_owner(entity, const classname[], owner)
  11075. {
  11076.     while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", classname)) && pev(entity, pev_owner) != owner) { /* keep looping */ }
  11077.     return entity;
  11078. }
  11079.  
  11080. // Set player's health (from fakemeta_util)
  11081. stock fm_set_user_health(id, health)
  11082. {
  11083.     (health > 0) ? set_pev(id, pev_health, float(health)) : dllfunc(DLLFunc_ClientKill, id);
  11084. }
  11085.  
  11086. // Give an item to a player (from fakemeta_util)
  11087. stock fm_give_item(id, const item[])
  11088. {
  11089.     static ent
  11090.     ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, item))
  11091.     if (!pev_valid(ent)) return;
  11092.    
  11093.     static Float:originF[3]
  11094.     pev(id, pev_origin, originF)
  11095.     set_pev(ent, pev_origin, originF)
  11096.     set_pev(ent, pev_spawnflags, pev(ent, pev_spawnflags) | SF_NORESPAWN)
  11097.     dllfunc(DLLFunc_Spawn, ent)
  11098.    
  11099.     static save
  11100.     save = pev(ent, pev_solid)
  11101.     dllfunc(DLLFunc_Touch, ent, id)
  11102.     if (pev(ent, pev_solid) != save)
  11103.         return;
  11104.    
  11105.     engfunc(EngFunc_RemoveEntity, ent)
  11106. }
  11107.  
  11108. // Strip user weapons (from fakemeta_util)
  11109. stock fm_strip_user_weapons(id)
  11110. {
  11111.     static ent
  11112.     ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "player_weaponstrip"))
  11113.     if (!pev_valid(ent)) return;
  11114.    
  11115.     dllfunc(DLLFunc_Spawn, ent)
  11116.     dllfunc(DLLFunc_Use, ent, id)
  11117.     engfunc(EngFunc_RemoveEntity, ent)
  11118. }
  11119.  
  11120. // Collect random spawn points
  11121. stock load_spawns()
  11122. {
  11123.     // Check for CSDM spawns of the current map
  11124.     new cfgdir[32], mapname[32], filepath[100], linedata[64]
  11125.     get_configsdir(cfgdir, charsmax(cfgdir))
  11126.     get_mapname(mapname, charsmax(mapname))
  11127.     formatex(filepath, charsmax(filepath), "%s/csdm/%s.spawns.cfg", cfgdir, mapname)
  11128.    
  11129.     // Load CSDM spawns if present
  11130.     if (file_exists(filepath))
  11131.     {
  11132.         new csdmdata[10][6], file = fopen(filepath,"rt")
  11133.        
  11134.         while (file && !feof(file))
  11135.         {
  11136.             fgets(file, linedata, charsmax(linedata))
  11137.            
  11138.             // invalid spawn
  11139.             if(!linedata[0] || str_count(linedata,' ') < 2) continue;
  11140.            
  11141.             // get spawn point data
  11142.             parse(linedata,csdmdata[0],5,csdmdata[1],5,csdmdata[2],5,csdmdata[3],5,csdmdata[4],5,csdmdata[5],5,csdmdata[6],5,csdmdata[7],5,csdmdata[8],5,csdmdata[9],5)
  11143.            
  11144.             // origin
  11145.             g_spawns[g_spawnCount][0] = floatstr(csdmdata[0])
  11146.             g_spawns[g_spawnCount][1] = floatstr(csdmdata[1])
  11147.             g_spawns[g_spawnCount][2] = floatstr(csdmdata[2])
  11148.            
  11149.             // increase spawn count
  11150.             g_spawnCount++
  11151.             if (g_spawnCount >= sizeof g_spawns) break;
  11152.         }
  11153.         if (file) fclose(file)
  11154.     }
  11155.     else
  11156.     {
  11157.         // Collect regular spawns
  11158.         collect_spawns_ent("info_player_start")
  11159.         collect_spawns_ent("info_player_deathmatch")
  11160.     }
  11161.    
  11162.     // Collect regular spawns for non-random spawning unstuck
  11163.     collect_spawns_ent2("info_player_start")
  11164.     collect_spawns_ent2("info_player_deathmatch")
  11165. }
  11166.  
  11167. // Collect spawn points from entity origins
  11168. stock collect_spawns_ent(const classname[])
  11169. {
  11170.     new ent = -1
  11171.     while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", classname)) != 0)
  11172.     {
  11173.         // get origin
  11174.         new Float:originF[3]
  11175.         pev(ent, pev_origin, originF)
  11176.         g_spawns[g_spawnCount][0] = originF[0]
  11177.         g_spawns[g_spawnCount][1] = originF[1]
  11178.         g_spawns[g_spawnCount][2] = originF[2]
  11179.        
  11180.         // increase spawn count
  11181.         g_spawnCount++
  11182.         if (g_spawnCount >= sizeof g_spawns) break;
  11183.     }
  11184. }
  11185.  
  11186. // Collect spawn points from entity origins
  11187. stock collect_spawns_ent2(const classname[])
  11188. {
  11189.     new ent = -1
  11190.     while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", classname)) != 0)
  11191.     {
  11192.         // get origin
  11193.         new Float:originF[3]
  11194.         pev(ent, pev_origin, originF)
  11195.         g_spawns2[g_spawnCount2][0] = originF[0]
  11196.         g_spawns2[g_spawnCount2][1] = originF[1]
  11197.         g_spawns2[g_spawnCount2][2] = originF[2]
  11198.        
  11199.         // increase spawn count
  11200.         g_spawnCount2++
  11201.         if (g_spawnCount2 >= sizeof g_spawns2) break;
  11202.     }
  11203. }
  11204.  
  11205. // Drop primary/secondary weapons
  11206. stock drop_weapons(id, dropwhat)
  11207. {
  11208.     // Get user weapons
  11209.     static weapons[32], num, i, weaponid
  11210.     num = 0 // reset passed weapons count (bugfix)
  11211.     get_user_weapons(id, weapons, num)
  11212.    
  11213.     // Loop through them and drop primaries or secondaries
  11214.     for (i = 0; i < num; i++)
  11215.     {
  11216.         // Prevent re-indexing the array
  11217.         weaponid = weapons[i]
  11218.        
  11219.         if ((dropwhat == 1 && ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)) || (dropwhat == 2 && ((1<<weaponid) & SECONDARY_WEAPONS_BIT_SUM)))
  11220.         {
  11221.             // Get weapon entity
  11222.             static wname[32], weapon_ent
  11223.             get_weaponname(weaponid, wname, charsmax(wname))
  11224.             weapon_ent = fm_find_ent_by_owner(-1, wname, id)
  11225.            
  11226.             // Hack: store weapon bpammo on PEV_ADDITIONAL_AMMO
  11227.             set_pev(weapon_ent, PEV_ADDITIONAL_AMMO, cs_get_user_bpammo(id, weaponid))
  11228.            
  11229.             // Player drops the weapon and looses his bpammo
  11230.             engclient_cmd(id, "drop", wname)
  11231.             cs_set_user_bpammo(id, weaponid, 0)
  11232.         }
  11233.     }
  11234. }
  11235.  
  11236. // Stock by (probably) Twilight Suzuka -counts number of chars in a string
  11237. stock str_count(const str[], searchchar)
  11238. {
  11239.     new count, i, len = strlen(str)
  11240.    
  11241.     for (i = 0; i <= len; i++)
  11242.     {
  11243.         if(str[i] == searchchar)
  11244.             count++
  11245.     }
  11246.    
  11247.     return count;
  11248. }
  11249.  
  11250. // Checks if a space is vacant (credits to VEN)
  11251. stock is_hull_vacant(Float:origin[3], hull)
  11252. {
  11253.     engfunc(EngFunc_TraceHull, origin, origin, 0, hull, 0, 0)
  11254.    
  11255.     if (!get_tr2(0, TR_StartSolid) && !get_tr2(0, TR_AllSolid) && get_tr2(0, TR_InOpen))
  11256.         return true;
  11257.    
  11258.     return false;
  11259. }
  11260.  
  11261. // Check if a player is stuck (credits to VEN)
  11262. stock is_player_stuck(id)
  11263. {
  11264.     static Float:originF[3]
  11265.     pev(id, pev_origin, originF)
  11266.    
  11267.     engfunc(EngFunc_TraceHull, originF, originF, 0, (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN, id, 0)
  11268.    
  11269.     if (get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen))
  11270.         return true;
  11271.    
  11272.     return false;
  11273. }
  11274.  
  11275. // Simplified get_weaponid (CS only)
  11276. stock cs_weapon_name_to_id(const weapon[])
  11277. {
  11278.     static i
  11279.     for (i = 0; i < sizeof WEAPONENTNAMES; i++)
  11280.     {
  11281.         if (equal(weapon, WEAPONENTNAMES[i]))
  11282.             return i;
  11283.     }
  11284.    
  11285.     return 0;
  11286. }
  11287.  
  11288. // Get User Current Weapon Entity
  11289. stock fm_cs_get_current_weapon_ent(id)
  11290. {
  11291.     // Prevent server crash if entity's private data not initalized
  11292.     if (pev_valid(id) != PDATA_SAFE)
  11293.         return -1;
  11294.    
  11295.     return get_pdata_cbase(id, OFFSET_ACTIVE_ITEM, OFFSET_LINUX);
  11296. }
  11297.  
  11298. // Get Weapon Entity's Owner
  11299. stock fm_cs_get_weapon_ent_owner(ent)
  11300. {
  11301.     // Prevent server crash if entity's private data not initalized
  11302.     if (pev_valid(ent) != PDATA_SAFE)
  11303.         return -1;
  11304.    
  11305.     return get_pdata_cbase(ent, OFFSET_WEAPONOWNER, OFFSET_LINUX_WEAPONS);
  11306. }
  11307.  
  11308. // Set User Deaths
  11309. stock fm_cs_set_user_deaths(id, value)
  11310. {
  11311.     // Prevent server crash if entity's private data not initalized
  11312.     if (pev_valid(id) != PDATA_SAFE)
  11313.         return;
  11314.    
  11315.     set_pdata_int(id, OFFSET_CSDEATHS, value, OFFSET_LINUX)
  11316. }
  11317.  
  11318. // Get User Team
  11319. stock fm_cs_get_user_team(id)
  11320. {
  11321.     // Prevent server crash if entity's private data not initalized
  11322.     if (pev_valid(id) != PDATA_SAFE)
  11323.         return FM_CS_TEAM_UNASSIGNED;
  11324.    
  11325.     return get_pdata_int(id, OFFSET_CSTEAMS, OFFSET_LINUX);
  11326. }
  11327.  
  11328. // Set a Player's Team
  11329. stock fm_cs_set_user_team(id, team)
  11330. {
  11331.     // Prevent server crash if entity's private data not initalized
  11332.     if (pev_valid(id) != PDATA_SAFE)
  11333.         return;
  11334.    
  11335.     set_pdata_int(id, OFFSET_CSTEAMS, team, OFFSET_LINUX)
  11336. }
  11337.  
  11338. // Set User Money
  11339. stock fm_cs_set_user_money(id, value)
  11340. {
  11341.     // Prevent server crash if entity's private data not initalized
  11342.     if (pev_valid(id) != PDATA_SAFE)
  11343.         return;
  11344.    
  11345.     set_pdata_int(id, OFFSET_CSMONEY, value, OFFSET_LINUX)
  11346. }
  11347.  
  11348. // Set User Flashlight Batteries
  11349. stock fm_cs_set_user_batteries(id, value)
  11350. {
  11351.     // Prevent server crash if entity's private data not initalized
  11352.     if (pev_valid(id) != PDATA_SAFE)
  11353.         return;
  11354.    
  11355.     set_pdata_int(id, OFFSET_FLASHLIGHT_BATTERY, value, OFFSET_LINUX)
  11356. }
  11357.  
  11358. // Update Player's Team on all clients (adding needed delays)
  11359. stock fm_user_team_update(id)
  11360. {
  11361.     static Float:current_time
  11362.     current_time = get_gametime()
  11363.    
  11364.     if (current_time - g_teams_targettime >= 0.1)
  11365.     {
  11366.         set_task(0.1, "fm_cs_set_user_team_msg", id+TASK_TEAM)
  11367.         g_teams_targettime = current_time + 0.1
  11368.     }
  11369.     else
  11370.     {
  11371.         set_task((g_teams_targettime + 0.1) - current_time, "fm_cs_set_user_team_msg", id+TASK_TEAM)
  11372.         g_teams_targettime = g_teams_targettime + 0.1
  11373.     }
  11374. }
  11375.  
  11376. // Send User Team Message
  11377. public fm_cs_set_user_team_msg(taskid)
  11378. {
  11379.     // Note to self: this next message can now be received by other plugins
  11380.    
  11381.     // Set the switching team flag
  11382.     g_switchingteam = true
  11383.    
  11384.     // Tell everyone my new team
  11385.     emessage_begin(MSG_ALL, g_msgTeamInfo)
  11386.     ewrite_byte(ID_TEAM) // player
  11387.     ewrite_string(CS_TEAM_NAMES[fm_cs_get_user_team(ID_TEAM)]) // team
  11388.     emessage_end()
  11389.    
  11390.     // Done switching team
  11391.     g_switchingteam = false
  11392. }
  11393.  
  11394. // Set the precached model index (updates hitboxes server side)
  11395. stock fm_cs_set_user_model_index(id, value)
  11396. {
  11397.     // Prevent server crash if entity's private data not initalized
  11398.     if (pev_valid(id) != PDATA_SAFE)
  11399.         return;
  11400.    
  11401.     set_pdata_int(id, OFFSET_MODELINDEX, value, OFFSET_LINUX)
  11402. }
  11403.  
  11404. // Set Player Model on Entity
  11405. stock fm_set_playermodel_ent(id)
  11406. {
  11407.     // Make original player entity invisible without hiding shadows or firing effects
  11408.     fm_set_rendering(id, kRenderFxNone, 255, 255, 255, kRenderTransTexture, 1)
  11409.    
  11410.     // Format model string
  11411.     static model[100]
  11412.     formatex(model, charsmax(model), "models/player/%s/%s.mdl", g_playermodel[id], g_playermodel[id])
  11413.    
  11414.     // Set model on entity or make a new one if unexistant
  11415.     if (!pev_valid(g_ent_playermodel[id]))
  11416.     {
  11417.         g_ent_playermodel[id] = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
  11418.         if (!pev_valid(g_ent_playermodel[id])) return;
  11419.        
  11420.         set_pev(g_ent_playermodel[id], pev_classname, MODEL_ENT_CLASSNAME)
  11421.         set_pev(g_ent_playermodel[id], pev_movetype, MOVETYPE_FOLLOW)
  11422.         set_pev(g_ent_playermodel[id], pev_aiment, id)
  11423.         set_pev(g_ent_playermodel[id], pev_owner, id)
  11424.     }
  11425.    
  11426.     engfunc(EngFunc_SetModel, g_ent_playermodel[id], model)
  11427. }
  11428.  
  11429. // Set Weapon Model on Entity
  11430. stock fm_set_weaponmodel_ent(id)
  11431. {
  11432.     // Get player's p_ weapon model
  11433.     static model[100]
  11434.     pev(id, pev_weaponmodel2, model, charsmax(model))
  11435.    
  11436.     // Set model on entity or make a new one if unexistant
  11437.     if (!pev_valid(g_ent_weaponmodel[id]))
  11438.     {
  11439.         g_ent_weaponmodel[id] = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
  11440.         if (!pev_valid(g_ent_weaponmodel[id])) return;
  11441.        
  11442.         set_pev(g_ent_weaponmodel[id], pev_classname, WEAPON_ENT_CLASSNAME)
  11443.         set_pev(g_ent_weaponmodel[id], pev_movetype, MOVETYPE_FOLLOW)
  11444.         set_pev(g_ent_weaponmodel[id], pev_aiment, id)
  11445.         set_pev(g_ent_weaponmodel[id], pev_owner, id)
  11446.     }
  11447.    
  11448.     engfunc(EngFunc_SetModel, g_ent_weaponmodel[id], model)
  11449. }
  11450.  
  11451. // Remove Custom Model Entities
  11452. stock fm_remove_model_ents(id)
  11453. {
  11454.     // Remove "playermodel" ent if present
  11455.     if (pev_valid(g_ent_playermodel[id]))
  11456.     {
  11457.         engfunc(EngFunc_RemoveEntity, g_ent_playermodel[id])
  11458.         g_ent_playermodel[id] = 0
  11459.     }
  11460.     // Remove "weaponmodel" ent if present
  11461.     if (pev_valid(g_ent_weaponmodel[id]))
  11462.     {
  11463.         engfunc(EngFunc_RemoveEntity, g_ent_weaponmodel[id])
  11464.         g_ent_weaponmodel[id] = 0
  11465.     }
  11466. }
  11467.  
  11468. // Set User Model
  11469. public fm_cs_set_user_model(taskid)
  11470. {
  11471.     set_user_info(ID_MODEL, "model", g_playermodel[ID_MODEL])
  11472. }
  11473.  
  11474. // Get User Model -model passed byref-
  11475. stock fm_cs_get_user_model(player, model[], len)
  11476. {
  11477.     get_user_info(player, "model", model, len)
  11478. }
  11479.  
  11480. // Update Player's Model on all clients (adding needed delays)
  11481. public fm_user_model_update(taskid)
  11482. {
  11483.     static Float:current_time
  11484.     current_time = get_gametime()
  11485.    
  11486.     if (current_time - g_models_targettime >= g_modelchange_delay)
  11487.     {
  11488.         fm_cs_set_user_model(taskid)
  11489.         g_models_targettime = current_time
  11490.     }
  11491.     else
  11492.     {
  11493.         set_task((g_models_targettime + g_modelchange_delay) - current_time, "fm_cs_set_user_model", taskid)
  11494.         g_models_targettime = g_models_targettime + g_modelchange_delay
  11495.     }
  11496. }
Add Comment
Please, Sign In to add comment