Guest User

Zombie Plague 4.3 Fix5a

a guest
Nov 22nd, 2014
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 355.35 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. Join spec
  3536.     if (!g_isalive[id] || !get_pcvar_num(cvar_blocksuicide) || (userflags & g_access_flag[ACCESS_ADMIN_MENU]))
  3537.         len += formatex(menu[len], charsmax(menu) - len, "\r6.\w %L^n^n", id, "MENU_SPECTATOR")
  3538.     else
  3539.         len += formatex(menu[len], charsmax(menu) - len, "\d6. %L^n^n", id, "MENU_SPECTATOR")
  3540.    
  3541.     // 9. Admin menu
  3542.     if (userflags & g_access_flag[ACCESS_ADMIN_MENU])
  3543.         len += formatex(menu[len], charsmax(menu) - len, "\r9.\w %L", id, "MENU_ADMIN")
  3544.     else
  3545.         len += formatex(menu[len], charsmax(menu) - len, "\d9. %L", id, "MENU_ADMIN")
  3546.    
  3547.     // 0. Exit
  3548.     len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
  3549.    
  3550.     // Fix for AMXX custom menus
  3551.     if (pev_valid(id) == PDATA_SAFE)
  3552.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3553.    
  3554.     show_menu(id, KEYSMENU, menu, -1, "Game Menu")
  3555. }
  3556.  
  3557. // Buy Menu 1
  3558. public show_menu_buy1(taskid)
  3559. {
  3560.     // Get player's id
  3561.     static id
  3562.     (taskid > g_maxplayers) ? (id = ID_SPAWN) : (id = taskid);
  3563.    
  3564.     // Player dead?
  3565.     if (!g_isalive[id])
  3566.         return;
  3567.    
  3568.     // Zombies or survivors get no guns
  3569.     if (g_zombie[id] || g_survivor[id])
  3570.         return;
  3571.    
  3572.     // Bots pick their weapons randomly / Random weapons setting enabled
  3573.     if (get_pcvar_num(cvar_randweapons) || g_isbot[id])
  3574.     {
  3575.         buy_primary_weapon(id, random_num(0, ArraySize(g_primary_items) - 1))
  3576.         menu_buy2(id, random_num(0, ArraySize(g_secondary_items) - 1))
  3577.         return;
  3578.     }
  3579.    
  3580.     // Automatic selection enabled for player and menu called on spawn event
  3581.     if (WPN_AUTO_ON && taskid > g_maxplayers)
  3582.     {
  3583.         buy_primary_weapon(id, WPN_AUTO_PRI)
  3584.         menu_buy2(id, WPN_AUTO_SEC)
  3585.         return;
  3586.     }
  3587.    
  3588.     static menu[300], len, weap, maxloops
  3589.     len = 0
  3590.     maxloops = min(WPN_STARTID+7, WPN_MAXIDS)
  3591.    
  3592.     // Title
  3593.     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))
  3594.    
  3595.     // 1-7. Weapon List
  3596.     for (weap = WPN_STARTID; weap < maxloops; weap++)
  3597.         len += formatex(menu[len], charsmax(menu) - len, "\r%d.\w %s^n", weap-WPN_STARTID+1, WEAPONNAMES[ArrayGetCell(g_primary_weaponids, weap)])
  3598.    
  3599.     // 8. Auto Select
  3600.     len += formatex(menu[len], charsmax(menu) - len, "^n\r8.\w %L \y[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  3601.    
  3602.     // 9. Next/Back - 0. Exit
  3603.     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")
  3604.    
  3605.     // Fix for AMXX custom menus
  3606.     if (pev_valid(id) == PDATA_SAFE)
  3607.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3608.    
  3609.     show_menu(id, KEYSMENU, menu, -1, "Buy Menu 1")
  3610. }
  3611.  
  3612. // Buy Menu 2
  3613. show_menu_buy2(id)
  3614. {
  3615.     // Player dead?
  3616.     if (!g_isalive[id])
  3617.         return;
  3618.    
  3619.     static menu[250], len, weap, maxloops
  3620.     len = 0
  3621.     maxloops = ArraySize(g_secondary_items)
  3622.    
  3623.     // Title
  3624.     len += formatex(menu[len], charsmax(menu) - len, "\y%L^n", id, "MENU_BUY2_TITLE")
  3625.    
  3626.     // 1-6. Weapon List
  3627.     for (weap = 0; weap < maxloops; weap++)
  3628.         len += formatex(menu[len], charsmax(menu) - len, "^n\r%d.\w %s", weap+1, WEAPONNAMES[ArrayGetCell(g_secondary_weaponids, weap)])
  3629.    
  3630.     // 8. Auto Select
  3631.     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")
  3632.    
  3633.     // 0. Exit
  3634.     len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
  3635.    
  3636.     // Fix for AMXX custom menus
  3637.     if (pev_valid(id) == PDATA_SAFE)
  3638.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3639.    
  3640.     show_menu(id, KEYSMENU, menu, -1, "Buy Menu 2")
  3641. }
  3642.  
  3643. // Extra Items Menu
  3644. show_menu_extras(id)
  3645. {
  3646.     // Player dead?
  3647.     if (!g_isalive[id])
  3648.         return;
  3649.    
  3650.     static menuid, menu[128], item, team, buffer[32]
  3651.    
  3652.     // Title
  3653.     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")
  3654.     menuid = menu_create(menu, "menu_extras")
  3655.    
  3656.     // Item List
  3657.     for (item = 0; item < g_extraitem_i; item++)
  3658.     {
  3659.         // Retrieve item's team
  3660.         team = ArrayGetCell(g_extraitem_team, item)
  3661.        
  3662.         // Item not available to player's team/class
  3663.         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)))
  3664.             continue;
  3665.        
  3666.         // Check if it's one of the hardcoded items, check availability, set translated caption
  3667.         switch (item)
  3668.         {
  3669.             case EXTRA_NVISION:
  3670.             {
  3671.                 if (!get_pcvar_num(cvar_extranvision)) continue;
  3672.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA1")
  3673.             }
  3674.             case EXTRA_ANTIDOTE:
  3675.             {
  3676.                 if (!get_pcvar_num(cvar_extraantidote) || g_antidotecounter >= get_pcvar_num(cvar_antidotelimit)) continue;
  3677.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA2")
  3678.             }
  3679.             case EXTRA_MADNESS:
  3680.             {
  3681.                 if (!get_pcvar_num(cvar_extramadness) || g_madnesscounter >= get_pcvar_num(cvar_madnesslimit)) continue;
  3682.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA3")
  3683.             }
  3684.             case EXTRA_INFBOMB:
  3685.             {
  3686.                 if (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit)) continue;
  3687.                 formatex(buffer, charsmax(buffer), "%L", id, "MENU_EXTRA4")
  3688.             }
  3689.             default:
  3690.             {
  3691.                 if (item >= EXTRA_WEAPONS_STARTID && item <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)) continue;
  3692.                 ArrayGetString(g_extraitem_name, item, buffer, charsmax(buffer))
  3693.             }
  3694.         }
  3695.        
  3696.         // Add Item Name and Cost
  3697.         formatex(menu, charsmax(menu), "%s \y%d %L", buffer, ArrayGetCell(g_extraitem_cost, item), id, "AMMO_PACKS2")
  3698.         buffer[0] = item
  3699.         buffer[1] = 0
  3700.         menu_additem(menuid, menu, buffer)
  3701.     }
  3702.    
  3703.     // No items to display?
  3704.     if (menu_items(menuid) <= 0)
  3705.     {
  3706.         zp_colored_print(id, "^x04[ZP]^x01 %L", id ,"CMD_NOT_EXTRAS")
  3707.         menu_destroy(menuid)
  3708.         return;
  3709.     }
  3710.    
  3711.     // Back - Next - Exit
  3712.     formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3713.     menu_setprop(menuid, MPROP_BACKNAME, menu)
  3714.     formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3715.     menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3716.     formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3717.     menu_setprop(menuid, MPROP_EXITNAME, menu)
  3718.        
  3719.     // If remembered page is greater than number of pages, clamp down the value
  3720.     MENU_PAGE_EXTRAS = min(MENU_PAGE_EXTRAS, menu_pages(menuid)-1)
  3721.    
  3722.     // Fix for AMXX custom menus
  3723.     if (pev_valid(id) == PDATA_SAFE)
  3724.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3725.    
  3726.     menu_display(id, menuid, MENU_PAGE_EXTRAS)
  3727. }
  3728.  
  3729. // Zombie Class Menu
  3730. public show_menu_zclass(id)
  3731. {
  3732.     // Player disconnected
  3733.     if (!g_isconnected[id])
  3734.         return;
  3735.    
  3736.     // Bots pick their zombie class randomly
  3737.     if (g_isbot[id])
  3738.     {
  3739.         g_zombieclassnext[id] = random_num(0, g_zclass_i - 1)
  3740.         return;
  3741.     }
  3742.    
  3743.     static menuid, menu[128], class, buffer[32], buffer2[32]
  3744.    
  3745.     // Title
  3746.     formatex(menu, charsmax(menu), "%L\r", id, "MENU_ZCLASS_TITLE")
  3747.     menuid = menu_create(menu, "menu_zclass")
  3748.    
  3749.     // Class List
  3750.     for (class = 0; class < g_zclass_i; class++)
  3751.     {
  3752.         // Retrieve name and info
  3753.         ArrayGetString(g_zclass_name, class, buffer, charsmax(buffer))
  3754.         ArrayGetString(g_zclass_info, class, buffer2, charsmax(buffer2))
  3755.        
  3756.         // Add to menu
  3757.         if (class == g_zombieclassnext[id])
  3758.             formatex(menu, charsmax(menu), "\d%s %s", buffer, buffer2)
  3759.         else
  3760.             formatex(menu, charsmax(menu), "%s \y%s", buffer, buffer2)
  3761.        
  3762.         buffer[0] = class
  3763.         buffer[1] = 0
  3764.         menu_additem(menuid, menu, buffer)
  3765.     }
  3766.    
  3767.     // Back - Next - Exit
  3768.     formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3769.     menu_setprop(menuid, MPROP_BACKNAME, menu)
  3770.     formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3771.     menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3772.     formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3773.     menu_setprop(menuid, MPROP_EXITNAME, menu)
  3774.    
  3775.     // If remembered page is greater than number of pages, clamp down the value
  3776.     MENU_PAGE_ZCLASS = min(MENU_PAGE_ZCLASS, menu_pages(menuid)-1)
  3777.    
  3778.     // Fix for AMXX custom menus
  3779.     if (pev_valid(id) == PDATA_SAFE)
  3780.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3781.    
  3782.     menu_display(id, menuid, MENU_PAGE_ZCLASS)
  3783. }
  3784.  
  3785. // Help Menu
  3786. show_menu_info(id)
  3787. {
  3788.     // Player disconnected?
  3789.     if (!g_isconnected[id])
  3790.         return;
  3791.    
  3792.     static menu[150]
  3793.    
  3794.     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")
  3795.    
  3796.     // Fix for AMXX custom menus
  3797.     if (pev_valid(id) == PDATA_SAFE)
  3798.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3799.    
  3800.     show_menu(id, KEYSMENU, menu, -1, "Mod Info")
  3801. }
  3802.  
  3803. // Admin Menu
  3804. show_menu_admin(id)
  3805. {
  3806.     // Player disconnected?
  3807.     if (!g_isconnected[id])
  3808.         return;
  3809.    
  3810.     static menu[250], len, userflags
  3811.     len = 0
  3812.     userflags = get_user_flags(id)
  3813.    
  3814.     // Title
  3815.     len += formatex(menu[len], charsmax(menu) - len, "\y%L^n^n", id, "MENU_ADMIN_TITLE")
  3816.    
  3817.     // 1. Zombiefy/Humanize command
  3818.     if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
  3819.         len += formatex(menu[len], charsmax(menu) - len, "\r1.\w %L^n", id, "MENU_ADMIN1")
  3820.     else
  3821.         len += formatex(menu[len], charsmax(menu) - len, "\d1. %L^n", id, "MENU_ADMIN1")
  3822.    
  3823.     // 2. Nemesis command
  3824.     if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
  3825.         len += formatex(menu[len], charsmax(menu) - len, "\r2.\w %L^n", id, "MENU_ADMIN2")
  3826.     else
  3827.         len += formatex(menu[len], charsmax(menu) - len, "\d2. %L^n", id, "MENU_ADMIN2")
  3828.    
  3829.     // 3. Survivor command
  3830.     if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
  3831.         len += formatex(menu[len], charsmax(menu) - len, "\r3.\w %L^n", id, "MENU_ADMIN3")
  3832.     else
  3833.         len += formatex(menu[len], charsmax(menu) - len, "\d3. %L^n", id, "MENU_ADMIN3")
  3834.    
  3835.     // 4. Respawn command
  3836.     if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  3837.         len += formatex(menu[len], charsmax(menu) - len, "\r4.\w %L^n", id, "MENU_ADMIN4")
  3838.     else
  3839.         len += formatex(menu[len], charsmax(menu) - len, "\d4. %L^n", id, "MENU_ADMIN4")
  3840.    
  3841.     // 5. Swarm mode command
  3842.     if ((userflags & g_access_flag[ACCESS_MODE_SWARM]) && allowed_swarm())
  3843.         len += formatex(menu[len], charsmax(menu) - len, "\r5.\w %L^n", id, "MENU_ADMIN5")
  3844.     else
  3845.         len += formatex(menu[len], charsmax(menu) - len, "\d5. %L^n", id, "MENU_ADMIN5")
  3846.    
  3847.     // 6. Multi infection command
  3848.     if ((userflags & g_access_flag[ACCESS_MODE_MULTI]) && allowed_multi())
  3849.         len += formatex(menu[len], charsmax(menu) - len, "\r6.\w %L^n", id, "MENU_ADMIN6")
  3850.     else
  3851.         len += formatex(menu[len], charsmax(menu) - len, "\d6. %L^n", id, "MENU_ADMIN6")
  3852.    
  3853.     // 7. Plague mode command
  3854.     if ((userflags & g_access_flag[ACCESS_MODE_PLAGUE]) && allowed_plague())
  3855.         len += formatex(menu[len], charsmax(menu) - len, "\r7.\w %L^n", id, "MENU_ADMIN7")
  3856.     else
  3857.         len += formatex(menu[len], charsmax(menu) - len, "\d7. %L^n", id, "MENU_ADMIN7")
  3858.    
  3859.     // 0. Exit
  3860.     len += formatex(menu[len], charsmax(menu) - len, "^n\r0.\w %L", id, "MENU_EXIT")
  3861.    
  3862.     // Fix for AMXX custom menus
  3863.     if (pev_valid(id) == PDATA_SAFE)
  3864.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3865.    
  3866.     show_menu(id, KEYSMENU, menu, -1, "Admin Menu")
  3867. }
  3868.  
  3869. // Player List Menu
  3870. show_menu_player_list(id)
  3871. {
  3872.     // Player disconnected?
  3873.     if (!g_isconnected[id])
  3874.         return;
  3875.    
  3876.     static menuid, menu[128], player, userflags, buffer[2]
  3877.     userflags = get_user_flags(id)
  3878.    
  3879.     // Title
  3880.     switch (PL_ACTION)
  3881.     {
  3882.         case ACTION_ZOMBIEFY_HUMANIZE: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN1")
  3883.         case ACTION_MAKE_NEMESIS: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN2")
  3884.         case ACTION_MAKE_SURVIVOR: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN3")
  3885.         case ACTION_RESPAWN_PLAYER: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN4")
  3886.     }
  3887.     menuid = menu_create(menu, "menu_player_list")
  3888.    
  3889.     // Player List
  3890.     for (player = 0; player <= g_maxplayers; player++)
  3891.     {
  3892.         // Skip if not connected
  3893.         if (!g_isconnected[player])
  3894.             continue;
  3895.        
  3896.         // Format text depending on the action to take
  3897.         switch (PL_ACTION)
  3898.         {
  3899.             case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  3900.             {
  3901.                 if (g_zombie[player])
  3902.                 {
  3903.                     if (allowed_human(player) && (userflags & g_access_flag[ACCESS_MAKE_HUMAN]))
  3904.                         formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3905.                     else
  3906.                         formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3907.                 }
  3908.                 else
  3909.                 {
  3910.                     if (allowed_zombie(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE])))
  3911.                         formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3912.                     else
  3913.                         formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3914.                 }
  3915.             }
  3916.             case ACTION_MAKE_NEMESIS: // Nemesis command
  3917.             {
  3918.                 if (allowed_nemesis(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS])))
  3919.                 {
  3920.                     if (g_zombie[player])
  3921.                         formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3922.                     else
  3923.                         formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3924.                 }
  3925.                 else
  3926.                     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")
  3927.             }
  3928.             case ACTION_MAKE_SURVIVOR: // Survivor command
  3929.             {
  3930.                 if (allowed_survivor(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR])))
  3931.                 {
  3932.                     if (g_zombie[player])
  3933.                         formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
  3934.                     else
  3935.                         formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
  3936.                 }
  3937.                 else
  3938.                     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")
  3939.             }
  3940.             case ACTION_RESPAWN_PLAYER: // Respawn command
  3941.             {
  3942.                 if (allowed_respawn(player) && (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS]))
  3943.                     formatex(menu, charsmax(menu), "%s", g_playername[player])
  3944.                 else
  3945.                     formatex(menu, charsmax(menu), "\d%s", g_playername[player])
  3946.             }
  3947.         }
  3948.        
  3949.         // Add player
  3950.         buffer[0] = player
  3951.         buffer[1] = 0
  3952.         menu_additem(menuid, menu, buffer)
  3953.     }
  3954.    
  3955.     // Back - Next - Exit
  3956.     formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
  3957.     menu_setprop(menuid, MPROP_BACKNAME, menu)
  3958.     formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
  3959.     menu_setprop(menuid, MPROP_NEXTNAME, menu)
  3960.     formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
  3961.     menu_setprop(menuid, MPROP_EXITNAME, menu)
  3962.    
  3963.     // If remembered page is greater than number of pages, clamp down the value
  3964.     MENU_PAGE_PLAYERS = min(MENU_PAGE_PLAYERS, menu_pages(menuid)-1)
  3965.    
  3966.     // Fix for AMXX custom menus
  3967.     if (pev_valid(id) == PDATA_SAFE)
  3968.         set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
  3969.    
  3970.     menu_display(id, menuid, MENU_PAGE_PLAYERS)
  3971. }
  3972.  
  3973. /*================================================================================
  3974.  [Menu Handlers]
  3975. =================================================================================*/
  3976.  
  3977. // Game Menu
  3978. public menu_game(id, key)
  3979. {
  3980.     // Player disconnected?
  3981.     if (!g_isconnected[id])
  3982.         return PLUGIN_HANDLED;
  3983.    
  3984.     switch (key)
  3985.     {
  3986.         case 0: // Buy Weapons
  3987.         {
  3988.             // Custom buy menus enabled?
  3989.             if (get_pcvar_num(cvar_buycustom))
  3990.             {
  3991.                 // Disable the remember selection setting
  3992.                 WPN_AUTO_ON = 0
  3993.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "BUY_ENABLED")
  3994.                
  3995.                 // Show menu if player hasn't yet bought anything
  3996.                 if (g_canbuy[id]) show_menu_buy1(id)
  3997.             }
  3998.             else
  3999.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4000.         }
  4001.         case 1: // Extra Items
  4002.         {
  4003.             // Extra items enabled?
  4004.             if (get_pcvar_num(cvar_extraitems))
  4005.             {
  4006.                 // Check whether the player is able to buy anything
  4007.                 if (g_isalive[id])
  4008.                     show_menu_extras(id)
  4009.                 else
  4010.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4011.             }
  4012.             else
  4013.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_EXTRAS")
  4014.         }
  4015.         case 2: // Zombie Classes
  4016.         {
  4017.             // Zombie classes enabled?
  4018.             if (get_pcvar_num(cvar_zclasses))
  4019.                 show_menu_zclass(id)
  4020.             else
  4021.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ZCLASSES")
  4022.         }
  4023.         case 3: // Unstuck
  4024.         {
  4025.             // Check if player is stuck
  4026.             if (g_isalive[id])
  4027.             {
  4028.                 if (is_player_stuck(id))
  4029.                 {
  4030.                     // Move to an initial spawn
  4031.                     if (get_pcvar_num(cvar_randspawn))
  4032.                         do_random_spawn(id) // random spawn (including CSDM)
  4033.                     else
  4034.                         do_random_spawn(id, 1) // regular spawn
  4035.                 }
  4036.                 else
  4037.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_STUCK")
  4038.             }
  4039.             else
  4040.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4041.         }
  4042.         case 4: // Help Menu
  4043.         {
  4044.             show_menu_info(id)
  4045.         }
  4046.         case 5: // Join Spectator
  4047.         {
  4048.             // Player alive?
  4049.             if (g_isalive[id])
  4050.             {
  4051.                 // Prevent abuse by non-admins if block suicide setting is enabled
  4052.                 if (get_pcvar_num(cvar_blocksuicide) && !(get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU]))
  4053.                 {
  4054.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4055.                     return PLUGIN_HANDLED;
  4056.                 }
  4057.                
  4058.                 // Check that we still have both humans and zombies to keep the round going
  4059.                 check_round(id)
  4060.                
  4061.                 // Kill him before he switches team
  4062.                 dllfunc(DLLFunc_ClientKill, id)
  4063.             }
  4064.            
  4065.             // Temporarily save player stats?
  4066.             if (get_pcvar_num(cvar_statssave)) save_stats(id)
  4067.            
  4068.             // Remove previous tasks
  4069.             remove_task(id+TASK_TEAM)
  4070.             remove_task(id+TASK_MODEL)
  4071.             remove_task(id+TASK_FLASH)
  4072.             remove_task(id+TASK_CHARGE)
  4073.             remove_task(id+TASK_SPAWN)
  4074.             remove_task(id+TASK_BLOOD)
  4075.             remove_task(id+TASK_AURA)
  4076.             remove_task(id+TASK_BURN)
  4077.            
  4078.             // Then move him to the spectator team
  4079.             fm_cs_set_user_team(id, FM_CS_TEAM_SPECTATOR)
  4080.             fm_user_team_update(id)
  4081.         }
  4082.         case 8: // Admin Menu
  4083.         {
  4084.             // Check if player has the required access
  4085.             if (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU])
  4086.                 show_menu_admin(id)
  4087.             else
  4088.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4089.         }
  4090.     }
  4091.    
  4092.     return PLUGIN_HANDLED;
  4093. }
  4094.  
  4095. // Buy Menu 1
  4096. public menu_buy1(id, key)
  4097. {
  4098.     // Player dead?
  4099.     if (!g_isalive[id])
  4100.         return PLUGIN_HANDLED;
  4101.    
  4102.     // Zombies or survivors get no guns
  4103.     if (g_zombie[id] || g_survivor[id])
  4104.         return PLUGIN_HANDLED;
  4105.    
  4106.     // Special keys / weapon list exceeded
  4107.     if (key >= MENU_KEY_AUTOSELECT || WPN_SELECTION >= WPN_MAXIDS)
  4108.     {
  4109.         switch (key)
  4110.         {
  4111.             case MENU_KEY_AUTOSELECT: // toggle auto select
  4112.             {
  4113.                 WPN_AUTO_ON = 1 - WPN_AUTO_ON
  4114.             }
  4115.             case MENU_KEY_NEXT: // next/back
  4116.             {
  4117.                 if (WPN_STARTID+7 < WPN_MAXIDS)
  4118.                     WPN_STARTID += 7
  4119.                 else
  4120.                     WPN_STARTID = 0
  4121.             }
  4122.             case MENU_KEY_EXIT: // exit
  4123.             {
  4124.                 return PLUGIN_HANDLED;
  4125.             }
  4126.         }
  4127.        
  4128.         // Show buy menu again
  4129.         show_menu_buy1(id)
  4130.         return PLUGIN_HANDLED;
  4131.     }
  4132.    
  4133.     // Store selected weapon id
  4134.     WPN_AUTO_PRI = WPN_SELECTION
  4135.    
  4136.     // Buy primary weapon
  4137.     buy_primary_weapon(id, WPN_AUTO_PRI)
  4138.    
  4139.     // Show pistols menu
  4140.     show_menu_buy2(id)
  4141.    
  4142.     return PLUGIN_HANDLED;
  4143. }
  4144.  
  4145. // Buy Primary Weapon
  4146. buy_primary_weapon(id, selection)
  4147. {
  4148.     // Drop previous weapons
  4149.     drop_weapons(id, 1)
  4150.     drop_weapons(id, 2)
  4151.    
  4152.     // Strip off from weapons
  4153.     fm_strip_user_weapons(id)
  4154.     fm_give_item(id, "weapon_knife")
  4155.    
  4156.     // Get weapon's id and name
  4157.     static weaponid, wname[32]
  4158.     weaponid = ArrayGetCell(g_primary_weaponids, selection)
  4159.     ArrayGetString(g_primary_items, selection, wname, charsmax(wname))
  4160.    
  4161.     // Give the new weapon and full ammo
  4162.     fm_give_item(id, wname)
  4163.     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4164.    
  4165.     // Weapons bought
  4166.     g_canbuy[id] = false
  4167.    
  4168.     // Give additional items
  4169.     static i
  4170.     for (i = 0; i < ArraySize(g_additional_items); i++)
  4171.     {
  4172.         ArrayGetString(g_additional_items, i, wname, charsmax(wname))
  4173.         fm_give_item(id, wname)
  4174.     }
  4175. }
  4176.  
  4177. // Buy Menu 2
  4178. public menu_buy2(id, key)
  4179. {
  4180.     // Player dead?
  4181.     if (!g_isalive[id])
  4182.         return PLUGIN_HANDLED;
  4183.    
  4184.     // Zombies or survivors get no guns
  4185.     if (g_zombie[id] || g_survivor[id])
  4186.         return PLUGIN_HANDLED;
  4187.    
  4188.     // Special keys / weapon list exceeded
  4189.     if (key >= ArraySize(g_secondary_items))
  4190.     {
  4191.         // Toggle autoselect
  4192.         if (key == MENU_KEY_AUTOSELECT)
  4193.             WPN_AUTO_ON = 1 - WPN_AUTO_ON
  4194.        
  4195.         // Reshow menu unless user exited
  4196.         if (key != MENU_KEY_EXIT)
  4197.             show_menu_buy2(id)
  4198.        
  4199.         return PLUGIN_HANDLED;
  4200.     }
  4201.    
  4202.     // Store selected weapon
  4203.     WPN_AUTO_SEC = key
  4204.    
  4205.     // Drop secondary gun again, in case we picked another (bugfix)
  4206.     drop_weapons(id, 2)
  4207.    
  4208.     // Get weapon's id
  4209.     static weaponid, wname[32]
  4210.     weaponid = ArrayGetCell(g_secondary_weaponids, key)
  4211.     ArrayGetString(g_secondary_items, key, wname, charsmax(wname))
  4212.    
  4213.     // Give the new weapon and full ammo
  4214.     fm_give_item(id, wname)
  4215.     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4216.    
  4217.     return PLUGIN_HANDLED;
  4218. }
  4219.  
  4220. // Extra Items Menu
  4221. public menu_extras(id, menuid, item)
  4222. {
  4223.     // Player disconnected?
  4224.     if (!is_user_connected(id))
  4225.     {
  4226.         menu_destroy(menuid)
  4227.         return PLUGIN_HANDLED;
  4228.     }
  4229.    
  4230.     // Remember player's menu page
  4231.     static menudummy
  4232.     player_menu_info(id, menudummy, menudummy, MENU_PAGE_EXTRAS)
  4233.    
  4234.     // Menu was closed
  4235.     if (item == MENU_EXIT)
  4236.     {
  4237.         menu_destroy(menuid)
  4238.         return PLUGIN_HANDLED;
  4239.     }
  4240.    
  4241.     // Dead players are not allowed to buy items
  4242.     if (!g_isalive[id])
  4243.     {
  4244.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4245.         menu_destroy(menuid)
  4246.         return PLUGIN_HANDLED;
  4247.     }
  4248.    
  4249.     // Retrieve extra item id
  4250.     static buffer[2], dummy, itemid
  4251.     menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4252.     itemid = buffer[0]
  4253.    
  4254.     // Attempt to buy the item
  4255.     buy_extra_item(id, itemid)
  4256.     menu_destroy(menuid)
  4257.     return PLUGIN_HANDLED;
  4258. }
  4259.  
  4260. // Buy Extra Item
  4261. buy_extra_item(id, itemid, ignorecost = 0)
  4262. {
  4263.     // Retrieve item's team
  4264.     static team
  4265.     team = ArrayGetCell(g_extraitem_team, itemid)
  4266.    
  4267.     // Check for team/class specific items
  4268.     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)))
  4269.     {
  4270.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4271.         return;
  4272.     }
  4273.    
  4274.     // Check for unavailable items
  4275.     if ((itemid == EXTRA_NVISION && !get_pcvar_num(cvar_extranvision))
  4276.     || (itemid == EXTRA_ANTIDOTE && (!get_pcvar_num(cvar_extraantidote) || g_antidotecounter >= get_pcvar_num(cvar_antidotelimit)))
  4277.     || (itemid == EXTRA_MADNESS && (!get_pcvar_num(cvar_extramadness) || g_madnesscounter >= get_pcvar_num(cvar_madnesslimit)))
  4278.     || (itemid == EXTRA_INFBOMB && (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit)))
  4279.     || (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)))
  4280.     {
  4281.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4282.         return;
  4283.     }
  4284.    
  4285.     // Check for hard coded items with special conditions
  4286.     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)))
  4287.     || (itemid == EXTRA_MADNESS && g_nodamage[id]) || (itemid == EXTRA_INFBOMB && (g_endround || g_swarmround || g_nemround || g_survround || g_plagueround)))
  4288.     {
  4289.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_CANTUSE")
  4290.         return;
  4291.     }
  4292.    
  4293.     // Ignore item's cost?
  4294.     if (!ignorecost)
  4295.     {
  4296.         // Check that we have enough ammo packs
  4297.         if (g_ammopacks[id] < ArrayGetCell(g_extraitem_cost, itemid))
  4298.         {
  4299.             zp_colored_print(id, "^x04[ZP]^x01 %L", id, "NOT_ENOUGH_AMMO")
  4300.             return;
  4301.         }
  4302.        
  4303.         // Deduce item cost
  4304.         g_ammopacks[id] -= ArrayGetCell(g_extraitem_cost, itemid)
  4305.     }
  4306.    
  4307.     // Check which kind of item we're buying
  4308.     switch (itemid)
  4309.     {
  4310.         case EXTRA_NVISION: // Night Vision
  4311.         {
  4312.             g_nvision[id] = true
  4313.            
  4314.             if (!g_isbot[id])
  4315.             {
  4316.                 g_nvisionenabled[id] = true
  4317.                
  4318.                 // Custom nvg?
  4319.                 if (get_pcvar_num(cvar_customnvg))
  4320.                 {
  4321.                     remove_task(id+TASK_NVISION)
  4322.                     set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  4323.                 }
  4324.                 else
  4325.                     set_user_gnvision(id, 1)
  4326.             }
  4327.             else
  4328.                 cs_set_user_nvg(id, 1)
  4329.         }
  4330.         case EXTRA_ANTIDOTE: // Antidote
  4331.         {
  4332.             // Increase antidote purchase count for this round
  4333.             g_antidotecounter++
  4334.            
  4335.             humanme(id, 0, 0)
  4336.         }
  4337.         case EXTRA_MADNESS: // Zombie Madness
  4338.         {
  4339.             // Increase madness purchase count for this round
  4340.             g_madnesscounter++
  4341.            
  4342.             g_nodamage[id] = true
  4343.             set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
  4344.             set_task(get_pcvar_float(cvar_madnessduration), "madness_over", id+TASK_BLOOD)
  4345.            
  4346.             static sound[64]
  4347.             ArrayGetString(zombie_madness, random_num(0, ArraySize(zombie_madness) - 1), sound, charsmax(sound))
  4348.             emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4349.         }
  4350.         case EXTRA_INFBOMB: // Infection Bomb
  4351.         {
  4352.             // Increase infection bomb purchase count for this round
  4353.             g_infbombcounter++
  4354.            
  4355.             // Already own one
  4356.             if (user_has_weapon(id, CSW_HEGRENADE))
  4357.             {
  4358.                 // Increase BP ammo on it instead
  4359.                 cs_set_user_bpammo(id, CSW_HEGRENADE, cs_get_user_bpammo(id, CSW_HEGRENADE) + 1)
  4360.                
  4361.                 // Flash ammo in hud
  4362.                 message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
  4363.                 write_byte(AMMOID[CSW_HEGRENADE]) // ammo id
  4364.                 write_byte(1) // ammo amount
  4365.                 message_end()
  4366.                
  4367.                 // Play clip purchase sound
  4368.                 emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4369.                
  4370.                 return; // stop here
  4371.             }
  4372.            
  4373.             // Give weapon to the player
  4374.             fm_give_item(id, "weapon_hegrenade")
  4375.         }
  4376.         default:
  4377.         {
  4378.             if (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1) // Weapons
  4379.             {
  4380.                 // Get weapon's id and name
  4381.                 static weaponid, wname[32]
  4382.                 ArrayGetString(g_extraweapon_items, itemid - EXTRA_WEAPONS_STARTID, wname, charsmax(wname))
  4383.                 weaponid = cs_weapon_name_to_id(wname)
  4384.                
  4385.                 // If we are giving a primary/secondary weapon
  4386.                 if (MAXBPAMMO[weaponid] > 2)
  4387.                 {
  4388.                     // Make user drop the previous one
  4389.                     if ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)
  4390.                         drop_weapons(id, 1)
  4391.                     else
  4392.                         drop_weapons(id, 2)
  4393.                    
  4394.                     // Give full BP ammo for the new one
  4395.                     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
  4396.                 }
  4397.                 // If we are giving a grenade which the user already owns
  4398.                 else if (user_has_weapon(id, weaponid))
  4399.                 {
  4400.                     // Increase BP ammo on it instead
  4401.                     cs_set_user_bpammo(id, weaponid, cs_get_user_bpammo(id, weaponid) + 1)
  4402.                    
  4403.                     // Flash ammo in hud
  4404.                     message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
  4405.                     write_byte(AMMOID[weaponid]) // ammo id
  4406.                     write_byte(1) // ammo amount
  4407.                     message_end()
  4408.                    
  4409.                     // Play clip purchase sound
  4410.                     emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
  4411.                    
  4412.                     return; // stop here
  4413.                 }
  4414.                
  4415.                 // Give weapon to the player
  4416.                 fm_give_item(id, wname)
  4417.             }
  4418.             else // Custom additions
  4419.             {
  4420.                 // Item selected forward
  4421.                 ExecuteForward(g_fwExtraItemSelected, g_fwDummyResult, id, itemid);
  4422.                
  4423.                 // Item purchase blocked, restore buyer's ammo packs
  4424.                 if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && !ignorecost)
  4425.                     g_ammopacks[id] += ArrayGetCell(g_extraitem_cost, itemid)
  4426.             }
  4427.         }
  4428.     }
  4429. }
  4430.  
  4431. // Zombie Class Menu
  4432. public menu_zclass(id, menuid, item)
  4433. {
  4434.     // Player disconnected?
  4435.     if (!is_user_connected(id))
  4436.     {
  4437.         menu_destroy(menuid)
  4438.         return PLUGIN_HANDLED;
  4439.     }
  4440.    
  4441.     // Remember player's menu page
  4442.     static menudummy
  4443.     player_menu_info(id, menudummy, menudummy, MENU_PAGE_ZCLASS)
  4444.    
  4445.     // Menu was closed
  4446.     if (item == MENU_EXIT)
  4447.     {
  4448.         menu_destroy(menuid)
  4449.         return PLUGIN_HANDLED;
  4450.     }
  4451.    
  4452.     // Retrieve zombie class id
  4453.     static buffer[2], dummy, classid
  4454.     menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4455.     classid = buffer[0]
  4456.    
  4457.     // Store selection for the next infection
  4458.     g_zombieclassnext[id] = classid
  4459.    
  4460.     static name[32]
  4461.     ArrayGetString(g_zclass_name, g_zombieclassnext[id], name, charsmax(name))
  4462.    
  4463.     // Show selected zombie class info and stats
  4464.     zp_colored_print(id, "^x04[ZP]^x01 %L: %s", id, "ZOMBIE_SELECT", name)
  4465.     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]),
  4466.     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))
  4467.    
  4468.     menu_destroy(menuid)
  4469.     return PLUGIN_HANDLED;
  4470. }
  4471.  
  4472. // Info Menu
  4473. public menu_info(id, key)
  4474. {
  4475.     // Player disconnected?
  4476.     if (!g_isconnected[id])
  4477.         return PLUGIN_HANDLED;
  4478.    
  4479.     static motd[1500], len
  4480.     len = 0
  4481.    
  4482.     switch (key)
  4483.     {
  4484.         case 0: // General
  4485.         {
  4486.             static weather, lighting[2]
  4487.             weather = 0
  4488.             get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
  4489.             strtolower(lighting)
  4490.            
  4491.             len += formatex(motd[len], charsmax(motd) - len, "%L ", id, "MOTD_INFO11", "Zombie Plague", PLUGIN_VERSION, "MeRcyLeZZ")
  4492.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO12")
  4493.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_A")
  4494.            
  4495.             if (g_ambience_fog)
  4496.             {
  4497.                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_FOG")
  4498.                 weather++
  4499.             }
  4500.             if (g_ambience_rain)
  4501.             {
  4502.                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_RAIN")
  4503.                 weather++
  4504.             }
  4505.             if (g_ambience_snow)
  4506.             {
  4507.                 len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_SNOW")
  4508.                 weather++
  4509.             }
  4510.             if (weather < 1) len += formatex(motd[len], charsmax(motd) - len, " %L", id, "MOTD_DISABLED")
  4511.            
  4512.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_B", lighting)
  4513.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_C", id, get_pcvar_num(cvar_triggered) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4514.             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)))
  4515.             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")
  4516.             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")
  4517.             if (get_pcvar_num(cvar_deathmatch)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_G", floatround(get_pcvar_float(cvar_spawnprotection)))
  4518.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_H", id, get_pcvar_num(cvar_randspawn) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4519.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_I", id, get_pcvar_num(cvar_extraitems) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4520.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_J", id, get_pcvar_num(cvar_zclasses) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4521.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_K", id, get_pcvar_num(cvar_customnvg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4522.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_L", id, g_cached_customflash ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4523.            
  4524.             show_motd(id, motd)
  4525.         }
  4526.         case 1: // Humans
  4527.         {
  4528.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2")
  4529.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_A", get_pcvar_num(cvar_humanhp))
  4530.             if (get_pcvar_num(cvar_humanlasthp) > 0) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_B", get_pcvar_num(cvar_humanlasthp))
  4531.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_C", get_pcvar_num(cvar_humanspd))
  4532.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_D", floatround(get_pcvar_float(cvar_humangravity) * 800.0))
  4533.             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")
  4534.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_F", get_pcvar_num(cvar_ammodamage_human))
  4535.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_G", id, get_pcvar_num(cvar_firegrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4536.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_H", id, get_pcvar_num(cvar_frostgrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4537.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_I", id, get_pcvar_num(cvar_flaregrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4538.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_J", id, get_pcvar_num(cvar_knockback) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4539.            
  4540.             show_motd(id, motd)
  4541.         }
  4542.         case 2: // Zombies
  4543.         {
  4544.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3")
  4545.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_A", ArrayGetCell(g_zclass_hp, 0))
  4546.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_B", floatround(float(ArrayGetCell(g_zclass_hp, 0)) * get_pcvar_float(cvar_zombiefirsthp)))
  4547.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_C", floatround(get_pcvar_float(cvar_zombiearmor) * 100.0))
  4548.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_D", ArrayGetCell(g_zclass_spd, 0))
  4549.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_E", floatround(Float:ArrayGetCell(g_zclass_grav, 0) * 800.0))
  4550.             if (get_pcvar_num(cvar_zombiebonushp)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_F", get_pcvar_num(cvar_zombiebonushp))
  4551.             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")
  4552.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_H", id, get_pcvar_num(cvar_zombiebleeding) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4553.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_I", get_pcvar_num(cvar_ammoinfect))
  4554.            
  4555.             show_motd(id, motd)
  4556.         }
  4557.         case 3: // Gameplay Modes
  4558.         {
  4559.             static nemhp[5], survhp[5]
  4560.            
  4561.             // Get nemesis and survivor health
  4562.             num_to_str(get_pcvar_num(cvar_nemhp), nemhp, charsmax(nemhp))
  4563.             num_to_str(get_pcvar_num(cvar_survhp), survhp, charsmax(survhp))
  4564.            
  4565.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4")
  4566.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_A", id, get_pcvar_num(cvar_nem) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4567.             if (get_pcvar_num(cvar_nem))
  4568.             {
  4569.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_B", get_pcvar_num(cvar_nemchance))
  4570.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_C", get_pcvar_num(cvar_nemhp) > 0 ? nemhp : "[Auto]")
  4571.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_D", get_pcvar_num(cvar_nemspd))
  4572.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_E", floatround(get_pcvar_float(cvar_nemgravity) * 800.0))
  4573.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_F", id, g_cached_leapnemesis ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4574.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_G", id, get_pcvar_num(cvar_nempainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4575.             }
  4576.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_H", id, get_pcvar_num(cvar_surv) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4577.             if (get_pcvar_num(cvar_surv))
  4578.             {
  4579.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_I", get_pcvar_num(cvar_survchance))
  4580.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_J", get_pcvar_num(cvar_survhp) > 0 ? survhp : "[Auto]")
  4581.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_K", get_pcvar_num(cvar_survspd))
  4582.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_L", floatround(get_pcvar_float(cvar_survgravity) * 800.0))
  4583.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_M", id, g_cached_leapsurvivor ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4584.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_N", id, get_pcvar_num(cvar_survpainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4585.             }
  4586.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_O", id, get_pcvar_num(cvar_swarm) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4587.             if (get_pcvar_num(cvar_swarm)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_P", get_pcvar_num(cvar_swarmchance))
  4588.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_Q", id, get_pcvar_num(cvar_multi) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4589.             if (get_pcvar_num(cvar_multi))
  4590.             {
  4591.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_R", get_pcvar_num(cvar_multichance))
  4592.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_S", floatround(get_pcvar_float(cvar_multiratio) * 100.0))
  4593.             }
  4594.             len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_T", id, get_pcvar_num(cvar_plague) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4595.             if (get_pcvar_num(cvar_plague))
  4596.             {
  4597.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_U", get_pcvar_num(cvar_plaguechance))
  4598.                 len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_V", floatround(get_pcvar_float(cvar_plagueratio) * 100.0))
  4599.             }
  4600.            
  4601.             show_motd(id, motd)
  4602.         }
  4603.         default: return PLUGIN_HANDLED;
  4604.     }
  4605.    
  4606.     // Show help menu again if user wishes to read another topic
  4607.     show_menu_info(id)
  4608.    
  4609.     return PLUGIN_HANDLED;
  4610. }
  4611.  
  4612. // Admin Menu
  4613. public menu_admin(id, key)
  4614. {
  4615.     // Player disconnected?
  4616.     if (!g_isconnected[id])
  4617.         return PLUGIN_HANDLED;
  4618.    
  4619.     static userflags
  4620.     userflags = get_user_flags(id)
  4621.    
  4622.     switch (key)
  4623.     {
  4624.         case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  4625.         {
  4626.             if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
  4627.             {
  4628.                 // Show player list for admin to pick a target
  4629.                 PL_ACTION = ACTION_ZOMBIEFY_HUMANIZE
  4630.                 show_menu_player_list(id)
  4631.             }
  4632.             else
  4633.             {
  4634.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4635.                 show_menu_admin(id)
  4636.             }
  4637.         }
  4638.         case ACTION_MAKE_NEMESIS: // Nemesis command
  4639.         {
  4640.             if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
  4641.             {
  4642.                 // Show player list for admin to pick a target
  4643.                 PL_ACTION = ACTION_MAKE_NEMESIS
  4644.                 show_menu_player_list(id)
  4645.             }
  4646.             else
  4647.             {
  4648.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4649.                 show_menu_admin(id)
  4650.             }
  4651.         }
  4652.         case ACTION_MAKE_SURVIVOR: // Survivor command
  4653.         {
  4654.             if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
  4655.             {
  4656.                 // Show player list for admin to pick a target
  4657.                 PL_ACTION = ACTION_MAKE_SURVIVOR
  4658.                 show_menu_player_list(id)
  4659.             }
  4660.             else
  4661.             {
  4662.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4663.                 show_menu_admin(id)
  4664.             }
  4665.         }
  4666.         case ACTION_RESPAWN_PLAYER: // Respawn command
  4667.         {
  4668.             if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  4669.             {
  4670.                 // Show player list for admin to pick a target
  4671.                 PL_ACTION = ACTION_RESPAWN_PLAYER
  4672.                 show_menu_player_list(id)
  4673.             }
  4674.             else
  4675.             {
  4676.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4677.                 show_menu_admin(id)
  4678.             }
  4679.         }
  4680.         case ACTION_MODE_SWARM: // Swarm Mode command
  4681.         {
  4682.             if (userflags & g_access_flag[ACCESS_MODE_SWARM])
  4683.             {
  4684.                 if (allowed_swarm())
  4685.                     command_swarm(id)
  4686.                 else
  4687.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4688.             }
  4689.             else
  4690.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4691.            
  4692.             show_menu_admin(id)
  4693.         }
  4694.         case ACTION_MODE_MULTI: // Multiple Infection command
  4695.         {
  4696.             if (userflags & g_access_flag[ACCESS_MODE_MULTI])
  4697.             {
  4698.                 if (allowed_multi())
  4699.                     command_multi(id)
  4700.                 else
  4701.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4702.             }
  4703.             else
  4704.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4705.            
  4706.             show_menu_admin(id)
  4707.         }
  4708.         case ACTION_MODE_PLAGUE: // Plague Mode command
  4709.         {
  4710.             if (userflags & g_access_flag[ACCESS_MODE_PLAGUE])
  4711.             {
  4712.                 if (allowed_plague())
  4713.                     command_plague(id)
  4714.                 else
  4715.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4716.             }
  4717.             else
  4718.                 zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4719.            
  4720.             show_menu_admin(id)
  4721.         }
  4722.     }
  4723.    
  4724.     return PLUGIN_HANDLED;
  4725. }
  4726.  
  4727. // Player List Menu
  4728. public menu_player_list(id, menuid, item)
  4729. {
  4730.     // Player disconnected?
  4731.     if (!is_user_connected(id))
  4732.     {
  4733.         menu_destroy(menuid)
  4734.         return PLUGIN_HANDLED;
  4735.     }
  4736.    
  4737.     // Remember player's menu page
  4738.     static menudummy
  4739.     player_menu_info(id, menudummy, menudummy, MENU_PAGE_PLAYERS)
  4740.    
  4741.     // Menu was closed
  4742.     if (item == MENU_EXIT)
  4743.     {
  4744.         menu_destroy(menuid)
  4745.         show_menu_admin(id)
  4746.         return PLUGIN_HANDLED;
  4747.     }
  4748.    
  4749.     // Retrieve player id
  4750.     static buffer[2], dummy, playerid
  4751.     menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
  4752.     playerid = buffer[0]
  4753.    
  4754.     // Perform action on player
  4755.    
  4756.     // Get admin flags
  4757.     static userflags
  4758.     userflags = get_user_flags(id)
  4759.    
  4760.     // Make sure it's still connected
  4761.     if (g_isconnected[playerid])
  4762.     {
  4763.         // Perform the right action if allowed
  4764.         switch (PL_ACTION)
  4765.         {
  4766.             case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
  4767.             {
  4768.                 if (g_zombie[playerid])
  4769.                 {
  4770.                     if (userflags & g_access_flag[ACCESS_MAKE_HUMAN])
  4771.                     {
  4772.                         if (allowed_human(playerid))
  4773.                             command_human(id, playerid)
  4774.                         else
  4775.                             zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4776.                     }
  4777.                     else
  4778.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4779.                 }
  4780.                 else
  4781.                 {
  4782.                     if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE]))
  4783.                     {
  4784.                         if (allowed_zombie(playerid))
  4785.                             command_zombie(id, playerid)
  4786.                         else
  4787.                             zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4788.                     }
  4789.                     else
  4790.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4791.                 }
  4792.             }
  4793.             case ACTION_MAKE_NEMESIS: // Nemesis command
  4794.             {
  4795.                 if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS]))
  4796.                 {
  4797.                     if (allowed_nemesis(playerid))
  4798.                         command_nemesis(id, playerid)
  4799.                     else
  4800.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4801.                 }
  4802.                 else
  4803.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4804.             }
  4805.             case ACTION_MAKE_SURVIVOR: // Survivor command
  4806.             {
  4807.                 if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR]))
  4808.                 {
  4809.                     if (allowed_survivor(playerid))
  4810.                         command_survivor(id, playerid)
  4811.                     else
  4812.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4813.                 }
  4814.                 else
  4815.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4816.             }
  4817.             case ACTION_RESPAWN_PLAYER: // Respawn command
  4818.             {
  4819.                 if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
  4820.                 {
  4821.                     if (allowed_respawn(playerid))
  4822.                         command_respawn(id, playerid)
  4823.                     else
  4824.                         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4825.                 }
  4826.                 else
  4827.                     zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
  4828.             }
  4829.         }
  4830.     }
  4831.     else
  4832.         zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
  4833.    
  4834.     menu_destroy(menuid)
  4835.     show_menu_player_list(id)
  4836.     return PLUGIN_HANDLED;
  4837. }
  4838.  
  4839. // CS Buy Menus
  4840. public menu_cs_buy(id, key)
  4841. {
  4842.     // Prevent buying if zombie/survivor (bugfix)
  4843.     if (g_zombie[id] || g_survivor[id])
  4844.         return PLUGIN_HANDLED;
  4845.    
  4846.     return PLUGIN_CONTINUE;
  4847. }
  4848.  
  4849. /*================================================================================
  4850.  [Admin Commands]
  4851. =================================================================================*/
  4852.  
  4853. // zp_toggle [1/0]
  4854. public cmd_toggle(id, level, cid)
  4855. {
  4856.     // Check for access flag - Enable/Disable Mod
  4857.     if (!cmd_access(id, g_access_flag[ACCESS_ENABLE_MOD], cid, 2))
  4858.         return PLUGIN_HANDLED;
  4859.    
  4860.     // Retrieve arguments
  4861.     new arg[2]
  4862.     read_argv(1, arg, charsmax(arg))
  4863.    
  4864.     // Mod already enabled/disabled
  4865.     if (str_to_num(arg) == g_pluginenabled)
  4866.         return PLUGIN_HANDLED;
  4867.    
  4868.     // Set toggle cvar
  4869.     set_pcvar_num(cvar_toggle, str_to_num(arg))
  4870.     client_print(id, print_console, "Zombie Plague %L.", id, str_to_num(arg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
  4871.    
  4872.     // Retrieve map name
  4873.     new mapname[32]
  4874.     get_mapname(mapname, charsmax(mapname))
  4875.    
  4876.     // Restart current map
  4877.     server_cmd("changelevel %s", mapname)
  4878.    
  4879.     return PLUGIN_HANDLED;
  4880. }
  4881.  
  4882. // zp_zombie [target]
  4883. public cmd_zombie(id, level, cid)
  4884. {
  4885.     // Check for access flag depending on the resulting action
  4886.     if (g_newround)
  4887.     {
  4888.         // Start Mode Infection
  4889.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_INFECTION], cid, 2))
  4890.             return PLUGIN_HANDLED;
  4891.     }
  4892.     else
  4893.     {
  4894.         // Make Zombie
  4895.         if (!cmd_access(id, g_access_flag[ACCESS_MAKE_ZOMBIE], cid, 2))
  4896.             return PLUGIN_HANDLED;
  4897.     }
  4898.    
  4899.     // Retrieve arguments
  4900.     static arg[32], player
  4901.     read_argv(1, arg, charsmax(arg))
  4902.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4903.    
  4904.     // Invalid target
  4905.     if (!player) return PLUGIN_HANDLED;
  4906.    
  4907.     // Target not allowed to be zombie
  4908.     if (!allowed_zombie(player))
  4909.     {
  4910.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4911.         return PLUGIN_HANDLED
  4912.     }
  4913.    
  4914.     command_zombie(id, player)
  4915.    
  4916.     return PLUGIN_HANDLED;
  4917. }
  4918.  
  4919. // zp_human [target]
  4920. public cmd_human(id, level, cid)
  4921. {
  4922.     // Check for access flag - Make Human
  4923.     if (!cmd_access(id, g_access_flag[ACCESS_MAKE_HUMAN], cid, 2))
  4924.         return PLUGIN_HANDLED;
  4925.    
  4926.     // Retrieve arguments
  4927.     static arg[32], player
  4928.     read_argv(1, arg, charsmax(arg))
  4929.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4930.    
  4931.     // Invalid target
  4932.     if (!player) return PLUGIN_HANDLED;
  4933.    
  4934.     // Target not allowed to be human
  4935.     if (!allowed_human(player))
  4936.     {
  4937.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4938.         return PLUGIN_HANDLED;
  4939.     }
  4940.    
  4941.     command_human(id, player)
  4942.    
  4943.     return PLUGIN_HANDLED;
  4944. }
  4945.  
  4946. // zp_survivor [target]
  4947. public cmd_survivor(id, level, cid)
  4948. {
  4949.     // Check for access flag depending on the resulting action
  4950.     if (g_newround)
  4951.     {
  4952.         // Start Mode Survivor
  4953.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_SURVIVOR], cid, 2))
  4954.             return PLUGIN_HANDLED;
  4955.     }
  4956.     else
  4957.     {
  4958.         // Make Survivor
  4959.         if (!cmd_access(id, g_access_flag[ACCESS_MAKE_SURVIVOR], cid, 2))
  4960.             return PLUGIN_HANDLED;
  4961.     }
  4962.    
  4963.     // Retrieve arguments
  4964.     static arg[32], player
  4965.     read_argv(1, arg, charsmax(arg))
  4966.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  4967.    
  4968.     // Invalid target
  4969.     if (!player) return PLUGIN_HANDLED;
  4970.    
  4971.     // Target not allowed to be survivor
  4972.     if (!allowed_survivor(player))
  4973.     {
  4974.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  4975.         return PLUGIN_HANDLED;
  4976.     }
  4977.    
  4978.     command_survivor(id, player)
  4979.    
  4980.     return PLUGIN_HANDLED;
  4981. }
  4982.  
  4983. // zp_nemesis [target]
  4984. public cmd_nemesis(id, level, cid)
  4985. {
  4986.     // Check for access flag depending on the resulting action
  4987.     if (g_newround)
  4988.     {
  4989.         // Start Mode Nemesis
  4990.         if (!cmd_access(id, g_access_flag[ACCESS_MODE_NEMESIS], cid, 2))
  4991.             return PLUGIN_HANDLED;
  4992.     }
  4993.     else
  4994.     {
  4995.         // Make Nemesis
  4996.         if (!cmd_access(id, g_access_flag[ACCESS_MAKE_NEMESIS], cid, 2))
  4997.             return PLUGIN_HANDLED;
  4998.     }
  4999.    
  5000.     // Retrieve arguments
  5001.     static arg[32], player
  5002.     read_argv(1, arg, charsmax(arg))
  5003.     player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
  5004.    
  5005.     // Invalid target
  5006.     if (!player) return PLUGIN_HANDLED;
  5007.    
  5008.     // Target not allowed to be nemesis
  5009.     if (!allowed_nemesis(player))
  5010.     {
  5011.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5012.         return PLUGIN_HANDLED;
  5013.     }
  5014.    
  5015.     command_nemesis(id, player)
  5016.    
  5017.     return PLUGIN_HANDLED;
  5018. }
  5019.  
  5020. // zp_respawn [target]
  5021. public cmd_respawn(id, level, cid)
  5022. {
  5023.     // Check for access flag - Respawn
  5024.     if (!cmd_access(id, g_access_flag[ACCESS_RESPAWN_PLAYERS], cid, 2))
  5025.         return PLUGIN_HANDLED;
  5026.    
  5027.     // Retrieve arguments
  5028.     static arg[32], player
  5029.     read_argv(1, arg, charsmax(arg))
  5030.     player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
  5031.    
  5032.     // Invalid target
  5033.     if (!player) return PLUGIN_HANDLED;
  5034.    
  5035.     // Target not allowed to be respawned
  5036.     if (!allowed_respawn(player))
  5037.     {
  5038.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5039.         return PLUGIN_HANDLED;
  5040.     }
  5041.    
  5042.     command_respawn(id, player)
  5043.    
  5044.     return PLUGIN_HANDLED;
  5045. }
  5046.  
  5047. // zp_swarm
  5048. public cmd_swarm(id, level, cid)
  5049. {
  5050.     // Check for access flag - Mode Swarm
  5051.     if (!cmd_access(id, g_access_flag[ACCESS_MODE_SWARM], cid, 1))
  5052.         return PLUGIN_HANDLED;
  5053.    
  5054.     // Swarm mode not allowed
  5055.     if (!allowed_swarm())
  5056.     {
  5057.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5058.         return PLUGIN_HANDLED;
  5059.     }
  5060.    
  5061.     command_swarm(id)
  5062.    
  5063.     return PLUGIN_HANDLED;
  5064. }
  5065.  
  5066. // zp_multi
  5067. public cmd_multi(id, level, cid)
  5068. {
  5069.     // Check for access flag - Mode Multi
  5070.     if (!cmd_access(id, g_access_flag[ACCESS_MODE_MULTI], cid, 1))
  5071.         return PLUGIN_HANDLED;
  5072.    
  5073.     // Multi infection mode not allowed
  5074.     if (!allowed_multi())
  5075.     {
  5076.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5077.         return PLUGIN_HANDLED;
  5078.     }
  5079.    
  5080.     command_multi(id)
  5081.    
  5082.     return PLUGIN_HANDLED;
  5083. }
  5084.  
  5085. // zp_plague
  5086. public cmd_plague(id, level, cid)
  5087. {
  5088.     // Check for access flag - Mode Plague
  5089.     if (!cmd_access(id, g_access_flag[ACCESS_MODE_PLAGUE], cid, 1))
  5090.         return PLUGIN_HANDLED;
  5091.    
  5092.     // Plague mode not allowed
  5093.     if (!allowed_plague())
  5094.     {
  5095.         client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
  5096.         return PLUGIN_HANDLED;
  5097.     }
  5098.    
  5099.     command_plague(id)
  5100.    
  5101.     return PLUGIN_HANDLED;
  5102. }
  5103.  
  5104. /*================================================================================
  5105.  [Message Hooks]
  5106. =================================================================================*/
  5107.  
  5108. // Current Weapon info
  5109. public message_cur_weapon(msg_id, msg_dest, msg_entity)
  5110. {
  5111.     // Not alive or zombie
  5112.     if (!g_isalive[msg_entity] || g_zombie[msg_entity])
  5113.         return;
  5114.    
  5115.     // Not an active weapon
  5116.     if (get_msg_arg_int(1) != 1)
  5117.         return;
  5118.    
  5119.     // Unlimited clip disabled for class
  5120.     if (g_survivor[msg_entity] ? get_pcvar_num(cvar_survinfammo) <= 1 : get_pcvar_num(cvar_infammo) <= 1)
  5121.         return;
  5122.    
  5123.     // Get weapon's id
  5124.     static weapon
  5125.     weapon = get_msg_arg_int(2)
  5126.    
  5127.     // Unlimited Clip Ammo for this weapon?
  5128.     if (MAXBPAMMO[weapon] > 2)
  5129.     {
  5130.         // Max out clip ammo
  5131.         static weapon_ent
  5132.         weapon_ent = fm_cs_get_current_weapon_ent(msg_entity)
  5133.         if (pev_valid(weapon_ent)) cs_set_weapon_ammo(weapon_ent, MAXCLIP[weapon])
  5134.        
  5135.         // HUD should show full clip all the time
  5136.         set_msg_arg_int(3, get_msg_argtype(3), MAXCLIP[weapon])
  5137.     }
  5138. }
  5139.  
  5140. // Take off player's money
  5141. public message_money(msg_id, msg_dest, msg_entity)
  5142. {
  5143.     // Remove money setting enabled?
  5144.     if (!get_pcvar_num(cvar_removemoney))
  5145.         return PLUGIN_CONTINUE;
  5146.    
  5147.     fm_cs_set_user_money(msg_entity, 0)
  5148.     return PLUGIN_HANDLED;
  5149. }
  5150.  
  5151. // Fix for the HL engine bug when HP is multiples of 256
  5152. public message_health(msg_id, msg_dest, msg_entity)
  5153. {
  5154.     // Get player's health
  5155.     static health
  5156.     health = get_msg_arg_int(1)
  5157.    
  5158.     // Don't bother
  5159.     if (health < 256) return;
  5160.    
  5161.     // Check if we need to fix it
  5162.     if (health % 256 == 0)
  5163.         fm_set_user_health(msg_entity, pev(msg_entity, pev_health) + 1)
  5164.    
  5165.     // HUD can only show as much as 255 hp
  5166.     set_msg_arg_int(1, get_msg_argtype(1), 255)
  5167. }
  5168.  
  5169. // Block flashlight battery messages if custom flashlight is enabled instead
  5170. public message_flashbat()
  5171. {
  5172.     if (g_cached_customflash)
  5173.         return PLUGIN_HANDLED;
  5174.    
  5175.     return PLUGIN_CONTINUE;
  5176. }
  5177.  
  5178. // Flashbangs should only affect zombies
  5179. public message_screenfade(msg_id, msg_dest, msg_entity)
  5180. {
  5181.     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)
  5182.         return PLUGIN_CONTINUE;
  5183.    
  5184.     // Nemesis shouldn't be FBed
  5185.     if (g_zombie[msg_entity] && !g_nemesis[msg_entity])
  5186.     {
  5187.         // Set flash color to nighvision's
  5188.         set_msg_arg_int(4, get_msg_argtype(4), get_pcvar_num(cvar_nvgcolor[0]))
  5189.         set_msg_arg_int(5, get_msg_argtype(5), get_pcvar_num(cvar_nvgcolor[1]))
  5190.         set_msg_arg_int(6, get_msg_argtype(6), get_pcvar_num(cvar_nvgcolor[2]))
  5191.         return PLUGIN_CONTINUE;
  5192.     }
  5193.    
  5194.     return PLUGIN_HANDLED;
  5195. }
  5196.  
  5197. // Prevent spectators' nightvision from being turned off when switching targets, etc.
  5198. public message_nvgtoggle()
  5199. {
  5200.     return PLUGIN_HANDLED;
  5201. }
  5202.  
  5203. // Set correct model on player corpses
  5204. public message_clcorpse()
  5205. {
  5206.     set_msg_arg_string(1, g_playermodel[get_msg_arg_int(12)])
  5207. }
  5208.  
  5209. // Prevent zombies from seeing any weapon pickup icon
  5210. public message_weappickup(msg_id, msg_dest, msg_entity)
  5211. {
  5212.     if (g_zombie[msg_entity])
  5213.         return PLUGIN_HANDLED;
  5214.    
  5215.     return PLUGIN_CONTINUE;
  5216. }
  5217.  
  5218. // Prevent zombies from seeing any ammo pickup icon
  5219. public message_ammopickup(msg_id, msg_dest, msg_entity)
  5220. {
  5221.     if (g_zombie[msg_entity])
  5222.         return PLUGIN_HANDLED;
  5223.    
  5224.     return PLUGIN_CONTINUE;
  5225. }
  5226.  
  5227. // Block hostage HUD display
  5228. public message_scenario()
  5229. {
  5230.     if (get_msg_args() > 1)
  5231.     {
  5232.         static sprite[8]
  5233.         get_msg_arg_string(2, sprite, charsmax(sprite))
  5234.        
  5235.         if (equal(sprite, "hostage"))
  5236.             return PLUGIN_HANDLED;
  5237.     }
  5238.    
  5239.     return PLUGIN_CONTINUE;
  5240. }
  5241.  
  5242. // Block hostages from appearing on radar
  5243. public message_hostagepos()
  5244. {
  5245.     return PLUGIN_HANDLED;
  5246. }
  5247.  
  5248. // Block some text messages
  5249. public message_textmsg()
  5250. {
  5251.     static textmsg[22]
  5252.     get_msg_arg_string(2, textmsg, charsmax(textmsg))
  5253.    
  5254.     // Game restarting, reset scores and call round end to balance the teams
  5255.     if (equal(textmsg, "#Game_will_restart_in"))
  5256.     {
  5257.         logevent_round_end()
  5258.         g_scorehumans = 0
  5259.         g_scorezombies = 0
  5260.     }
  5261.     // Game commencing, reset scores only (round end is automatically triggered)
  5262.     else if (equal(textmsg, "#Game_Commencing"))
  5263.     {
  5264.         g_gamecommencing = true
  5265.         g_scorehumans = 0
  5266.         g_scorezombies = 0
  5267.     }
  5268.     // Block round end related messages
  5269.     else if (equal(textmsg, "#Hostages_Not_Rescued") || equal(textmsg, "#Round_Draw") || equal(textmsg, "#Terrorists_Win") || equal(textmsg, "#CTs_Win"))
  5270.     {
  5271.         return PLUGIN_HANDLED;
  5272.     }
  5273.    
  5274.     return PLUGIN_CONTINUE;
  5275. }
  5276.  
  5277. // Block CS round win audio messages, since we're playing our own instead
  5278. public message_sendaudio()
  5279. {
  5280.     static audio[17]
  5281.     get_msg_arg_string(2, audio, charsmax(audio))
  5282.    
  5283.     if(equal(audio[7], "terwin") || equal(audio[7], "ctwin") || equal(audio[7], "rounddraw"))
  5284.         return PLUGIN_HANDLED;
  5285.    
  5286.     return PLUGIN_CONTINUE;
  5287. }
  5288.  
  5289. // Send actual team scores (T = zombies // CT = humans)
  5290. public message_teamscore()
  5291. {
  5292.     static team[2]
  5293.     get_msg_arg_string(1, team, charsmax(team))
  5294.    
  5295.     switch (team[0])
  5296.     {
  5297.         // CT
  5298.         case 'C': set_msg_arg_int(2, get_msg_argtype(2), g_scorehumans)
  5299.         // Terrorist
  5300.         case 'T': set_msg_arg_int(2, get_msg_argtype(2), g_scorezombies)
  5301.     }
  5302. }
  5303.  
  5304. // Team Switch (or player joining a team for first time)
  5305. public message_teaminfo(msg_id, msg_dest)
  5306. {
  5307.     // Only hook global messages
  5308.     if (msg_dest != MSG_ALL && msg_dest != MSG_BROADCAST) return;
  5309.    
  5310.     // Don't pick up our own TeamInfo messages for this player (bugfix)
  5311.     if (g_switchingteam) return;
  5312.    
  5313.     // Get player's id
  5314.     static id
  5315.     id = get_msg_arg_int(1)
  5316.    
  5317.     // Invalid player id? (bugfix)
  5318.     if (!(1 <= id <= g_maxplayers)) return;
  5319.    
  5320.     // Enable spectators' nightvision if not spawning right away
  5321.     set_task(0.2, "spec_nvision", id)
  5322.    
  5323.     // Round didn't start yet, nothing to worry about
  5324.     if (g_newround) return;
  5325.    
  5326.     // Get his new team
  5327.     static team[2]
  5328.     get_msg_arg_string(2, team, charsmax(team))
  5329.    
  5330.     // Perform some checks to see if they should join a different team instead
  5331.     switch (team[0])
  5332.     {
  5333.         case 'C': // CT
  5334.         {
  5335.             if (g_survround && fnGetHumans()) // survivor alive --> switch to T and spawn as zombie
  5336.             {
  5337.                 g_respawn_as_zombie[id] = true;
  5338.                 remove_task(id+TASK_TEAM)
  5339.                 fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5340.                 set_msg_arg_string(2, "TERRORIST")
  5341.             }
  5342.             else if (!fnGetZombies()) // no zombies 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.         }
  5350.         case 'T': // Terrorist
  5351.         {
  5352.             if ((g_swarmround || g_survround) && fnGetHumans()) // survivor alive or swarm round w/ humans --> spawn as zombie
  5353.             {
  5354.                 g_respawn_as_zombie[id] = true;
  5355.             }
  5356.             else if (fnGetZombies()) // zombies alive --> switch to CT
  5357.             {
  5358.                 remove_task(id+TASK_TEAM)
  5359.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5360.                 set_msg_arg_string(2, "CT")
  5361.             }
  5362.         }
  5363.     }
  5364. }
  5365.  
  5366. /*================================================================================
  5367.  [Main Functions]
  5368. =================================================================================*/
  5369.  
  5370. // Make Zombie Task
  5371. public make_zombie_task()
  5372. {
  5373.     // Call make a zombie with no specific mode
  5374.     make_a_zombie(MODE_NONE, 0)
  5375. }
  5376.  
  5377. // Make a Zombie Function
  5378. make_a_zombie(mode, id)
  5379. {
  5380.     // Get alive players count
  5381.     static iPlayersnum
  5382.     iPlayersnum = fnGetAlive()
  5383.    
  5384.     // Not enough players, come back later!
  5385.     if (iPlayersnum < 1)
  5386.     {
  5387.         set_task(2.0, "make_zombie_task", TASK_MAKEZOMBIE)
  5388.         return;
  5389.     }
  5390.    
  5391.     // Round started!
  5392.     g_newround = false
  5393.    
  5394.     // Set up some common vars
  5395.     static forward_id, sound[64], iZombies, iMaxZombies
  5396.    
  5397.     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)
  5398.     {
  5399.         // Survivor Mode
  5400.         g_survround = true
  5401.         g_lastmode = MODE_SURVIVOR
  5402.        
  5403.         // Choose player randomly?
  5404.         if (mode == MODE_NONE)
  5405.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5406.        
  5407.         // Remember id for calling our forward later
  5408.         forward_id = id
  5409.        
  5410.         // Turn player into a survivor
  5411.         humanme(id, 1, 0)
  5412.        
  5413.         // Turn the remaining players into zombies
  5414.         for (id = 1; id <= g_maxplayers; id++)
  5415.         {
  5416.             // Not alive
  5417.             if (!g_isalive[id])
  5418.                 continue;
  5419.            
  5420.             // Survivor or already a zombie
  5421.             if (g_survivor[id] || g_zombie[id])
  5422.                 continue;
  5423.            
  5424.             // Turn into a zombie
  5425.             zombieme(id, 0, 0, 1, 0)
  5426.         }
  5427.        
  5428.         // Play survivor sound
  5429.         ArrayGetString(sound_survivor, random_num(0, ArraySize(sound_survivor) - 1), sound, charsmax(sound))
  5430.         PlaySound(sound);
  5431.        
  5432.         // Show Survivor HUD notice
  5433.         set_hudmessage(20, 20, 255, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5434.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SURVIVOR", g_playername[forward_id])
  5435.        
  5436.         // Mode fully started!
  5437.         g_modestarted = true
  5438.        
  5439.         // Round start forward
  5440.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SURVIVOR, forward_id);
  5441.     }
  5442.     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)
  5443.     {      
  5444.         // Swarm Mode
  5445.         g_swarmround = true
  5446.         g_lastmode = MODE_SWARM
  5447.        
  5448.         // Make sure there are alive players on both teams (BUGFIX)
  5449.         if (!fnGetAliveTs())
  5450.         {
  5451.             // Move random player to T team
  5452.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5453.             remove_task(id+TASK_TEAM)
  5454.             fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5455.             fm_user_team_update(id)
  5456.         }
  5457.         else if (!fnGetAliveCTs())
  5458.         {
  5459.             // Move random player to CT team
  5460.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5461.             remove_task(id+TASK_TEAM)
  5462.             fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5463.             fm_user_team_update(id)
  5464.         }
  5465.        
  5466.         // Turn every T into a zombie
  5467.         for (id = 1; id <= g_maxplayers; id++)
  5468.         {
  5469.             // Not alive
  5470.             if (!g_isalive[id])
  5471.                 continue;
  5472.            
  5473.             // Not a Terrorist
  5474.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_T)
  5475.                 continue;
  5476.            
  5477.             // Turn into a zombie
  5478.             zombieme(id, 0, 0, 1, 0)
  5479.         }
  5480.        
  5481.         // Play swarm sound
  5482.         ArrayGetString(sound_swarm, random_num(0, ArraySize(sound_swarm) - 1), sound, charsmax(sound))
  5483.         PlaySound(sound);
  5484.        
  5485.         // Show Swarm HUD notice
  5486.         set_hudmessage(20, 255, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5487.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SWARM")
  5488.        
  5489.         // Mode fully started!
  5490.         g_modestarted = true
  5491.        
  5492.         // Round start forward
  5493.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SWARM, 0);
  5494.     }
  5495.     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)
  5496.     {
  5497.         // Multi Infection Mode
  5498.         g_lastmode = MODE_MULTI
  5499.        
  5500.         // iMaxZombies is rounded up, in case there aren't enough players
  5501.         iMaxZombies = floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil)
  5502.         iZombies = 0
  5503.        
  5504.         // Randomly turn iMaxZombies players into zombies
  5505.         while (iZombies < iMaxZombies)
  5506.         {
  5507.             // Keep looping through all players
  5508.             if (++id > g_maxplayers) id = 1
  5509.            
  5510.             // Dead or already a zombie
  5511.             if (!g_isalive[id] || g_zombie[id])
  5512.                 continue;
  5513.            
  5514.             // Random chance
  5515.             if (random_num(0, 1))
  5516.             {
  5517.                 // Turn into a zombie
  5518.                 zombieme(id, 0, 0, 1, 0)
  5519.                 iZombies++
  5520.             }
  5521.         }
  5522.        
  5523.         // Turn the remaining players into humans
  5524.         for (id = 1; id <= g_maxplayers; id++)
  5525.         {
  5526.             // Only those of them who aren't zombies
  5527.             if (!g_isalive[id] || g_zombie[id])
  5528.                 continue;
  5529.            
  5530.             // Switch to CT
  5531.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5532.             {
  5533.                 remove_task(id+TASK_TEAM)
  5534.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5535.                 fm_user_team_update(id)
  5536.             }
  5537.         }
  5538.        
  5539.         // Play multi infection sound
  5540.         ArrayGetString(sound_multi, random_num(0, ArraySize(sound_multi) - 1), sound, charsmax(sound))
  5541.         PlaySound(sound);
  5542.        
  5543.         // Show Multi Infection HUD notice
  5544.         set_hudmessage(200, 50, 0, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5545.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_MULTI")
  5546.        
  5547.         // Mode fully started!
  5548.         g_modestarted = true
  5549.        
  5550.         // Round start forward
  5551.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_MULTI, 0);
  5552.     }
  5553.     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
  5554.     && 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)
  5555.     {
  5556.         // Plague Mode
  5557.         g_plagueround = true
  5558.         g_lastmode = MODE_PLAGUE
  5559.        
  5560.         // Turn specified amount of players into Survivors
  5561.         static iSurvivors, iMaxSurvivors
  5562.         iMaxSurvivors = get_pcvar_num(cvar_plaguesurvnum)
  5563.         iSurvivors = 0
  5564.        
  5565.         while (iSurvivors < iMaxSurvivors)
  5566.         {
  5567.             // Choose random guy
  5568.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5569.            
  5570.             // Already a survivor?
  5571.             if (g_survivor[id])
  5572.                 continue;
  5573.            
  5574.             // If not, turn him into one
  5575.             humanme(id, 1, 0)
  5576.             iSurvivors++
  5577.            
  5578.             // Apply survivor health multiplier
  5579.             fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguesurvhpmulti)))
  5580.         }
  5581.        
  5582.         // Turn specified amount of players into Nemesis
  5583.         static iNemesis, iMaxNemesis
  5584.         iMaxNemesis = get_pcvar_num(cvar_plaguenemnum)
  5585.         iNemesis = 0
  5586.        
  5587.         while (iNemesis < iMaxNemesis)
  5588.         {
  5589.             // Choose random guy
  5590.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5591.            
  5592.             // Already a survivor or nemesis?
  5593.             if (g_survivor[id] || g_nemesis[id])
  5594.                 continue;
  5595.            
  5596.             // If not, turn him into one
  5597.             zombieme(id, 0, 1, 0, 0)
  5598.             iNemesis++
  5599.            
  5600.             // Apply nemesis health multiplier
  5601.             fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguenemhpmulti)))
  5602.         }
  5603.        
  5604.         // iMaxZombies is rounded up, in case there aren't enough players
  5605.         iMaxZombies = floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)
  5606.         iZombies = 0
  5607.        
  5608.         // Randomly turn iMaxZombies players into zombies
  5609.         while (iZombies < iMaxZombies)
  5610.         {
  5611.             // Keep looping through all players
  5612.             if (++id > g_maxplayers) id = 1
  5613.            
  5614.             // Dead or already a zombie or survivor
  5615.             if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  5616.                 continue;
  5617.            
  5618.             // Random chance
  5619.             if (random_num(0, 1))
  5620.             {
  5621.                 // Turn into a zombie
  5622.                 zombieme(id, 0, 0, 1, 0)
  5623.                 iZombies++
  5624.             }
  5625.         }
  5626.        
  5627.         // Turn the remaining players into humans
  5628.         for (id = 1; id <= g_maxplayers; id++)
  5629.         {
  5630.             // Only those of them who arent zombies or survivor
  5631.             if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
  5632.                 continue;
  5633.            
  5634.             // Switch to CT
  5635.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5636.             {
  5637.                 remove_task(id+TASK_TEAM)
  5638.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5639.                 fm_user_team_update(id)
  5640.             }
  5641.         }
  5642.        
  5643.         // Play plague sound
  5644.         ArrayGetString(sound_plague, random_num(0, ArraySize(sound_plague) - 1), sound, charsmax(sound))
  5645.         PlaySound(sound);
  5646.        
  5647.         // Show Plague HUD notice
  5648.         set_hudmessage(0, 50, 200, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5649.         ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_PLAGUE")
  5650.        
  5651.         // Mode fully started!
  5652.         g_modestarted = true
  5653.        
  5654.         // Round start forward
  5655.         ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_PLAGUE, 0);
  5656.     }
  5657.     else
  5658.     {
  5659.         // Single Infection Mode or Nemesis Mode
  5660.        
  5661.         // Choose player randomly?
  5662.         if (mode == MODE_NONE)
  5663.             id = fnGetRandomAlive(random_num(1, iPlayersnum))
  5664.        
  5665.         // Remember id for calling our forward later
  5666.         forward_id = id
  5667.        
  5668.         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)
  5669.         {
  5670.             // Nemesis Mode
  5671.             g_nemround = true
  5672.             g_lastmode = MODE_NEMESIS
  5673.            
  5674.             // Turn player into nemesis
  5675.             zombieme(id, 0, 1, 0, 0)
  5676.         }
  5677.         else
  5678.         {
  5679.             // Single Infection Mode
  5680.             g_lastmode = MODE_INFECTION
  5681.            
  5682.             // Turn player into the first zombie
  5683.             zombieme(id, 0, 0, 0, 0)
  5684.         }
  5685.        
  5686.         // Remaining players should be humans (CTs)
  5687.         for (id = 1; id <= g_maxplayers; id++)
  5688.         {
  5689.             // Not alive
  5690.             if (!g_isalive[id])
  5691.                 continue;
  5692.            
  5693.             // First zombie/nemesis
  5694.             if (g_zombie[id])
  5695.                 continue;
  5696.            
  5697.             // Switch to CT
  5698.             if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  5699.             {
  5700.                 remove_task(id+TASK_TEAM)
  5701.                 fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  5702.                 fm_user_team_update(id)
  5703.             }
  5704.         }
  5705.        
  5706.         if (g_nemround)
  5707.         {
  5708.             // Play Nemesis sound
  5709.             ArrayGetString(sound_nemesis, random_num(0, ArraySize(sound_nemesis) - 1), sound, charsmax(sound))
  5710.             PlaySound(sound);
  5711.            
  5712.             // Show Nemesis HUD notice
  5713.             set_hudmessage(255, 20, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
  5714.             ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_NEMESIS", g_playername[forward_id])
  5715.            
  5716.             // Mode fully started!
  5717.             g_modestarted = true
  5718.            
  5719.             // Round start forward
  5720.             ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_NEMESIS, forward_id);
  5721.         }
  5722.         else
  5723.         {
  5724.             // Show First Zombie HUD notice
  5725.             set_hudmessage(255, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  5726.             ShowSyncHudMsg(0, g_MsgSync, "%L",LANG_PLAYER, "NOTICE_FIRST", g_playername[forward_id])
  5727.            
  5728.             // Mode fully started!
  5729.             g_modestarted = true
  5730.            
  5731.             // Round start forward
  5732.             ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_INFECTION, forward_id);
  5733.         }
  5734.     }
  5735.    
  5736.     // Start ambience sounds after a mode begins
  5737.     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))
  5738.     {
  5739.         remove_task(TASK_AMBIENCESOUNDS)
  5740.         set_task(2.0, "ambience_sound_effects", TASK_AMBIENCESOUNDS)
  5741.     }
  5742. }
  5743.  
  5744. // Zombie Me Function (player id, infector, turn into a nemesis, silent mode, deathmsg and rewards)
  5745. zombieme(id, infector, nemesis, silentmode, rewards)
  5746. {
  5747.     // User infect attempt forward
  5748.     ExecuteForward(g_fwUserInfect_attempt, g_fwDummyResult, id, infector, nemesis)
  5749.    
  5750.     // One or more plugins blocked the infection. Only allow this after making sure it's
  5751.     // not going to leave us with no zombies. Take into account a last player leaving case.
  5752.     // BUGFIX: only allow after a mode has started, to prevent blocking first zombie e.g.
  5753.     if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetZombies() > g_lastplayerleaving)
  5754.         return;
  5755.    
  5756.     // Pre user infect forward
  5757.     ExecuteForward(g_fwUserInfected_pre, g_fwDummyResult, id, infector, nemesis)
  5758.    
  5759.     // Show zombie class menu if they haven't chosen any (e.g. just connected)
  5760.     if (g_zombieclassnext[id] == ZCLASS_NONE && get_pcvar_num(cvar_zclasses))
  5761.         set_task(0.2, "show_menu_zclass", id)
  5762.    
  5763.     // Set selected zombie class
  5764.     g_zombieclass[id] = g_zombieclassnext[id]
  5765.     // If no class selected yet, use the first (default) one
  5766.     if (g_zombieclass[id] == ZCLASS_NONE) g_zombieclass[id] = 0
  5767.    
  5768.     // Way to go...
  5769.     g_zombie[id] = true
  5770.     g_nemesis[id] = false
  5771.     g_survivor[id] = false
  5772.     g_firstzombie[id] = false
  5773.    
  5774.     // Remove survivor's aura (bugfix)
  5775.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
  5776.    
  5777.     // Remove spawn protection (bugfix)
  5778.     g_nodamage[id] = false
  5779.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
  5780.    
  5781.     // Reset burning duration counter (bugfix)
  5782.     g_burning_duration[id] = 0
  5783.    
  5784.     // Show deathmsg and reward infector?
  5785.     if (rewards && infector)
  5786.     {
  5787.         // Send death notice and fix the "dead" attrib on scoreboard
  5788.         SendDeathMsg(infector, id)
  5789.         FixDeadAttrib(id)
  5790.        
  5791.         // Reward frags, deaths, health, and ammo packs
  5792.         UpdateFrags(infector, id, get_pcvar_num(cvar_fragsinfect), 1, 1)
  5793.         g_ammopacks[infector] += get_pcvar_num(cvar_ammoinfect)
  5794.         fm_set_user_health(infector, pev(infector, pev_health) + get_pcvar_num(cvar_zombiebonushp))
  5795.     }
  5796.    
  5797.     // Cache speed, knockback, and name for player's class
  5798.     g_zombie_spd[id] = float(ArrayGetCell(g_zclass_spd, g_zombieclass[id]))
  5799.     g_zombie_knockback[id] = Float:ArrayGetCell(g_zclass_kb, g_zombieclass[id])
  5800.     ArrayGetString(g_zclass_name, g_zombieclass[id], g_zombie_classname[id], charsmax(g_zombie_classname[]))
  5801.    
  5802.     // Set zombie attributes based on the mode
  5803.     static sound[64]
  5804.     if (!silentmode)
  5805.     {
  5806.         if (nemesis)
  5807.         {
  5808.             // Nemesis
  5809.             g_nemesis[id] = true
  5810.            
  5811.             // Set health [0 = auto]
  5812.             if (get_pcvar_num(cvar_nemhp) == 0)
  5813.             {
  5814.                 if (get_pcvar_num(cvar_nembasehp) == 0)
  5815.                     fm_set_user_health(id, ArrayGetCell(g_zclass_hp, 0) * fnGetAlive())
  5816.                 else
  5817.                     fm_set_user_health(id, get_pcvar_num(cvar_nembasehp) * fnGetAlive())
  5818.             }
  5819.             else
  5820.                 fm_set_user_health(id, get_pcvar_num(cvar_nemhp))
  5821.            
  5822.             // Set gravity, if frozen set the restore gravity value instead
  5823.             if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_nemgravity))
  5824.             else g_frozen_gravity[id] = get_pcvar_float(cvar_nemgravity)
  5825.            
  5826.             // Set nemesis maxspeed
  5827.             ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5828.         }
  5829.         else if (fnGetZombies() == 1)
  5830.         {
  5831.             // First zombie
  5832.             g_firstzombie[id] = true
  5833.            
  5834.             // Set health
  5835.             fm_set_user_health(id, floatround(float(ArrayGetCell(g_zclass_hp, g_zombieclass[id])) * get_pcvar_float(cvar_zombiefirsthp)))
  5836.            
  5837.             // Set gravity, if frozen set the restore gravity value instead
  5838.             if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5839.             else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
  5840.            
  5841.             // Set zombie maxspeed
  5842.             ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5843.            
  5844.             // Infection sound
  5845.             ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound))
  5846.             emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  5847.         }
  5848.         else
  5849.         {
  5850.             // Infected by someone
  5851.            
  5852.             // Set health
  5853.             fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
  5854.            
  5855.             // Set gravity, if frozen set the restore gravity value instead
  5856.             if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5857.             else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
  5858.            
  5859.             // Set zombie maxspeed
  5860.             ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5861.            
  5862.             // Infection sound
  5863.             ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound))
  5864.             emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  5865.            
  5866.             // Show Infection HUD notice
  5867.             set_hudmessage(255, 0, 0, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  5868.            
  5869.             if (infector) // infected by someone?
  5870.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT2", g_playername[id], g_playername[infector])
  5871.             else
  5872.                 ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT", g_playername[id])
  5873.         }
  5874.     }
  5875.     else
  5876.     {
  5877.         // Silent mode, no HUD messages, no infection sounds
  5878.        
  5879.         // Set health
  5880.         fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
  5881.        
  5882.         // Set gravity, if frozen set the restore gravity value instead
  5883.         if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
  5884.         else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
  5885.        
  5886.         // Set zombie maxspeed
  5887.         ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  5888.     }
  5889.    
  5890.     // Remove previous tasks
  5891.     remove_task(id+TASK_MODEL)
  5892.     remove_task(id+TASK_BLOOD)
  5893.     remove_task(id+TASK_AURA)
  5894.     remove_task(id+TASK_BURN)
  5895.    
  5896.     // Switch to T
  5897.     if (fm_cs_get_user_team(id) != FM_CS_TEAM_T) // need to change team?
  5898.     {
  5899.         remove_task(id+TASK_TEAM)
  5900.         fm_cs_set_user_team(id, FM_CS_TEAM_T)
  5901.         fm_user_team_update(id)
  5902.     }
  5903.    
  5904.     // Custom models stuff
  5905.     static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  5906.     already_has_model = false
  5907.    
  5908.     if (g_handle_models_on_separate_ent)
  5909.     {
  5910.         // Set the right model
  5911.         if (g_nemesis[id])
  5912.         {
  5913.             iRand = random_num(0, ArraySize(model_nemesis) - 1)
  5914.             ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5915.             if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
  5916.         }
  5917.         else
  5918.         {
  5919.             if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  5920.             {
  5921.                 iRand = random_num(0, ArraySize(model_admin_zombie) - 1)
  5922.                 ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5923.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
  5924.             }
  5925.             else
  5926.             {
  5927.                 iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
  5928.                 ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5929.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
  5930.             }
  5931.         }
  5932.        
  5933.         // Set model on player model entity
  5934.         fm_set_playermodel_ent(id)
  5935.        
  5936.         // Nemesis glow / remove glow on player model entity, unless frozen
  5937.         if (!g_frozen[id])
  5938.         {
  5939.             if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  5940.                 fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  5941.             else
  5942.                 fm_set_rendering(g_ent_playermodel[id])
  5943.         }
  5944.     }
  5945.     else
  5946.     {
  5947.         // Get current model for comparing it with the current one
  5948.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  5949.        
  5950.         // Set the right model, after checking that we don't already have it
  5951.         if (g_nemesis[id])
  5952.         {
  5953.             size = ArraySize(model_nemesis)
  5954.             for (i = 0; i < size; i++)
  5955.             {
  5956.                 ArrayGetString(model_nemesis, i, tempmodel, charsmax(tempmodel))
  5957.                 if (equal(currentmodel, tempmodel)) already_has_model = true
  5958.             }
  5959.            
  5960.             if (!already_has_model)
  5961.             {
  5962.                 iRand = random_num(0, size - 1)
  5963.                 ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5964.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
  5965.             }
  5966.         }
  5967.         else
  5968.         {
  5969.             if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  5970.             {
  5971.                 size = ArraySize(model_admin_zombie)
  5972.                 for (i = 0; i < size; i++)
  5973.                 {
  5974.                     ArrayGetString(model_admin_zombie, i, tempmodel, charsmax(tempmodel))
  5975.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  5976.                 }
  5977.                
  5978.                 if (!already_has_model)
  5979.                 {
  5980.                     iRand = random_num(0, size - 1)
  5981.                     ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5982.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
  5983.                 }
  5984.             }
  5985.             else
  5986.             {
  5987.                 for (i = ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]); i < ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]); i++)
  5988.                 {
  5989.                     ArrayGetString(g_zclass_playermodel, i, tempmodel, charsmax(tempmodel))
  5990.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  5991.                 }
  5992.                
  5993.                 if (!already_has_model)
  5994.                 {
  5995.                     iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
  5996.                     ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  5997.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
  5998.                 }
  5999.             }
  6000.         }
  6001.        
  6002.         // Need to change the model?
  6003.         if (!already_has_model)
  6004.         {
  6005.             // An additional delay is offset at round start
  6006.             // since SVC_BAD is more likely to be triggered there
  6007.             if (g_newround)
  6008.                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  6009.             else
  6010.                 fm_user_model_update(id+TASK_MODEL)
  6011.         }
  6012.        
  6013.         // Nemesis glow / remove glow, unless frozen
  6014.         if (!g_frozen[id])
  6015.         {
  6016.             if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  6017.                 fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  6018.             else
  6019.                 fm_set_rendering(id)
  6020.         }
  6021.     }
  6022.    
  6023.     // Remove any zoom (bugfix)
  6024.     cs_set_user_zoom(id, CS_RESET_ZOOM, 1)
  6025.    
  6026.     // Remove armor
  6027.     cs_set_user_armor(id, 0, CS_ARMOR_NONE)
  6028.    
  6029.     // Drop weapons when infected
  6030.     drop_weapons(id, 1)
  6031.     drop_weapons(id, 2)
  6032.    
  6033.     // Strip zombies from guns and give them a knife
  6034.     fm_strip_user_weapons(id)
  6035.     fm_give_item(id, "weapon_knife")
  6036.    
  6037.     // Fancy effects
  6038.     infection_effects(id)
  6039.    
  6040.     // Nemesis aura task
  6041.     if (g_nemesis[id] && get_pcvar_num(cvar_nemaura))
  6042.         set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
  6043.    
  6044.     // Remove CS nightvision if player owns one (bugfix)
  6045.     if (cs_get_user_nvg(id))
  6046.     {
  6047.         cs_set_user_nvg(id, 0)
  6048.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6049.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6050.     }
  6051.    
  6052.     // Give Zombies Night Vision?
  6053.     if (get_pcvar_num(cvar_nvggive))
  6054.     {
  6055.         g_nvision[id] = true
  6056.        
  6057.         if (!g_isbot[id])
  6058.         {
  6059.             // Turn on Night Vision automatically?
  6060.             if (get_pcvar_num(cvar_nvggive) == 1)
  6061.             {
  6062.                 g_nvisionenabled[id] = true
  6063.                
  6064.                 // Custom nvg?
  6065.                 if (get_pcvar_num(cvar_customnvg))
  6066.                 {
  6067.                     remove_task(id+TASK_NVISION)
  6068.                     set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  6069.                 }
  6070.                 else
  6071.                     set_user_gnvision(id, 1)
  6072.             }
  6073.             // Turn off nightvision when infected (bugfix)
  6074.             else if (g_nvisionenabled[id])
  6075.             {
  6076.                 if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6077.                 else set_user_gnvision(id, 0)
  6078.                 g_nvisionenabled[id] = false
  6079.             }
  6080.         }
  6081.         else
  6082.             cs_set_user_nvg(id, 1); // turn on NVG for bots
  6083.     }
  6084.     // Disable nightvision when infected (bugfix)
  6085.     else if (g_nvision[id])
  6086.     {
  6087.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6088.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6089.         g_nvision[id] = false
  6090.         g_nvisionenabled[id] = false
  6091.     }
  6092.    
  6093.     // Set custom FOV?
  6094.     if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
  6095.     {
  6096.         message_begin(MSG_ONE, g_msgSetFOV, _, id)
  6097.         write_byte(get_pcvar_num(cvar_zombiefov)) // fov angle
  6098.         message_end()
  6099.     }
  6100.    
  6101.     // Call the bloody task
  6102.     if (!g_nemesis[id] && get_pcvar_num(cvar_zombiebleeding))
  6103.         set_task(0.7, "make_blood", id+TASK_BLOOD, _, _, "b")
  6104.    
  6105.     // Idle sounds task
  6106.     if (!g_nemesis[id])
  6107.         set_task(random_float(50.0, 70.0), "zombie_play_idle", id+TASK_BLOOD, _, _, "b")
  6108.    
  6109.     // Turn off zombie's flashlight
  6110.     turn_off_flashlight(id)
  6111.    
  6112.     // Post user infect forward
  6113.     ExecuteForward(g_fwUserInfected_post, g_fwDummyResult, id, infector, nemesis)
  6114.    
  6115.     // Last Zombie Check
  6116.     fnCheckLastZombie()
  6117. }
  6118.  
  6119. // Function Human Me (player id, turn into a survivor, silent mode)
  6120. humanme(id, survivor, silentmode)
  6121. {
  6122.     // User humanize attempt forward
  6123.     ExecuteForward(g_fwUserHumanize_attempt, g_fwDummyResult, id, survivor)
  6124.    
  6125.     // One or more plugins blocked the "humanization". Only allow this after making sure it's
  6126.     // not going to leave us with no humans. Take into account a last player leaving case.
  6127.     // BUGFIX: only allow after a mode has started, to prevent blocking first survivor e.g.
  6128.     if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetHumans() > g_lastplayerleaving)
  6129.         return;
  6130.    
  6131.     // Pre user humanize forward
  6132.     ExecuteForward(g_fwUserHumanized_pre, g_fwDummyResult, id, survivor)
  6133.    
  6134.     // Remove previous tasks
  6135.     remove_task(id+TASK_MODEL)
  6136.     remove_task(id+TASK_BLOOD)
  6137.     remove_task(id+TASK_AURA)
  6138.     remove_task(id+TASK_BURN)
  6139.     remove_task(id+TASK_NVISION)
  6140.    
  6141.     // Reset some vars
  6142.     g_zombie[id] = false
  6143.     g_nemesis[id] = false
  6144.     g_survivor[id] = false
  6145.     g_firstzombie[id] = false
  6146.     g_canbuy[id] = true
  6147.     g_buytime[id] = get_gametime()
  6148.    
  6149.     // Remove survivor's aura (bugfix)
  6150.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
  6151.    
  6152.     // Remove spawn protection (bugfix)
  6153.     g_nodamage[id] = false
  6154.     set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
  6155.    
  6156.     // Reset burning duration counter (bugfix)
  6157.     g_burning_duration[id] = 0
  6158.    
  6159.     // Remove CS nightvision if player owns one (bugfix)
  6160.     if (cs_get_user_nvg(id))
  6161.     {
  6162.         cs_set_user_nvg(id, 0)
  6163.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6164.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6165.     }
  6166.    
  6167.     // Drop previous weapons
  6168.     drop_weapons(id, 1)
  6169.     drop_weapons(id, 2)
  6170.    
  6171.     // Strip off from weapons
  6172.     fm_strip_user_weapons(id)
  6173.     fm_give_item(id, "weapon_knife")
  6174.    
  6175.     // Set human attributes based on the mode
  6176.     if (survivor)
  6177.     {
  6178.         // Survivor
  6179.         g_survivor[id] = true
  6180.        
  6181.         // Set Health [0 = auto]
  6182.         if (get_pcvar_num(cvar_survhp) == 0)
  6183.         {
  6184.             if (get_pcvar_num(cvar_survbasehp) == 0)
  6185.                 fm_set_user_health(id, get_pcvar_num(cvar_humanhp) * fnGetAlive())
  6186.             else
  6187.                 fm_set_user_health(id, get_pcvar_num(cvar_survbasehp) * fnGetAlive())
  6188.         }
  6189.         else
  6190.             fm_set_user_health(id, get_pcvar_num(cvar_survhp))
  6191.        
  6192.         // Set gravity, if frozen set the restore gravity value instead
  6193.         if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_survgravity))
  6194.         else g_frozen_gravity[id] = get_pcvar_float(cvar_survgravity)
  6195.        
  6196.         // Set survivor maxspeed
  6197.         ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  6198.        
  6199.         // Give survivor his own weapon
  6200.         static survweapon[32]
  6201.         get_pcvar_string(cvar_survweapon, survweapon, charsmax(survweapon))
  6202.         fm_give_item(id, survweapon)
  6203.         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)])
  6204.        
  6205.         // Turn off his flashlight
  6206.         turn_off_flashlight(id)
  6207.        
  6208.         // Give the survivor a bright light
  6209.         if (get_pcvar_num(cvar_survaura)) set_pev(id, pev_effects, pev(id, pev_effects) | EF_BRIGHTLIGHT)
  6210.        
  6211.         // Survivor bots will also need nightvision to see in the dark
  6212.         if (g_isbot[id])
  6213.         {
  6214.             g_nvision[id] = true
  6215.             cs_set_user_nvg(id, 1)
  6216.         }
  6217.     }
  6218.     else
  6219.     {
  6220.         // Human taking an antidote
  6221.        
  6222.         // Set health
  6223.         fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
  6224.        
  6225.         // Set gravity, if frozen set the restore gravity value instead
  6226.         if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
  6227.         else g_frozen_gravity[id] = get_pcvar_float(cvar_humangravity)
  6228.        
  6229.         // Set human maxspeed
  6230.         ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  6231.        
  6232.         // Show custom buy menu?
  6233.         if (get_pcvar_num(cvar_buycustom))
  6234.             set_task(0.2, "show_menu_buy1", id+TASK_SPAWN)
  6235.        
  6236.         // Silent mode = no HUD messages, no antidote sound
  6237.         if (!silentmode)
  6238.         {
  6239.             // Antidote sound
  6240.             static sound[64]
  6241.             ArrayGetString(sound_antidote, random_num(0, ArraySize(sound_antidote) - 1), sound, charsmax(sound))
  6242.             emit_sound(id, CHAN_ITEM, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  6243.            
  6244.             // Show Antidote HUD notice
  6245.             set_hudmessage(0, 0, 255, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
  6246.             ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_ANTIDOTE", g_playername[id])
  6247.         }
  6248.     }
  6249.    
  6250.     // Switch to CT
  6251.     if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
  6252.     {
  6253.         remove_task(id+TASK_TEAM)
  6254.         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  6255.         fm_user_team_update(id)
  6256.     }
  6257.    
  6258.     // Custom models stuff
  6259.     static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
  6260.     already_has_model = false
  6261.    
  6262.     if (g_handle_models_on_separate_ent)
  6263.     {
  6264.         // Set the right model
  6265.         if (g_survivor[id])
  6266.         {
  6267.             iRand = random_num(0, ArraySize(model_survivor) - 1)
  6268.             ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6269.             if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
  6270.         }
  6271.         else
  6272.         {
  6273.             if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  6274.             {
  6275.                 iRand = random_num(0, ArraySize(model_admin_human) - 1)
  6276.                 ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6277.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  6278.             }
  6279.             else
  6280.             {
  6281.                 iRand = random_num(0, ArraySize(model_human) - 1)
  6282.                 ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6283.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  6284.             }
  6285.         }
  6286.        
  6287.         // Set model on player model entity
  6288.         fm_set_playermodel_ent(id)
  6289.        
  6290.         // Set survivor glow / remove glow on player model entity, unless frozen
  6291.         if (!g_frozen[id])
  6292.         {
  6293.             if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  6294.                 fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  6295.             else
  6296.                 fm_set_rendering(g_ent_playermodel[id])
  6297.         }
  6298.     }
  6299.     else
  6300.     {
  6301.         // Get current model for comparing it with the current one
  6302.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  6303.        
  6304.         // Set the right model, after checking that we don't already have it
  6305.         if (g_survivor[id])
  6306.         {
  6307.             size = ArraySize(model_survivor)
  6308.             for (i = 0; i < size; i++)
  6309.             {
  6310.                 ArrayGetString(model_survivor, i, tempmodel, charsmax(tempmodel))
  6311.                 if (equal(currentmodel, tempmodel)) already_has_model = true
  6312.             }
  6313.            
  6314.             if (!already_has_model)
  6315.             {
  6316.                 iRand = random_num(0, size - 1)
  6317.                 ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6318.                 if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
  6319.             }
  6320.         }
  6321.         else
  6322.         {
  6323.             if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
  6324.             {
  6325.                 size = ArraySize(model_admin_human)
  6326.                 for (i = 0; i < size; i++)
  6327.                 {
  6328.                     ArrayGetString(model_admin_human, i, tempmodel, charsmax(tempmodel))
  6329.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  6330.                 }
  6331.                
  6332.                 if (!already_has_model)
  6333.                 {
  6334.                     iRand = random_num(0, size - 1)
  6335.                     ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6336.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
  6337.                 }
  6338.             }
  6339.             else
  6340.             {
  6341.                 size = ArraySize(model_human)
  6342.                 for (i = 0; i < size; i++)
  6343.                 {
  6344.                     ArrayGetString(model_human, i, tempmodel, charsmax(tempmodel))
  6345.                     if (equal(currentmodel, tempmodel)) already_has_model = true
  6346.                 }
  6347.                
  6348.                 if (!already_has_model)
  6349.                 {
  6350.                     iRand = random_num(0, size - 1)
  6351.                     ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
  6352.                     if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
  6353.                 }
  6354.             }
  6355.         }
  6356.        
  6357.         // Need to change the model?
  6358.         if (!already_has_model)
  6359.         {
  6360.             // An additional delay is offset at round start
  6361.             // since SVC_BAD is more likely to be triggered there
  6362.             if (g_newround)
  6363.                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  6364.             else
  6365.                 fm_user_model_update(id+TASK_MODEL)
  6366.         }
  6367.        
  6368.         // Set survivor glow / remove glow, unless frozen
  6369.         if (!g_frozen[id])
  6370.         {
  6371.             if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  6372.                 fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  6373.             else
  6374.                 fm_set_rendering(id)
  6375.         }
  6376.     }
  6377.    
  6378.     // Restore FOV?
  6379.     if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
  6380.     {
  6381.         message_begin(MSG_ONE, g_msgSetFOV, _, id)
  6382.         write_byte(90) // angle
  6383.         message_end()
  6384.     }
  6385.    
  6386.     // Disable nightvision when turning into human/survivor (bugfix)
  6387.     if (g_nvision[id])
  6388.     {
  6389.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  6390.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  6391.         g_nvision[id] = false
  6392.         g_nvisionenabled[id] = false
  6393.     }
  6394.    
  6395.     // Post user humanize forward
  6396.     ExecuteForward(g_fwUserHumanized_post, g_fwDummyResult, id, survivor)
  6397.    
  6398.     // Last Zombie Check
  6399.     fnCheckLastZombie()
  6400. }
  6401.  
  6402. /*================================================================================
  6403.  [Other Functions and Tasks]
  6404. =================================================================================*/
  6405.  
  6406. public cache_cvars()
  6407. {
  6408.     g_cached_zombiesilent = get_pcvar_num(cvar_zombiesilent)
  6409.     g_cached_customflash = get_pcvar_num(cvar_customflash)
  6410.     g_cached_leapzombies = get_pcvar_num(cvar_leapzombies)
  6411.     g_cached_leapzombiescooldown = get_pcvar_float(cvar_leapzombiescooldown)
  6412.     g_cached_leapnemesis = get_pcvar_num(cvar_leapnemesis)
  6413.     g_cached_leapnemesiscooldown = get_pcvar_float(cvar_leapnemesiscooldown)
  6414.     g_cached_leapsurvivor = get_pcvar_num(cvar_leapsurvivor)
  6415.     g_cached_leapsurvivorcooldown = get_pcvar_float(cvar_leapsurvivorcooldown)
  6416.     g_cached_buytime = get_pcvar_float(cvar_buyzonetime)
  6417. }
  6418.  
  6419. load_customization_from_files()
  6420. {
  6421.     // Build customization file path
  6422.     new path[64]
  6423.     get_configsdir(path, charsmax(path))
  6424.     format(path, charsmax(path), "%s/%s", path, ZP_CUSTOMIZATION_FILE)
  6425.    
  6426.     // File not present
  6427.     if (!file_exists(path))
  6428.     {
  6429.         new error[100]
  6430.         formatex(error, charsmax(error), "Cannot load customization file %s!", path)
  6431.         set_fail_state(error)
  6432.         return;
  6433.     }
  6434.    
  6435.     // Set up some vars to hold parsing info
  6436.     new linedata[1024], key[64], value[960], section, teams
  6437.    
  6438.     // Open customization file for reading
  6439.     new file = fopen(path, "rt")
  6440.    
  6441.     while (file && !feof(file))
  6442.     {
  6443.         // Read one line at a time
  6444.         fgets(file, linedata, charsmax(linedata))
  6445.        
  6446.         // Replace newlines with a null character to prevent headaches
  6447.         replace(linedata, charsmax(linedata), "^n", "")
  6448.        
  6449.         // Blank line or comment
  6450.         if (!linedata[0] || linedata[0] == ';') continue;
  6451.        
  6452.         // New section starting
  6453.         if (linedata[0] == '[')
  6454.         {
  6455.             section++
  6456.             continue;
  6457.         }
  6458.        
  6459.         // Get key and value(s)
  6460.         strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  6461.        
  6462.         // Trim spaces
  6463.         trim(key)
  6464.         trim(value)
  6465.        
  6466.         switch (section)
  6467.         {
  6468.             case SECTION_ACCESS_FLAGS:
  6469.             {
  6470.                 if (equal(key, "ENABLE/DISABLE MOD"))
  6471.                     g_access_flag[ACCESS_ENABLE_MOD] = read_flags(value)
  6472.                 else if (equal(key, "ADMIN MENU"))
  6473.                     g_access_flag[ACCESS_ADMIN_MENU] = read_flags(value)
  6474.                 else if (equal(key, "START MODE INFECTION"))
  6475.                     g_access_flag[ACCESS_MODE_INFECTION] = read_flags(value)
  6476.                 else if (equal(key, "START MODE NEMESIS"))
  6477.                     g_access_flag[ACCESS_MODE_NEMESIS] = read_flags(value)
  6478.                 else if (equal(key, "START MODE SURVIVOR"))
  6479.                     g_access_flag[ACCESS_MODE_SURVIVOR] = read_flags(value)
  6480.                 else if (equal(key, "START MODE SWARM"))
  6481.                     g_access_flag[ACCESS_MODE_SWARM] = read_flags(value)
  6482.                 else if (equal(key, "START MODE MULTI"))
  6483.                     g_access_flag[ACCESS_MODE_MULTI] = read_flags(value)
  6484.                 else if (equal(key, "START MODE PLAGUE"))
  6485.                     g_access_flag[ACCESS_MODE_PLAGUE] = read_flags(value)
  6486.                 else if (equal(key, "MAKE ZOMBIE"))
  6487.                     g_access_flag[ACCESS_MAKE_ZOMBIE] = read_flags(value)
  6488.                 else if (equal(key, "MAKE HUMAN"))
  6489.                     g_access_flag[ACCESS_MAKE_HUMAN] = read_flags(value)
  6490.                 else if (equal(key, "MAKE NEMESIS"))
  6491.                     g_access_flag[ACCESS_MAKE_NEMESIS] = read_flags(value)
  6492.                 else if (equal(key, "MAKE SURVIVOR"))
  6493.                     g_access_flag[ACCESS_MAKE_SURVIVOR] = read_flags(value)
  6494.                 else if (equal(key, "RESPAWN PLAYERS"))
  6495.                     g_access_flag[ACCESS_RESPAWN_PLAYERS] = read_flags(value)
  6496.                 else if (equal(key, "ADMIN MODELS"))
  6497.                     g_access_flag[ACCESS_ADMIN_MODELS] = read_flags(value)
  6498.             }
  6499.             case SECTION_PLAYER_MODELS:
  6500.             {
  6501.                 if (equal(key, "HUMAN"))
  6502.                 {
  6503.                     // Parse models
  6504.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6505.                     {
  6506.                         // Trim spaces
  6507.                         trim(key)
  6508.                         trim(value)
  6509.                        
  6510.                         // Add to models array
  6511.                         ArrayPushString(model_human, key)
  6512.                     }
  6513.                 }
  6514.                 else if (equal(key, "NEMESIS"))
  6515.                 {
  6516.                     // Parse models
  6517.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6518.                     {
  6519.                         // Trim spaces
  6520.                         trim(key)
  6521.                         trim(value)
  6522.                        
  6523.                         // Add to models array
  6524.                         ArrayPushString(model_nemesis, key)
  6525.                     }
  6526.                 }
  6527.                 else if (equal(key, "SURVIVOR"))
  6528.                 {
  6529.                     // Parse models
  6530.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6531.                     {
  6532.                         // Trim spaces
  6533.                         trim(key)
  6534.                         trim(value)
  6535.                        
  6536.                         // Add to models array
  6537.                         ArrayPushString(model_survivor, key)
  6538.                     }
  6539.                 }
  6540.                 else if (equal(key, "ADMIN ZOMBIE"))
  6541.                 {
  6542.                     // Parse models
  6543.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6544.                     {
  6545.                         // Trim spaces
  6546.                         trim(key)
  6547.                         trim(value)
  6548.                        
  6549.                         // Add to models array
  6550.                         ArrayPushString(model_admin_zombie, key)
  6551.                     }
  6552.                 }
  6553.                 else if (equal(key, "ADMIN HUMAN"))
  6554.                 {
  6555.                     // Parse models
  6556.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6557.                     {
  6558.                         // Trim spaces
  6559.                         trim(key)
  6560.                         trim(value)
  6561.                        
  6562.                         // Add to models array
  6563.                         ArrayPushString(model_admin_human, key)
  6564.                     }
  6565.                 }
  6566.                 else if (equal(key, "FORCE CONSISTENCY"))
  6567.                     g_force_consistency = str_to_num(value)
  6568.                 else if (equal(key, "SAME MODELS FOR ALL"))
  6569.                     g_same_models_for_all = str_to_num(value)
  6570.                 else if (g_same_models_for_all && equal(key, "ZOMBIE"))
  6571.                 {
  6572.                     // Parse models
  6573.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6574.                     {
  6575.                         // Trim spaces
  6576.                         trim(key)
  6577.                         trim(value)
  6578.                        
  6579.                         // Add to models array
  6580.                         ArrayPushString(g_zclass_playermodel, key)
  6581.                        
  6582.                         // Precache model and retrieve its modelindex
  6583.                         formatex(linedata, charsmax(linedata), "models/player/%s/%s.mdl", key, key)
  6584.                         ArrayPushCell(g_zclass_modelindex, engfunc(EngFunc_PrecacheModel, linedata))
  6585.                         if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, linedata)
  6586.                         if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, linedata)
  6587.                         // Precache modelT.mdl files too
  6588.                         copy(linedata[strlen(linedata)-4], charsmax(linedata) - (strlen(linedata)-4), "T.mdl")
  6589.                         if (file_exists(linedata)) engfunc(EngFunc_PrecacheModel, linedata)
  6590.                     }
  6591.                 }
  6592.             }
  6593.             case SECTION_WEAPON_MODELS:
  6594.             {
  6595.                 if (equal(key, "V_KNIFE HUMAN"))
  6596.                     copy(model_vknife_human, charsmax(model_vknife_human), value)
  6597.                 else if (equal(key, "V_KNIFE NEMESIS"))
  6598.                     copy(model_vknife_nemesis, charsmax(model_vknife_nemesis), value)
  6599.                 else if (equal(key, "V_M249 SURVIVOR")) // backwards compatibility with old configs
  6600.                     copy(model_vweapon_survivor, charsmax(model_vweapon_survivor), value)
  6601.                 else if (equal(key, "V_WEAPON SURVIVOR"))
  6602.                     copy(model_vweapon_survivor, charsmax(model_vweapon_survivor), value)
  6603.                 else if (equal(key, "GRENADE INFECT"))
  6604.                     copy(model_grenade_infect, charsmax(model_grenade_infect), value)
  6605.                 else if (equal(key, "GRENADE FIRE"))
  6606.                     copy(model_grenade_fire, charsmax(model_grenade_fire), value)
  6607.                 else if (equal(key, "GRENADE FROST"))
  6608.                     copy(model_grenade_frost, charsmax(model_grenade_frost), value)
  6609.                 else if (equal(key, "GRENADE FLARE"))
  6610.                     copy(model_grenade_flare, charsmax(model_grenade_flare), value)
  6611.                 else if (equal(key, "V_KNIFE ADMIN HUMAN"))
  6612.                     copy(model_vknife_admin_human, charsmax(model_vknife_admin_human), value)
  6613.                 else if (equal(key, "V_KNIFE ADMIN ZOMBIE"))
  6614.                     copy(model_vknife_admin_zombie, charsmax(model_vknife_admin_zombie), value)
  6615.             }
  6616.             case SECTION_GRENADE_SPRITES:
  6617.             {
  6618.                 if (equal(key, "TRAIL"))
  6619.                     copy(sprite_grenade_trail, charsmax(sprite_grenade_trail), value)
  6620.                 else if (equal(key, "RING"))
  6621.                     copy(sprite_grenade_ring, charsmax(sprite_grenade_ring), value)
  6622.                 else if (equal(key, "FIRE"))
  6623.                     copy(sprite_grenade_fire, charsmax(sprite_grenade_fire), value)
  6624.                 else if (equal(key, "SMOKE"))
  6625.                     copy(sprite_grenade_smoke, charsmax(sprite_grenade_smoke), value)
  6626.                 else if (equal(key, "GLASS"))
  6627.                     copy(sprite_grenade_glass, charsmax(sprite_grenade_glass), value)
  6628.             }
  6629.             case SECTION_SOUNDS:
  6630.             {
  6631.                 if (equal(key, "WIN ZOMBIES"))
  6632.                 {
  6633.                     // Parse sounds
  6634.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6635.                     {
  6636.                         // Trim spaces
  6637.                         trim(key)
  6638.                         trim(value)
  6639.                        
  6640.                         // Add to sounds array
  6641.                         ArrayPushString(sound_win_zombies, key)
  6642.                         ArrayPushCell(sound_win_zombies_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6643.                     }
  6644.                 }
  6645.                 else if (equal(key, "WIN HUMANS"))
  6646.                 {
  6647.                     // Parse sounds
  6648.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6649.                     {
  6650.                         // Trim spaces
  6651.                         trim(key)
  6652.                         trim(value)
  6653.                        
  6654.                         // Add to sounds array
  6655.                         ArrayPushString(sound_win_humans, key)
  6656.                         ArrayPushCell(sound_win_humans_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6657.                     }
  6658.                 }
  6659.                 else if (equal(key, "WIN NO ONE"))
  6660.                 {
  6661.                     // Parse sounds
  6662.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6663.                     {
  6664.                         // Trim spaces
  6665.                         trim(key)
  6666.                         trim(value)
  6667.                        
  6668.                         // Add to sounds array
  6669.                         ArrayPushString(sound_win_no_one, key)
  6670.                         ArrayPushCell(sound_win_no_one_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  6671.                     }
  6672.                 }
  6673.                 else if (equal(key, "ZOMBIE INFECT"))
  6674.                 {
  6675.                     // Parse sounds
  6676.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6677.                     {
  6678.                         // Trim spaces
  6679.                         trim(key)
  6680.                         trim(value)
  6681.                        
  6682.                         // Add to sounds array
  6683.                         ArrayPushString(zombie_infect, key)
  6684.                     }
  6685.                 }
  6686.                 else if (equal(key, "ZOMBIE PAIN"))
  6687.                 {
  6688.                     // Parse sounds
  6689.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6690.                     {
  6691.                         // Trim spaces
  6692.                         trim(key)
  6693.                         trim(value)
  6694.                        
  6695.                         // Add to sounds array
  6696.                         ArrayPushString(zombie_pain, key)
  6697.                     }
  6698.                 }
  6699.                 else if (equal(key, "NEMESIS PAIN"))
  6700.                 {
  6701.                     // Parse sounds
  6702.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6703.                     {
  6704.                         // Trim spaces
  6705.                         trim(key)
  6706.                         trim(value)
  6707.                        
  6708.                         // Add to sounds array
  6709.                         ArrayPushString(nemesis_pain, key)
  6710.                     }
  6711.                 }
  6712.                 else if (equal(key, "ZOMBIE DIE"))
  6713.                 {
  6714.                     // Parse sounds
  6715.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6716.                     {
  6717.                         // Trim spaces
  6718.                         trim(key)
  6719.                         trim(value)
  6720.                        
  6721.                         // Add to sounds array
  6722.                         ArrayPushString(zombie_die, key)
  6723.                     }
  6724.                 }
  6725.                 else if (equal(key, "ZOMBIE FALL"))
  6726.                 {
  6727.                     // Parse sounds
  6728.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6729.                     {
  6730.                         // Trim spaces
  6731.                         trim(key)
  6732.                         trim(value)
  6733.                        
  6734.                         // Add to sounds array
  6735.                         ArrayPushString(zombie_fall, key)
  6736.                     }
  6737.                 }
  6738.                 else if (equal(key, "ZOMBIE MISS SLASH"))
  6739.                 {
  6740.                     // Parse sounds
  6741.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6742.                     {
  6743.                         // Trim spaces
  6744.                         trim(key)
  6745.                         trim(value)
  6746.                        
  6747.                         // Add to sounds array
  6748.                         ArrayPushString(zombie_miss_slash, key)
  6749.                     }
  6750.                 }
  6751.                 else if (equal(key, "ZOMBIE MISS WALL"))
  6752.                 {
  6753.                     // Parse sounds
  6754.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6755.                     {
  6756.                         // Trim spaces
  6757.                         trim(key)
  6758.                         trim(value)
  6759.                        
  6760.                         // Add to sounds array
  6761.                         ArrayPushString(zombie_miss_wall, key)
  6762.                     }
  6763.                 }
  6764.                 else if (equal(key, "ZOMBIE HIT NORMAL"))
  6765.                 {
  6766.                     // Parse sounds
  6767.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6768.                     {
  6769.                         // Trim spaces
  6770.                         trim(key)
  6771.                         trim(value)
  6772.                        
  6773.                         // Add to sounds array
  6774.                         ArrayPushString(zombie_hit_normal, key)
  6775.                     }
  6776.                 }
  6777.                 else if (equal(key, "ZOMBIE HIT STAB"))
  6778.                 {
  6779.                     // Parse sounds
  6780.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6781.                     {
  6782.                         // Trim spaces
  6783.                         trim(key)
  6784.                         trim(value)
  6785.                        
  6786.                         // Add to sounds array
  6787.                         ArrayPushString(zombie_hit_stab, key)
  6788.                     }
  6789.                 }
  6790.                 else if (equal(key, "ZOMBIE IDLE"))
  6791.                 {
  6792.                     // Parse sounds
  6793.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6794.                     {
  6795.                         // Trim spaces
  6796.                         trim(key)
  6797.                         trim(value)
  6798.                        
  6799.                         // Add to sounds array
  6800.                         ArrayPushString(zombie_idle, key)
  6801.                     }
  6802.                 }
  6803.                 else if (equal(key, "ZOMBIE IDLE LAST"))
  6804.                 {
  6805.                     // Parse sounds
  6806.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6807.                     {
  6808.                         // Trim spaces
  6809.                         trim(key)
  6810.                         trim(value)
  6811.                        
  6812.                         // Add to sounds array
  6813.                         ArrayPushString(zombie_idle_last, key)
  6814.                     }
  6815.                 }
  6816.                 else if (equal(key, "ZOMBIE MADNESS"))
  6817.                 {
  6818.                     // Parse sounds
  6819.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6820.                     {
  6821.                         // Trim spaces
  6822.                         trim(key)
  6823.                         trim(value)
  6824.                        
  6825.                         // Add to sounds array
  6826.                         ArrayPushString(zombie_madness, key)
  6827.                     }
  6828.                 }
  6829.                 else if (equal(key, "ROUND NEMESIS"))
  6830.                 {
  6831.                     // Parse sounds
  6832.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6833.                     {
  6834.                         // Trim spaces
  6835.                         trim(key)
  6836.                         trim(value)
  6837.                        
  6838.                         // Add to sounds array
  6839.                         ArrayPushString(sound_nemesis, key)
  6840.                     }
  6841.                 }
  6842.                 else if (equal(key, "ROUND SURVIVOR"))
  6843.                 {
  6844.                     // Parse sounds
  6845.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6846.                     {
  6847.                         // Trim spaces
  6848.                         trim(key)
  6849.                         trim(value)
  6850.                        
  6851.                         // Add to sounds array
  6852.                         ArrayPushString(sound_survivor, key)
  6853.                     }
  6854.                 }
  6855.                 else if (equal(key, "ROUND SWARM"))
  6856.                 {
  6857.                     // Parse sounds
  6858.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6859.                     {
  6860.                         // Trim spaces
  6861.                         trim(key)
  6862.                         trim(value)
  6863.                        
  6864.                         // Add to sounds array
  6865.                         ArrayPushString(sound_swarm, key)
  6866.                     }
  6867.                 }
  6868.                 else if (equal(key, "ROUND MULTI"))
  6869.                 {
  6870.                     // Parse sounds
  6871.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6872.                     {
  6873.                         // Trim spaces
  6874.                         trim(key)
  6875.                         trim(value)
  6876.                        
  6877.                         // Add to sounds array
  6878.                         ArrayPushString(sound_multi, key)
  6879.                     }
  6880.                 }
  6881.                 else if (equal(key, "ROUND PLAGUE"))
  6882.                 {
  6883.                     // Parse sounds
  6884.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6885.                     {
  6886.                         // Trim spaces
  6887.                         trim(key)
  6888.                         trim(value)
  6889.                        
  6890.                         // Add to sounds array
  6891.                         ArrayPushString(sound_plague, key)
  6892.                     }
  6893.                 }
  6894.                 else if (equal(key, "GRENADE INFECT EXPLODE"))
  6895.                 {
  6896.                     // Parse sounds
  6897.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6898.                     {
  6899.                         // Trim spaces
  6900.                         trim(key)
  6901.                         trim(value)
  6902.                        
  6903.                         // Add to sounds array
  6904.                         ArrayPushString(grenade_infect, key)
  6905.                     }
  6906.                 }
  6907.                 else if (equal(key, "GRENADE INFECT PLAYER"))
  6908.                 {
  6909.                     // Parse sounds
  6910.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6911.                     {
  6912.                         // Trim spaces
  6913.                         trim(key)
  6914.                         trim(value)
  6915.                        
  6916.                         // Add to sounds array
  6917.                         ArrayPushString(grenade_infect_player, key)
  6918.                     }
  6919.                 }
  6920.                 else if (equal(key, "GRENADE FIRE EXPLODE"))
  6921.                 {
  6922.                     // Parse sounds
  6923.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6924.                     {
  6925.                         // Trim spaces
  6926.                         trim(key)
  6927.                         trim(value)
  6928.                        
  6929.                         // Add to sounds array
  6930.                         ArrayPushString(grenade_fire, key)
  6931.                     }
  6932.                 }
  6933.                 else if (equal(key, "GRENADE FIRE PLAYER"))
  6934.                 {
  6935.                     // Parse sounds
  6936.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6937.                     {
  6938.                         // Trim spaces
  6939.                         trim(key)
  6940.                         trim(value)
  6941.                        
  6942.                         // Add to sounds array
  6943.                         ArrayPushString(grenade_fire_player, key)
  6944.                     }
  6945.                 }
  6946.                 else if (equal(key, "GRENADE FROST EXPLODE"))
  6947.                 {
  6948.                     // Parse sounds
  6949.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6950.                     {
  6951.                         // Trim spaces
  6952.                         trim(key)
  6953.                         trim(value)
  6954.                        
  6955.                         // Add to sounds array
  6956.                         ArrayPushString(grenade_frost, key)
  6957.                     }
  6958.                 }
  6959.                 else if (equal(key, "GRENADE FROST PLAYER"))
  6960.                 {
  6961.                     // Parse sounds
  6962.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6963.                     {
  6964.                         // Trim spaces
  6965.                         trim(key)
  6966.                         trim(value)
  6967.                        
  6968.                         // Add to sounds array
  6969.                         ArrayPushString(grenade_frost_player, key)
  6970.                     }
  6971.                 }
  6972.                 else if (equal(key, "GRENADE FROST BREAK"))
  6973.                 {
  6974.                     // Parse sounds
  6975.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6976.                     {
  6977.                         // Trim spaces
  6978.                         trim(key)
  6979.                         trim(value)
  6980.                        
  6981.                         // Add to sounds array
  6982.                         ArrayPushString(grenade_frost_break, key)
  6983.                     }
  6984.                 }
  6985.                 else if (equal(key, "GRENADE FLARE"))
  6986.                 {
  6987.                     // Parse sounds
  6988.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  6989.                     {
  6990.                         // Trim spaces
  6991.                         trim(key)
  6992.                         trim(value)
  6993.                        
  6994.                         // Add to sounds array
  6995.                         ArrayPushString(grenade_flare, key)
  6996.                     }
  6997.                 }
  6998.                 else if (equal(key, "ANTIDOTE"))
  6999.                 {
  7000.                     // Parse sounds
  7001.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7002.                     {
  7003.                         // Trim spaces
  7004.                         trim(key)
  7005.                         trim(value)
  7006.                        
  7007.                         // Add to sounds array
  7008.                         ArrayPushString(sound_antidote, key)
  7009.                     }
  7010.                 }
  7011.                 else if (equal(key, "THUNDER"))
  7012.                 {
  7013.                     // Parse sounds
  7014.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7015.                     {
  7016.                         // Trim spaces
  7017.                         trim(key)
  7018.                         trim(value)
  7019.                        
  7020.                         // Add to sounds array
  7021.                         ArrayPushString(sound_thunder, key)
  7022.                     }
  7023.                 }
  7024.             }
  7025.             case SECTION_AMBIENCE_SOUNDS:
  7026.             {
  7027.                 if (equal(key, "INFECTION ENABLE"))
  7028.                     g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] = str_to_num(value)
  7029.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION SOUNDS"))
  7030.                 {
  7031.                     // Parse sounds
  7032.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7033.                     {
  7034.                         // Trim spaces
  7035.                         trim(key)
  7036.                         trim(value)
  7037.                        
  7038.                         // Add to sounds array
  7039.                         ArrayPushString(sound_ambience1, key)
  7040.                         ArrayPushCell(sound_ambience1_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7041.                     }
  7042.                 }
  7043.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION DURATIONS"))
  7044.                 {
  7045.                     // Parse sounds
  7046.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7047.                     {
  7048.                         // Trim spaces
  7049.                         trim(key)
  7050.                         trim(value)
  7051.                        
  7052.                         // Add to sounds array
  7053.                         ArrayPushCell(sound_ambience1_duration, str_to_num(key))
  7054.                     }
  7055.                 }
  7056.                 else if (equal(key, "NEMESIS ENABLE"))
  7057.                     g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] = str_to_num(value)
  7058.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS SOUNDS"))
  7059.                 {
  7060.                     // Parse sounds
  7061.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7062.                     {
  7063.                         // Trim spaces
  7064.                         trim(key)
  7065.                         trim(value)
  7066.                        
  7067.                         // Add to sounds array
  7068.                         ArrayPushString(sound_ambience2, key)
  7069.                         ArrayPushCell(sound_ambience2_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7070.                     }
  7071.                 }
  7072.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS DURATIONS"))
  7073.                 {
  7074.                     // Parse sounds
  7075.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7076.                     {
  7077.                         // Trim spaces
  7078.                         trim(key)
  7079.                         trim(value)
  7080.                        
  7081.                         // Add to sounds array
  7082.                         ArrayPushCell(sound_ambience2_duration, str_to_num(key))
  7083.                     }
  7084.                 }
  7085.                 else if (equal(key, "SURVIVOR ENABLE"))
  7086.                     g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] = str_to_num(value)
  7087.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR SOUNDS"))
  7088.                 {
  7089.                     // Parse sounds
  7090.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7091.                     {
  7092.                         // Trim spaces
  7093.                         trim(key)
  7094.                         trim(value)
  7095.                        
  7096.                         // Add to sounds array
  7097.                         ArrayPushString(sound_ambience3, key)
  7098.                         ArrayPushCell(sound_ambience3_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7099.                     }
  7100.                 }
  7101.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR DURATIONS"))
  7102.                 {
  7103.                     // Parse sounds
  7104.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7105.                     {
  7106.                         // Trim spaces
  7107.                         trim(key)
  7108.                         trim(value)
  7109.                        
  7110.                         // Add to sounds array
  7111.                         ArrayPushCell(sound_ambience3_duration, str_to_num(key))
  7112.                     }
  7113.                 }
  7114.                 else if (equal(key, "SWARM ENABLE"))
  7115.                     g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] = str_to_num(value)
  7116.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM SOUNDS"))
  7117.                 {
  7118.                     // Parse sounds
  7119.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7120.                     {
  7121.                         // Trim spaces
  7122.                         trim(key)
  7123.                         trim(value)
  7124.                        
  7125.                         // Add to sounds array
  7126.                         ArrayPushString(sound_ambience4, key)
  7127.                         ArrayPushCell(sound_ambience4_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7128.                     }
  7129.                 }
  7130.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM DURATIONS"))
  7131.                 {
  7132.                     // Parse sounds
  7133.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7134.                     {
  7135.                         // Trim spaces
  7136.                         trim(key)
  7137.                         trim(value)
  7138.                        
  7139.                         // Add to sounds array
  7140.                         ArrayPushCell(sound_ambience4_duration, str_to_num(key))
  7141.                     }
  7142.                 }
  7143.                 else if (equal(key, "PLAGUE ENABLE"))
  7144.                     g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] = str_to_num(value)
  7145.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE SOUNDS"))
  7146.                 {
  7147.                     // Parse sounds
  7148.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7149.                     {
  7150.                         // Trim spaces
  7151.                         trim(key)
  7152.                         trim(value)
  7153.                        
  7154.                         // Add to sounds array
  7155.                         ArrayPushString(sound_ambience5, key)
  7156.                         ArrayPushCell(sound_ambience5_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
  7157.                     }
  7158.                 }
  7159.                 else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE DURATIONS"))
  7160.                 {
  7161.                     // Parse sounds
  7162.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7163.                     {
  7164.                         // Trim spaces
  7165.                         trim(key)
  7166.                         trim(value)
  7167.                        
  7168.                         // Add to sounds array
  7169.                         ArrayPushCell(sound_ambience5_duration, str_to_num(key))
  7170.                     }
  7171.                 }
  7172.             }
  7173.             case SECTION_BUY_MENU_WEAPONS:
  7174.             {
  7175.                 if (equal(key, "PRIMARY"))
  7176.                 {
  7177.                     // Parse weapons
  7178.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7179.                     {
  7180.                         // Trim spaces
  7181.                         trim(key)
  7182.                         trim(value)
  7183.                        
  7184.                         // Add to weapons array
  7185.                         ArrayPushString(g_primary_items, key)
  7186.                         ArrayPushCell(g_primary_weaponids, cs_weapon_name_to_id(key))
  7187.                     }
  7188.                 }
  7189.                 else if (equal(key, "SECONDARY"))
  7190.                 {
  7191.                     // Parse weapons
  7192.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7193.                     {
  7194.                         // Trim spaces
  7195.                         trim(key)
  7196.                         trim(value)
  7197.                        
  7198.                         // Add to weapons array
  7199.                         ArrayPushString(g_secondary_items, key)
  7200.                         ArrayPushCell(g_secondary_weaponids, cs_weapon_name_to_id(key))
  7201.                     }
  7202.                 }
  7203.                 else if (equal(key, "ADDITIONAL ITEMS"))
  7204.                 {
  7205.                     // Parse weapons
  7206.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7207.                     {
  7208.                         // Trim spaces
  7209.                         trim(key)
  7210.                         trim(value)
  7211.                        
  7212.                         // Add to weapons array
  7213.                         ArrayPushString(g_additional_items, key)
  7214.                     }
  7215.                 }
  7216.             }
  7217.             case SECTION_EXTRA_ITEMS_WEAPONS:
  7218.             {
  7219.                 if (equal(key, "NAMES"))
  7220.                 {
  7221.                     // Parse weapon items
  7222.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7223.                     {
  7224.                         // Trim spaces
  7225.                         trim(key)
  7226.                         trim(value)
  7227.                        
  7228.                         // Add to weapons array
  7229.                         ArrayPushString(g_extraweapon_names, key)
  7230.                     }
  7231.                 }
  7232.                 else if (equal(key, "ITEMS"))
  7233.                 {
  7234.                     // Parse weapon items
  7235.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7236.                     {
  7237.                         // Trim spaces
  7238.                         trim(key)
  7239.                         trim(value)
  7240.                        
  7241.                         // Add to weapons array
  7242.                         ArrayPushString(g_extraweapon_items, key)
  7243.                     }
  7244.                 }
  7245.                 else if (equal(key, "COSTS"))
  7246.                 {
  7247.                     // Parse weapon items
  7248.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7249.                     {
  7250.                         // Trim spaces
  7251.                         trim(key)
  7252.                         trim(value)
  7253.                        
  7254.                         // Add to weapons array
  7255.                         ArrayPushCell(g_extraweapon_costs, str_to_num(key))
  7256.                     }
  7257.                 }
  7258.             }
  7259.             case SECTION_HARD_CODED_ITEMS_COSTS:
  7260.             {
  7261.                 if (equal(key, "NIGHT VISION"))
  7262.                     g_extra_costs2[EXTRA_NVISION] = str_to_num(value)
  7263.                 else if (equal(key, "ANTIDOTE"))
  7264.                     g_extra_costs2[EXTRA_ANTIDOTE] = str_to_num(value)
  7265.                 else if (equal(key, "ZOMBIE MADNESS"))
  7266.                     g_extra_costs2[EXTRA_MADNESS] = str_to_num(value)
  7267.                 else if (equal(key, "INFECTION BOMB"))
  7268.                     g_extra_costs2[EXTRA_INFBOMB] = str_to_num(value)
  7269.             }
  7270.             case SECTION_WEATHER_EFFECTS:
  7271.             {
  7272.                 if (equal(key, "RAIN"))
  7273.                     g_ambience_rain = str_to_num(value)
  7274.                 else if (equal(key, "SNOW"))
  7275.                     g_ambience_snow = str_to_num(value)
  7276.                 else if (equal(key, "FOG"))
  7277.                     g_ambience_fog = str_to_num(value)
  7278.                 else if (equal(key, "FOG DENSITY"))
  7279.                     copy(g_fog_density, charsmax(g_fog_density), value)
  7280.                 else if (equal(key, "FOG COLOR"))
  7281.                     copy(g_fog_color, charsmax(g_fog_color), value)
  7282.             }
  7283.             case SECTION_SKY:
  7284.             {
  7285.                 if (equal(key, "ENABLE"))
  7286.                     g_sky_enable = str_to_num(value)
  7287.                 else if (equal(key, "SKY NAMES"))
  7288.                 {
  7289.                     // Parse sky names
  7290.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7291.                     {
  7292.                         // Trim spaces
  7293.                         trim(key)
  7294.                         trim(value)
  7295.                        
  7296.                         // Add to skies array
  7297.                         ArrayPushString(g_sky_names, key)
  7298.                        
  7299.                         // Preache custom sky files
  7300.                         formatex(linedata, charsmax(linedata), "gfx/env/%sbk.tga", key)
  7301.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7302.                         formatex(linedata, charsmax(linedata), "gfx/env/%sdn.tga", key)
  7303.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7304.                         formatex(linedata, charsmax(linedata), "gfx/env/%sft.tga", key)
  7305.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7306.                         formatex(linedata, charsmax(linedata), "gfx/env/%slf.tga", key)
  7307.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7308.                         formatex(linedata, charsmax(linedata), "gfx/env/%srt.tga", key)
  7309.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7310.                         formatex(linedata, charsmax(linedata), "gfx/env/%sup.tga", key)
  7311.                         engfunc(EngFunc_PrecacheGeneric, linedata)
  7312.                     }
  7313.                 }
  7314.             }
  7315.             case SECTION_LIGHTNING:
  7316.             {
  7317.                 if (equal(key, "LIGHTS"))
  7318.                 {
  7319.                     // Parse lights
  7320.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7321.                     {
  7322.                         // Trim spaces
  7323.                         trim(key)
  7324.                         trim(value)
  7325.                        
  7326.                         // Add to lightning array
  7327.                         ArrayPushString(lights_thunder, key)
  7328.                     }
  7329.                 }
  7330.             }
  7331.             case SECTION_ZOMBIE_DECALS:
  7332.             {
  7333.                 if (equal(key, "DECALS"))
  7334.                 {
  7335.                     // Parse decals
  7336.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7337.                     {
  7338.                         // Trim spaces
  7339.                         trim(key)
  7340.                         trim(value)
  7341.                        
  7342.                         // Add to zombie decals array
  7343.                         ArrayPushCell(zombie_decals, str_to_num(key))
  7344.                     }
  7345.                 }
  7346.             }
  7347.             case SECTION_KNOCKBACK:
  7348.             {
  7349.                 // Format weapon entity name
  7350.                 strtolower(key)
  7351.                 format(key, charsmax(key), "weapon_%s", key)
  7352.                
  7353.                 // Add value to knockback power array
  7354.                 kb_weapon_power[cs_weapon_name_to_id(key)] = str_to_float(value)
  7355.             }
  7356.             case SECTION_OBJECTIVE_ENTS:
  7357.             {
  7358.                 if (equal(key, "CLASSNAMES"))
  7359.                 {
  7360.                     // Parse classnames
  7361.                     while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7362.                     {
  7363.                         // Trim spaces
  7364.                         trim(key)
  7365.                         trim(value)
  7366.                        
  7367.                         // Add to objective ents array
  7368.                         ArrayPushString(g_objective_ents, key)
  7369.                     }
  7370.                 }
  7371.             }
  7372.             case SECTION_SVC_BAD:
  7373.             {
  7374.                 if (equal(key, "MODELCHANGE DELAY"))
  7375.                     g_modelchange_delay = str_to_float(value)
  7376.                 else if (equal(key, "HANDLE MODELS ON SEPARATE ENT"))
  7377.                     g_handle_models_on_separate_ent = str_to_num(value)
  7378.                 else if (equal(key, "SET MODELINDEX OFFSET"))
  7379.                     g_set_modelindex_offset = str_to_num(value)
  7380.             }
  7381.         }
  7382.     }
  7383.     if (file) fclose(file)
  7384.    
  7385.     // Build zombie classes file path
  7386.     get_configsdir(path, charsmax(path))
  7387.     format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
  7388.    
  7389.     // Parse if present
  7390.     if (file_exists(path))
  7391.     {
  7392.         // Open zombie classes file for reading
  7393.         file = fopen(path, "rt")
  7394.        
  7395.         while (file && !feof(file))
  7396.         {
  7397.             // Read one line at a time
  7398.             fgets(file, linedata, charsmax(linedata))
  7399.            
  7400.             // Replace newlines with a null character to prevent headaches
  7401.             replace(linedata, charsmax(linedata), "^n", "")
  7402.            
  7403.             // Blank line or comment
  7404.             if (!linedata[0] || linedata[0] == ';') continue;
  7405.            
  7406.             // New class starting
  7407.             if (linedata[0] == '[')
  7408.             {
  7409.                 // Remove first and last characters (braces)
  7410.                 linedata[strlen(linedata) - 1] = 0
  7411.                 copy(linedata, charsmax(linedata), linedata[1])
  7412.                
  7413.                 // Store its real name for future reference
  7414.                 ArrayPushString(g_zclass2_realname, linedata)
  7415.                 continue;
  7416.             }
  7417.            
  7418.             // Get key and value(s)
  7419.             strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  7420.            
  7421.             // Trim spaces
  7422.             trim(key)
  7423.             trim(value)
  7424.            
  7425.             if (equal(key, "NAME"))
  7426.                 ArrayPushString(g_zclass2_name, value)
  7427.             else if (equal(key, "INFO"))
  7428.                 ArrayPushString(g_zclass2_info, value)
  7429.             else if (equal(key, "MODELS"))
  7430.             {
  7431.                 // Set models start index
  7432.                 ArrayPushCell(g_zclass2_modelsstart, ArraySize(g_zclass2_playermodel))
  7433.                
  7434.                 // Parse class models
  7435.                 while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7436.                 {
  7437.                     // Trim spaces
  7438.                     trim(key)
  7439.                     trim(value)
  7440.                    
  7441.                     // Add to class models array
  7442.                     ArrayPushString(g_zclass2_playermodel, key)
  7443.                     ArrayPushCell(g_zclass2_modelindex, -1)
  7444.                 }
  7445.                
  7446.                 // Set models end index
  7447.                 ArrayPushCell(g_zclass2_modelsend, ArraySize(g_zclass2_playermodel))
  7448.             }
  7449.             else if (equal(key, "CLAWMODEL"))
  7450.                 ArrayPushString(g_zclass2_clawmodel, value)
  7451.             else if (equal(key, "HEALTH"))
  7452.                 ArrayPushCell(g_zclass2_hp, str_to_num(value))
  7453.             else if (equal(key, "SPEED"))
  7454.                 ArrayPushCell(g_zclass2_spd, str_to_num(value))
  7455.             else if (equal(key, "GRAVITY"))
  7456.                 ArrayPushCell(g_zclass2_grav, str_to_float(value))
  7457.             else if (equal(key, "KNOCKBACK"))
  7458.                 ArrayPushCell(g_zclass2_kb, str_to_float(value))
  7459.         }
  7460.         if (file) fclose(file)
  7461.     }
  7462.    
  7463.     // Build extra items file path
  7464.     get_configsdir(path, charsmax(path))
  7465.     format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
  7466.    
  7467.     // Parse if present
  7468.     if (file_exists(path))
  7469.     {
  7470.         // Open extra items file for reading
  7471.         file = fopen(path, "rt")
  7472.        
  7473.         while (file && !feof(file))
  7474.         {
  7475.             // Read one line at a time
  7476.             fgets(file, linedata, charsmax(linedata))
  7477.            
  7478.             // Replace newlines with a null character to prevent headaches
  7479.             replace(linedata, charsmax(linedata), "^n", "")
  7480.            
  7481.             // Blank line or comment
  7482.             if (!linedata[0] || linedata[0] == ';') continue;
  7483.            
  7484.             // New item starting
  7485.             if (linedata[0] == '[')
  7486.             {
  7487.                 // Remove first and last characters (braces)
  7488.                 linedata[strlen(linedata) - 1] = 0
  7489.                 copy(linedata, charsmax(linedata), linedata[1])
  7490.                
  7491.                 // Store its real name for future reference
  7492.                 ArrayPushString(g_extraitem2_realname, linedata)
  7493.                 continue;
  7494.             }
  7495.            
  7496.             // Get key and value(s)
  7497.             strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
  7498.            
  7499.             // Trim spaces
  7500.             trim(key)
  7501.             trim(value)
  7502.            
  7503.             if (equal(key, "NAME"))
  7504.                 ArrayPushString(g_extraitem2_name, value)
  7505.             else if (equal(key, "COST"))
  7506.                 ArrayPushCell(g_extraitem2_cost, str_to_num(value))
  7507.             else if (equal(key, "TEAMS"))
  7508.             {
  7509.                 // Clear teams bitsum
  7510.                 teams = 0
  7511.                
  7512.                 // Parse teams
  7513.                 while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
  7514.                 {
  7515.                     // Trim spaces
  7516.                     trim(key)
  7517.                     trim(value)
  7518.                    
  7519.                     if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_ZOMBIE]))
  7520.                         teams |= ZP_TEAM_ZOMBIE
  7521.                     else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_HUMAN]))
  7522.                         teams |= ZP_TEAM_HUMAN
  7523.                     else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_NEMESIS]))
  7524.                         teams |= ZP_TEAM_NEMESIS
  7525.                     else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_SURVIVOR]))
  7526.                         teams |= ZP_TEAM_SURVIVOR
  7527.                 }
  7528.                
  7529.                 // Add to teams array
  7530.                 ArrayPushCell(g_extraitem2_team, teams)
  7531.             }
  7532.         }
  7533.         if (file) fclose(file)
  7534.     }
  7535. }
  7536.  
  7537. save_customization()
  7538. {
  7539.     new i, k, buffer[512]
  7540.    
  7541.     // Build zombie classes file path
  7542.     new path[64]
  7543.     get_configsdir(path, charsmax(path))
  7544.     format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
  7545.    
  7546.     // Open zombie classes file for appending data
  7547.     new file = fopen(path, "at"), size = ArraySize(g_zclass_name)
  7548.    
  7549.     // Add any new zombie classes data at the end if needed
  7550.     for (i = 0; i < size; i++)
  7551.     {
  7552.         if (ArrayGetCell(g_zclass_new, i))
  7553.         {
  7554.             // Add real name
  7555.             ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
  7556.             format(buffer, charsmax(buffer), "^n[%s]", buffer)
  7557.             fputs(file, buffer)
  7558.            
  7559.             // Add caption
  7560.             ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
  7561.             format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
  7562.             fputs(file, buffer)
  7563.            
  7564.             // Add info
  7565.             ArrayGetString(g_zclass_info, i, buffer, charsmax(buffer))
  7566.             format(buffer, charsmax(buffer), "^nINFO = %s", buffer)
  7567.             fputs(file, buffer)
  7568.            
  7569.             // Add models
  7570.             for (k = ArrayGetCell(g_zclass_modelsstart, i); k < ArrayGetCell(g_zclass_modelsend, i); k++)
  7571.             {
  7572.                 if (k == ArrayGetCell(g_zclass_modelsstart, i))
  7573.                 {
  7574.                     // First model, overwrite buffer
  7575.                     ArrayGetString(g_zclass_playermodel, k, buffer, charsmax(buffer))
  7576.                 }
  7577.                 else
  7578.                 {
  7579.                     // Successive models, append to buffer
  7580.                     ArrayGetString(g_zclass_playermodel, k, path, charsmax(path))
  7581.                     format(buffer, charsmax(buffer), "%s , %s", buffer, path)
  7582.                 }
  7583.             }
  7584.             format(buffer, charsmax(buffer), "^nMODELS = %s", buffer)
  7585.             fputs(file, buffer)
  7586.            
  7587.             // Add clawmodel
  7588.             ArrayGetString(g_zclass_clawmodel, i, buffer, charsmax(buffer))
  7589.             format(buffer, charsmax(buffer), "^nCLAWMODEL = %s", buffer)
  7590.             fputs(file, buffer)
  7591.            
  7592.             // Add health
  7593.             formatex(buffer, charsmax(buffer), "^nHEALTH = %d", ArrayGetCell(g_zclass_hp, i))
  7594.             fputs(file, buffer)
  7595.            
  7596.             // Add speed
  7597.             formatex(buffer, charsmax(buffer), "^nSPEED = %d", ArrayGetCell(g_zclass_spd, i))
  7598.             fputs(file, buffer)
  7599.            
  7600.             // Add gravity
  7601.             formatex(buffer, charsmax(buffer), "^nGRAVITY = %.2f", Float:ArrayGetCell(g_zclass_grav, i))
  7602.             fputs(file, buffer)
  7603.            
  7604.             // Add knockback
  7605.             formatex(buffer, charsmax(buffer), "^nKNOCKBACK = %.2f^n", Float:ArrayGetCell(g_zclass_kb, i))
  7606.             fputs(file, buffer)
  7607.         }
  7608.     }
  7609.     fclose(file)
  7610.    
  7611.     // Build extra items file path
  7612.     get_configsdir(path, charsmax(path))
  7613.     format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
  7614.    
  7615.     // Open extra items file for appending data
  7616.     file = fopen(path, "at")
  7617.     size = ArraySize(g_extraitem_name)
  7618.    
  7619.     // Add any new extra items data at the end if needed
  7620.     for (i = EXTRAS_CUSTOM_STARTID; i < size; i++)
  7621.     {
  7622.         if (ArrayGetCell(g_extraitem_new, i))
  7623.         {
  7624.             // Add real name
  7625.             ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
  7626.             format(buffer, charsmax(buffer), "^n[%s]", buffer)
  7627.             fputs(file, buffer)
  7628.            
  7629.             // Add caption
  7630.             ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
  7631.             format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
  7632.             fputs(file, buffer)
  7633.            
  7634.             // Add cost
  7635.             formatex(buffer, charsmax(buffer), "^nCOST = %d", ArrayGetCell(g_extraitem_cost, i))
  7636.             fputs(file, buffer)
  7637.            
  7638.             // Add team
  7639.             formatex(buffer, charsmax(buffer), "^nTEAMS = %s^n", ZP_TEAM_NAMES[ArrayGetCell(g_extraitem_team, i)])
  7640.             fputs(file, buffer)
  7641.         }
  7642.     }
  7643.     fclose(file)
  7644.    
  7645.     // Free arrays containing class/item overrides
  7646.     ArrayDestroy(g_zclass2_realname)
  7647.     ArrayDestroy(g_zclass2_name)
  7648.     ArrayDestroy(g_zclass2_info)
  7649.     ArrayDestroy(g_zclass2_modelsstart)
  7650.     ArrayDestroy(g_zclass2_modelsend)
  7651.     ArrayDestroy(g_zclass2_playermodel)
  7652.     ArrayDestroy(g_zclass2_modelindex)
  7653.     ArrayDestroy(g_zclass2_clawmodel)
  7654.     ArrayDestroy(g_zclass2_hp)
  7655.     ArrayDestroy(g_zclass2_spd)
  7656.     ArrayDestroy(g_zclass2_grav)
  7657.     ArrayDestroy(g_zclass2_kb)
  7658.     ArrayDestroy(g_zclass_new)
  7659.     ArrayDestroy(g_extraitem2_realname)
  7660.     ArrayDestroy(g_extraitem2_name)
  7661.     ArrayDestroy(g_extraitem2_cost)
  7662.     ArrayDestroy(g_extraitem2_team)
  7663.     ArrayDestroy(g_extraitem_new)
  7664. }
  7665.  
  7666. // Register Ham Forwards for CZ bots
  7667. public register_ham_czbots(id)
  7668. {
  7669.     // Make sure it's a CZ bot and it's still connected
  7670.     if (g_hamczbots || !g_isconnected[id] || !get_pcvar_num(cvar_botquota))
  7671.         return;
  7672.    
  7673.     RegisterHamFromEntity(Ham_Spawn, id, "fw_PlayerSpawn_Post", 1)
  7674.     RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled")
  7675.     RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled_Post", 1)
  7676.     RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage")
  7677.     RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage_Post", 1)
  7678.     RegisterHamFromEntity(Ham_TraceAttack, id, "fw_TraceAttack")
  7679.     RegisterHamFromEntity(Ham_Player_ResetMaxSpeed, id, "fw_ResetMaxSpeed_Post", 1)
  7680.    
  7681.     // Ham forwards for CZ bots succesfully registered
  7682.     g_hamczbots = true
  7683.    
  7684.     // If the bot has already spawned, call the forward manually for him
  7685.     if (is_user_alive(id)) fw_PlayerSpawn_Post(id)
  7686. }
  7687.  
  7688. // Disable minmodels task
  7689. public disable_minmodels(id)
  7690. {
  7691.     if (!g_isconnected[id]) return;
  7692.     client_cmd(id, "cl_minmodels 0")
  7693. }
  7694.  
  7695. // Bots automatically buy extra items
  7696. public bot_buy_extras(taskid)
  7697. {
  7698.     // Nemesis or Survivor bots have nothing to buy by default
  7699.     if (!g_isalive[ID_SPAWN] || g_survivor[ID_SPAWN] || g_nemesis[ID_SPAWN])
  7700.         return;
  7701.    
  7702.     if (!g_zombie[ID_SPAWN]) // human bots
  7703.     {
  7704.         // Attempt to buy Night Vision
  7705.         buy_extra_item(ID_SPAWN, EXTRA_NVISION)
  7706.        
  7707.         // Attempt to buy a weapon
  7708.         buy_extra_item(ID_SPAWN, random_num(EXTRA_WEAPONS_STARTID, EXTRAS_CUSTOM_STARTID-1))
  7709.     }
  7710.     else // zombie bots
  7711.     {
  7712.         // Attempt to buy an Antidote
  7713.         buy_extra_item(ID_SPAWN, EXTRA_ANTIDOTE)
  7714.     }
  7715. }
  7716.  
  7717. // Refill BP Ammo Task
  7718. public refill_bpammo(const args[], id)
  7719. {
  7720.     // Player died or turned into a zombie
  7721.     if (!g_isalive[id] || g_zombie[id])
  7722.         return;
  7723.    
  7724.     set_msg_block(g_msgAmmoPickup, BLOCK_ONCE)
  7725.     ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[REFILL_WEAPONID], AMMOTYPE[REFILL_WEAPONID], MAXBPAMMO[REFILL_WEAPONID])
  7726. }
  7727.  
  7728. // Balance Teams Task
  7729. balance_teams()
  7730. {
  7731.     // Get amount of users playing
  7732.     static iPlayersnum
  7733.     iPlayersnum = fnGetPlaying()
  7734.    
  7735.     // No players, don't bother
  7736.     if (iPlayersnum < 1) return;
  7737.    
  7738.     // Split players evenly
  7739.     static iTerrors, iMaxTerrors, id, team[33]
  7740.     iMaxTerrors = iPlayersnum/2
  7741.     iTerrors = 0
  7742.    
  7743.     // First, set everyone to CT
  7744.     for (id = 1; id <= g_maxplayers; id++)
  7745.     {
  7746.         // Skip if not connected
  7747.         if (!g_isconnected[id])
  7748.             continue;
  7749.        
  7750.         team[id] = fm_cs_get_user_team(id)
  7751.        
  7752.         // Skip if not playing
  7753.         if (team[id] == FM_CS_TEAM_SPECTATOR || team[id] == FM_CS_TEAM_UNASSIGNED)
  7754.             continue;
  7755.        
  7756.         // Set team
  7757.         remove_task(id+TASK_TEAM)
  7758.         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  7759.         team[id] = FM_CS_TEAM_CT
  7760.     }
  7761.    
  7762.     // Then randomly set half of the players to Terrorists
  7763.     while (iTerrors < iMaxTerrors)
  7764.     {
  7765.         // Keep looping through all players
  7766.         if (++id > g_maxplayers) id = 1
  7767.        
  7768.         // Skip if not connected
  7769.         if (!g_isconnected[id])
  7770.             continue;
  7771.        
  7772.         // Skip if not playing or already a Terrorist
  7773.         if (team[id] != FM_CS_TEAM_CT)
  7774.             continue;
  7775.        
  7776.         // Random chance
  7777.         if (random_num(0, 1))
  7778.         {
  7779.             fm_cs_set_user_team(id, FM_CS_TEAM_T)
  7780.             team[id] = FM_CS_TEAM_T
  7781.             iTerrors++
  7782.         }
  7783.     }
  7784. }
  7785.  
  7786. // Welcome Message Task
  7787. public welcome_msg()
  7788. {
  7789.     // Show mod info
  7790.     zp_colored_print(0, "^x01**** ^x04%s^x01 ****", g_modname)
  7791.     zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "NOTICE_INFO1")
  7792.     if (!get_pcvar_num(cvar_infammo)) zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "NOTICE_INFO2")
  7793.    
  7794.     // Show T-virus HUD notice
  7795.     set_hudmessage(0, 125, 200, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
  7796.     ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_VIRUS_FREE")
  7797. }
  7798.  
  7799. // Respawn Player Task (deathmatch)
  7800. public respawn_player_task(taskid)
  7801. {
  7802.     // Already alive or round ended
  7803.     if (g_isalive[ID_SPAWN] || g_endround)
  7804.         return;
  7805.    
  7806.     // Get player's team
  7807.     static team
  7808.     team = fm_cs_get_user_team(ID_SPAWN)
  7809.    
  7810.     // Player moved to spectators
  7811.     if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  7812.         return;
  7813.    
  7814.     // Respawn player automatically if allowed on current round
  7815.     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)))
  7816.     {
  7817.         // Infection rounds = none of the above
  7818.         if (!get_pcvar_num(cvar_allowrespawninfection) && !g_survround && !g_nemround && !g_swarmround && !g_plagueround)
  7819.             return;
  7820.        
  7821.         // Respawn if only the last human is left? (ignore this setting on survivor rounds)
  7822.         if (!g_survround && !get_pcvar_num(cvar_respawnafterlast) && fnGetHumans() <= 1)
  7823.             return;
  7824.        
  7825.         // Respawn as zombie?
  7826.         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))
  7827.             g_respawn_as_zombie[ID_SPAWN] = true
  7828.        
  7829.         // Override respawn as zombie setting on nemesis and survivor rounds
  7830.         if (g_survround) g_respawn_as_zombie[ID_SPAWN] = true
  7831.         else if (g_nemround) g_respawn_as_zombie[ID_SPAWN] = false
  7832.        
  7833.         respawn_player_manually(ID_SPAWN)
  7834.     }
  7835. }
  7836.  
  7837. // Respawn Player Check Task (if killed by worldspawn)
  7838. public respawn_player_check_task(taskid)
  7839. {
  7840.     // Successfully spawned or round ended
  7841.     if (g_isalive[ID_SPAWN] || g_endround)
  7842.         return;
  7843.    
  7844.     // Get player's team
  7845.     static team
  7846.     team = fm_cs_get_user_team(ID_SPAWN)
  7847.    
  7848.     // Player moved to spectators
  7849.     if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
  7850.         return;
  7851.    
  7852.     // If player was being spawned as a zombie, set the flag again
  7853.     if (g_zombie[ID_SPAWN]) g_respawn_as_zombie[ID_SPAWN] = true
  7854.     else g_respawn_as_zombie[ID_SPAWN] = false
  7855.    
  7856.     respawn_player_manually(ID_SPAWN)
  7857. }
  7858.  
  7859. // Respawn Player Manually (called after respawn checks are done)
  7860. respawn_player_manually(id)
  7861. {
  7862.     // Set proper team before respawning, so that the TeamInfo message that's sent doesn't confuse PODBots
  7863.     if (g_respawn_as_zombie[id])
  7864.         fm_cs_set_user_team(id, FM_CS_TEAM_T)
  7865.     else
  7866.         fm_cs_set_user_team(id, FM_CS_TEAM_CT)
  7867.    
  7868.     // Respawning a player has never been so easy
  7869.     ExecuteHamB(Ham_CS_RoundRespawn, id)
  7870. }
  7871.  
  7872. // Check Round Task -check that we still have both zombies and humans on a round-
  7873. check_round(leaving_player)
  7874. {
  7875.     // Round ended or make_a_zombie task still active
  7876.     if (g_endround || task_exists(TASK_MAKEZOMBIE))
  7877.         return;
  7878.    
  7879.     // Get alive players count
  7880.     static iPlayersnum, id
  7881.     iPlayersnum = fnGetAlive()
  7882.    
  7883.     // Last alive player, don't bother
  7884.     if (iPlayersnum < 2)
  7885.         return;
  7886.    
  7887.     // Last zombie disconnecting
  7888.     if (g_zombie[leaving_player] && fnGetZombies() == 1)
  7889.     {
  7890.         // Only one CT left, don't bother
  7891.         if (fnGetHumans() == 1 && fnGetCTs() == 1)
  7892.             return;
  7893.        
  7894.         // Pick a random one to take his place
  7895.         while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
  7896.        
  7897.         // Show last zombie left notice
  7898.         zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_ZOMBIE_LEFT", g_playername[id])
  7899.        
  7900.         // Set player leaving flag
  7901.         g_lastplayerleaving = true
  7902.        
  7903.         // Turn into a Nemesis or just a zombie?
  7904.         if (g_nemesis[leaving_player])
  7905.             zombieme(id, 0, 1, 0, 0)
  7906.         else
  7907.             zombieme(id, 0, 0, 0, 0)
  7908.        
  7909.         // Remove player leaving flag
  7910.         g_lastplayerleaving = false
  7911.        
  7912.         // If Nemesis, set chosen player's health to that of the one who's leaving
  7913.         if (get_pcvar_num(cvar_keephealthondisconnect) && g_nemesis[leaving_player])
  7914.             fm_set_user_health(id, pev(leaving_player, pev_health))
  7915.     }
  7916.    
  7917.     // Last human disconnecting
  7918.     else if (!g_zombie[leaving_player] && fnGetHumans() == 1)
  7919.     {
  7920.         // Only one T left, don't bother
  7921.         if (fnGetZombies() == 1 && fnGetTs() == 1)
  7922.             return;
  7923.        
  7924.         // Pick a random one to take his place
  7925.         while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
  7926.        
  7927.         // Show last human left notice
  7928.         zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_HUMAN_LEFT", g_playername[id])
  7929.        
  7930.         // Set player leaving flag
  7931.         g_lastplayerleaving = true
  7932.        
  7933.         // Turn into a Survivor or just a human?
  7934.         if (g_survivor[leaving_player])
  7935.             humanme(id, 1, 0)
  7936.         else
  7937.             humanme(id, 0, 0)
  7938.        
  7939.         // Remove player leaving flag
  7940.         g_lastplayerleaving = false
  7941.        
  7942.         // If Survivor, set chosen player's health to that of the one who's leaving
  7943.         if (get_pcvar_num(cvar_keephealthondisconnect) && g_survivor[leaving_player])
  7944.             fm_set_user_health(id, pev(leaving_player, pev_health))
  7945.     }
  7946. }
  7947.  
  7948. // Lighting Effects Task
  7949. public lighting_effects()
  7950. {
  7951.     // Cache some CVAR values at every 5 secs
  7952.     cache_cvars()
  7953.    
  7954.     // Get lighting style
  7955.     static lighting[2]
  7956.     get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
  7957.     strtolower(lighting)
  7958.    
  7959.     // Lighting disabled? ["0"]
  7960.     if (lighting[0] == '0')
  7961.         return;
  7962.    
  7963.     // Darkest light settings?
  7964.     if (lighting[0] >= 'a' && lighting[0] <= 'd')
  7965.     {
  7966.         static thunderclap_in_progress, Float:thunder
  7967.         thunderclap_in_progress = task_exists(TASK_THUNDER)
  7968.         thunder = get_pcvar_float(cvar_thunder)
  7969.        
  7970.         // Set thunderclap tasks if not existant
  7971.         if (thunder > 0.0 && !task_exists(TASK_THUNDER_PRE) && !thunderclap_in_progress)
  7972.         {
  7973.             g_lights_i = 0
  7974.             ArrayGetString(lights_thunder, random_num(0, ArraySize(lights_thunder) - 1), g_lights_cycle, charsmax(g_lights_cycle))
  7975.             g_lights_cycle_len = strlen(g_lights_cycle)
  7976.             set_task(thunder, "thunderclap", TASK_THUNDER_PRE)
  7977.         }
  7978.        
  7979.         // Set lighting only when no thunderclaps are going on
  7980.         if (!thunderclap_in_progress) engfunc(EngFunc_LightStyle, 0, lighting)
  7981.     }
  7982.     else
  7983.     {
  7984.         // Remove thunderclap tasks
  7985.         remove_task(TASK_THUNDER_PRE)
  7986.         remove_task(TASK_THUNDER)
  7987.        
  7988.         // Set lighting
  7989.         engfunc(EngFunc_LightStyle, 0, lighting)
  7990.     }
  7991. }
  7992.  
  7993. // Thunderclap task
  7994. public thunderclap()
  7995. {
  7996.     // Play thunder sound
  7997.     if (g_lights_i == 0)
  7998.     {
  7999.         static sound[64]
  8000.         ArrayGetString(sound_thunder, random_num(0, ArraySize(sound_thunder) - 1), sound, charsmax(sound))
  8001.         PlaySound(sound)
  8002.     }
  8003.    
  8004.     // Set lighting
  8005.     static light[2]
  8006.     light[0] = g_lights_cycle[g_lights_i]
  8007.     engfunc(EngFunc_LightStyle, 0, light)
  8008.    
  8009.     g_lights_i++
  8010.    
  8011.     // Lighting cycle end?
  8012.     if (g_lights_i >= g_lights_cycle_len)
  8013.     {
  8014.         remove_task(TASK_THUNDER)
  8015.         lighting_effects()
  8016.     }
  8017.     // Lighting cycle start?
  8018.     else if (!task_exists(TASK_THUNDER))
  8019.         set_task(0.1, "thunderclap", TASK_THUNDER, _, _, "b")
  8020. }
  8021.  
  8022. // Ambience Sound Effects Task
  8023. public ambience_sound_effects(taskid)
  8024. {
  8025.     // Play a random sound depending on the round
  8026.     static sound[64], iRand, duration
  8027.    
  8028.     if (g_nemround) // Nemesis Mode
  8029.     {
  8030.         iRand = random_num(0, ArraySize(sound_ambience2) - 1)
  8031.         ArrayGetString(sound_ambience2, iRand, sound, charsmax(sound))
  8032.         duration = ArrayGetCell(sound_ambience2_duration, iRand)
  8033.     }
  8034.     else if (g_survround) // Survivor Mode
  8035.     {
  8036.         iRand = random_num(0, ArraySize(sound_ambience3) - 1)
  8037.         ArrayGetString(sound_ambience3, iRand, sound, charsmax(sound))
  8038.         duration = ArrayGetCell(sound_ambience3_duration, iRand)
  8039.     }
  8040.     else if (g_swarmround) // Swarm Mode
  8041.     {
  8042.         iRand = random_num(0, ArraySize(sound_ambience4) - 1)
  8043.         ArrayGetString(sound_ambience4, iRand, sound, charsmax(sound))
  8044.         duration = ArrayGetCell(sound_ambience4_duration, iRand)
  8045.     }
  8046.     else if (g_plagueround) // Plague Mode
  8047.     {
  8048.         iRand = random_num(0, ArraySize(sound_ambience5) - 1)
  8049.         ArrayGetString(sound_ambience5, iRand, sound, charsmax(sound))
  8050.         duration = ArrayGetCell(sound_ambience5_duration, iRand)
  8051.     }
  8052.     else // Infection Mode
  8053.     {
  8054.         iRand = random_num(0, ArraySize(sound_ambience1) - 1)
  8055.         ArrayGetString(sound_ambience1, iRand, sound, charsmax(sound))
  8056.         duration = ArrayGetCell(sound_ambience1_duration, iRand)
  8057.     }
  8058.    
  8059.     // Play it on clients
  8060.     PlaySound(sound)
  8061.    
  8062.     // Set the task for when the sound is done playing
  8063.     set_task(float(duration), "ambience_sound_effects", TASK_AMBIENCESOUNDS)
  8064. }
  8065.  
  8066. // Ambience Sounds Stop Task
  8067. ambience_sound_stop()
  8068. {
  8069.     client_cmd(0, "mp3 stop; stopsound")
  8070. }
  8071.  
  8072. // Flashlight Charge Task
  8073. public flashlight_charge(taskid)
  8074. {
  8075.     // Drain or charge?
  8076.     if (g_flashlight[ID_CHARGE])
  8077.         g_flashbattery[ID_CHARGE] -= get_pcvar_num(cvar_flashdrain)
  8078.     else
  8079.         g_flashbattery[ID_CHARGE] += get_pcvar_num(cvar_flashcharge)
  8080.    
  8081.     // Battery fully charged
  8082.     if (g_flashbattery[ID_CHARGE] >= 100)
  8083.     {
  8084.         // Don't exceed 100%
  8085.         g_flashbattery[ID_CHARGE] = 100
  8086.        
  8087.         // Update flashlight battery on HUD
  8088.         message_begin(MSG_ONE, g_msgFlashBat, _, ID_CHARGE)
  8089.         write_byte(100) // battery
  8090.         message_end()
  8091.        
  8092.         // Task not needed anymore
  8093.         remove_task(taskid);
  8094.         return;
  8095.     }
  8096.    
  8097.     // Battery depleted
  8098.     if (g_flashbattery[ID_CHARGE] <= 0)
  8099.     {
  8100.         // Turn it off
  8101.         g_flashlight[ID_CHARGE] = false
  8102.         g_flashbattery[ID_CHARGE] = 0
  8103.        
  8104.         // Play flashlight toggle sound
  8105.         emit_sound(ID_CHARGE, CHAN_ITEM, sound_flashlight, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8106.        
  8107.         // Update flashlight status on HUD
  8108.         message_begin(MSG_ONE, g_msgFlashlight, _, ID_CHARGE)
  8109.         write_byte(0) // toggle
  8110.         write_byte(0) // battery
  8111.         message_end()
  8112.        
  8113.         // Remove flashlight task for this player
  8114.         remove_task(ID_CHARGE+TASK_FLASH)
  8115.     }
  8116.     else
  8117.     {
  8118.         // Update flashlight battery on HUD
  8119.         message_begin(MSG_ONE_UNRELIABLE, g_msgFlashBat, _, ID_CHARGE)
  8120.         write_byte(g_flashbattery[ID_CHARGE]) // battery
  8121.         message_end()
  8122.     }
  8123. }
  8124.  
  8125. // Remove Spawn Protection Task
  8126. public remove_spawn_protection(taskid)
  8127. {
  8128.     // Not alive
  8129.     if (!g_isalive[ID_SPAWN])
  8130.         return;
  8131.    
  8132.     // Remove spawn protection
  8133.     g_nodamage[ID_SPAWN] = false
  8134.     set_pev(ID_SPAWN, pev_effects, pev(ID_SPAWN, pev_effects) & ~EF_NODRAW)
  8135. }
  8136.  
  8137. // Hide Player's Money Task
  8138. public task_hide_money(taskid)
  8139. {
  8140.     // Not alive
  8141.     if (!g_isalive[ID_SPAWN])
  8142.         return;
  8143.    
  8144.     // Hide money
  8145.     message_begin(MSG_ONE, g_msgHideWeapon, _, ID_SPAWN)
  8146.     write_byte(HIDE_MONEY) // what to hide bitsum
  8147.     message_end()
  8148.    
  8149.     // Hide the HL crosshair that's drawn
  8150.     message_begin(MSG_ONE, g_msgCrosshair, _, ID_SPAWN)
  8151.     write_byte(0) // toggle
  8152.     message_end()
  8153. }
  8154.  
  8155. // Turn Off Flashlight and Restore Batteries
  8156. turn_off_flashlight(id)
  8157. {
  8158.     // Restore batteries for the next use
  8159.     fm_cs_set_user_batteries(id, 100)
  8160.    
  8161.     // Check if flashlight is on
  8162.     if (pev(id, pev_effects) & EF_DIMLIGHT)
  8163.     {
  8164.         // Turn it off
  8165.         set_pev(id, pev_impulse, IMPULSE_FLASHLIGHT)
  8166.     }
  8167.     else
  8168.     {
  8169.         // Clear any stored flashlight impulse (bugfix)
  8170.         set_pev(id, pev_impulse, 0)
  8171.     }
  8172.    
  8173.     // Turn off custom flashlight
  8174.     if (g_cached_customflash)
  8175.     {
  8176.         // Turn it off
  8177.         g_flashlight[id] = false
  8178.         g_flashbattery[id] = 100
  8179.        
  8180.         // Update flashlight HUD
  8181.         message_begin(MSG_ONE, g_msgFlashlight, _, id)
  8182.         write_byte(0) // toggle
  8183.         write_byte(100) // battery
  8184.         message_end()
  8185.        
  8186.         // Remove previous tasks
  8187.         remove_task(id+TASK_CHARGE)
  8188.         remove_task(id+TASK_FLASH)
  8189.     }
  8190. }
  8191.  
  8192. // Infection Bomb Explosion
  8193. infection_explode(ent)
  8194. {
  8195.     // Round ended (bugfix)
  8196.     if (g_endround) return;
  8197.    
  8198.     // Get origin
  8199.     static Float:originF[3]
  8200.     pev(ent, pev_origin, originF)
  8201.    
  8202.     // Make the explosion
  8203.     create_blast(originF)
  8204.    
  8205.     // Infection nade explode sound
  8206.     static sound[64]
  8207.     ArrayGetString(grenade_infect, random_num(0, ArraySize(grenade_infect) - 1), sound, charsmax(sound))
  8208.     emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8209.    
  8210.     // Get attacker
  8211.     static attacker
  8212.     attacker = pev(ent, pev_owner)
  8213.    
  8214.     // Infection bomb owner disconnected? (bugfix)
  8215.     if (!is_user_valid_connected(attacker))
  8216.     {
  8217.         // Get rid of the grenade
  8218.         engfunc(EngFunc_RemoveEntity, ent)
  8219.         return;
  8220.     }
  8221.    
  8222.     // Collisions
  8223.     static victim
  8224.     victim = -1
  8225.    
  8226.     while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
  8227.     {
  8228.         // Only effect alive non-spawnprotected humans
  8229.         if (!is_user_valid_alive(victim) || g_zombie[victim] || g_nodamage[victim])
  8230.             continue;
  8231.        
  8232.         // Last human is killed
  8233.         if (fnGetHumans() == 1)
  8234.         {
  8235.             ExecuteHamB(Ham_Killed, victim, attacker, 0)
  8236.             continue;
  8237.         }
  8238.        
  8239.         // Infected victim's sound
  8240.         ArrayGetString(grenade_infect_player, random_num(0, ArraySize(grenade_infect_player) - 1), sound, charsmax(sound))
  8241.         emit_sound(victim, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8242.        
  8243.         // Turn into zombie
  8244.         zombieme(victim, attacker, 0, 1, 1)
  8245.     }
  8246.    
  8247.     // Get rid of the grenade
  8248.     engfunc(EngFunc_RemoveEntity, ent)
  8249. }
  8250.  
  8251. // Fire Grenade Explosion
  8252. fire_explode(ent)
  8253. {
  8254.     // Get origin
  8255.     static Float:originF[3]
  8256.     pev(ent, pev_origin, originF)
  8257.    
  8258.     // Make the explosion
  8259.     create_blast2(originF)
  8260.    
  8261.     // Fire nade explode sound
  8262.     static sound[64]
  8263.     ArrayGetString(grenade_fire, random_num(0, ArraySize(grenade_fire) - 1), sound, charsmax(sound))
  8264.     emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8265.    
  8266.     // Collisions
  8267.     static victim
  8268.     victim = -1
  8269.    
  8270.     while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
  8271.     {
  8272.         // Only effect alive zombies
  8273.         if (!is_user_valid_alive(victim) || !g_zombie[victim] || g_nodamage[victim])
  8274.             continue;
  8275.        
  8276.         // Heat icon?
  8277.         if (get_pcvar_num(cvar_hudicons))
  8278.         {
  8279.             message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, victim)
  8280.             write_byte(0) // damage save
  8281.             write_byte(0) // damage take
  8282.             write_long(DMG_BURN) // damage type
  8283.             write_coord(0) // x
  8284.             write_coord(0) // y
  8285.             write_coord(0) // z
  8286.             message_end()
  8287.         }
  8288.        
  8289.         if (g_nemesis[victim]) // fire duration (nemesis is fire resistant)
  8290.             g_burning_duration[victim] += get_pcvar_num(cvar_fireduration)
  8291.         else
  8292.             g_burning_duration[victim] += get_pcvar_num(cvar_fireduration) * 5
  8293.        
  8294.         // Set burning task on victim if not present
  8295.         if (!task_exists(victim+TASK_BURN))
  8296.             set_task(0.2, "burning_flame", victim+TASK_BURN, _, _, "b")
  8297.     }
  8298.    
  8299.     // Get rid of the grenade
  8300.     engfunc(EngFunc_RemoveEntity, ent)
  8301. }
  8302.  
  8303. // Frost Grenade Explosion
  8304. frost_explode(ent)
  8305. {
  8306.     // Get origin
  8307.     static Float:originF[3]
  8308.     pev(ent, pev_origin, originF)
  8309.    
  8310.     // Make the explosion
  8311.     create_blast3(originF)
  8312.    
  8313.     // Frost nade explode sound
  8314.     static sound[64]
  8315.     ArrayGetString(grenade_frost, random_num(0, ArraySize(grenade_frost) - 1), sound, charsmax(sound))
  8316.     emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8317.    
  8318.     // Collisions
  8319.     static victim
  8320.     victim = -1
  8321.    
  8322.     while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
  8323.     {
  8324.         // Only effect alive unfrozen zombies
  8325.         if (!is_user_valid_alive(victim) || !g_zombie[victim] || g_frozen[victim] || g_nodamage[victim])
  8326.             continue;
  8327.        
  8328.         // Nemesis shouldn't be frozen
  8329.         if (g_nemesis[victim])
  8330.         {
  8331.             // Get player's origin
  8332.             static origin2[3]
  8333.             get_user_origin(victim, origin2)
  8334.            
  8335.             // Broken glass sound
  8336.             ArrayGetString(grenade_frost_break, random_num(0, ArraySize(grenade_frost_break) - 1), sound, charsmax(sound))
  8337.             emit_sound(victim, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8338.            
  8339.             // Glass shatter
  8340.             message_begin(MSG_PVS, SVC_TEMPENTITY, origin2)
  8341.             write_byte(TE_BREAKMODEL) // TE id
  8342.             write_coord(origin2[0]) // x
  8343.             write_coord(origin2[1]) // y
  8344.             write_coord(origin2[2]+24) // z
  8345.             write_coord(16) // size x
  8346.             write_coord(16) // size y
  8347.             write_coord(16) // size z
  8348.             write_coord(random_num(-50, 50)) // velocity x
  8349.             write_coord(random_num(-50, 50)) // velocity y
  8350.             write_coord(25) // velocity z
  8351.             write_byte(10) // random velocity
  8352.             write_short(g_glassSpr) // model
  8353.             write_byte(10) // count
  8354.             write_byte(25) // life
  8355.             write_byte(BREAK_GLASS) // flags
  8356.             message_end()
  8357.            
  8358.             continue;
  8359.         }
  8360.        
  8361.         // Freeze icon?
  8362.         if (get_pcvar_num(cvar_hudicons))
  8363.         {
  8364.             message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, victim)
  8365.             write_byte(0) // damage save
  8366.             write_byte(0) // damage take
  8367.             write_long(DMG_DROWN) // damage type - DMG_FREEZE
  8368.             write_coord(0) // x
  8369.             write_coord(0) // y
  8370.             write_coord(0) // z
  8371.             message_end()
  8372.         }
  8373.        
  8374.         // Light blue glow while frozen
  8375.         if (g_handle_models_on_separate_ent)
  8376.             fm_set_rendering(g_ent_playermodel[victim], kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)
  8377.         else
  8378.             fm_set_rendering(victim, kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)
  8379.        
  8380.         // Freeze sound
  8381.         ArrayGetString(grenade_frost_player, random_num(0, ArraySize(grenade_frost_player) - 1), sound, charsmax(sound))
  8382.         emit_sound(victim, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8383.        
  8384.         // Add a blue tint to their screen
  8385.         message_begin(MSG_ONE, g_msgScreenFade, _, victim)
  8386.         write_short(0) // duration
  8387.         write_short(0) // hold time
  8388.         write_short(FFADE_STAYOUT) // fade type
  8389.         write_byte(0) // red
  8390.         write_byte(50) // green
  8391.         write_byte(200) // blue
  8392.         write_byte(100) // alpha
  8393.         message_end()
  8394.        
  8395.         // Set the frozen flag
  8396.         g_frozen[victim] = true
  8397.        
  8398.         // Save player's old gravity (bugfix)
  8399.         pev(victim, pev_gravity, g_frozen_gravity[victim])
  8400.        
  8401.         // Prevent from jumping
  8402.         if (pev(victim, pev_flags) & FL_ONGROUND)
  8403.             set_pev(victim, pev_gravity, 999999.9) // set really high
  8404.         else
  8405.             set_pev(victim, pev_gravity, 0.000001) // no gravity
  8406.        
  8407.         // Prevent from moving
  8408.         ExecuteHamB(Ham_Player_ResetMaxSpeed, victim)
  8409.        
  8410.         // Set a task to remove the freeze
  8411.         set_task(get_pcvar_float(cvar_freezeduration), "remove_freeze", victim)
  8412.     }
  8413.    
  8414.     // Get rid of the grenade
  8415.     engfunc(EngFunc_RemoveEntity, ent)
  8416. }
  8417.  
  8418. // Remove freeze task
  8419. public remove_freeze(id)
  8420. {
  8421.     // Not alive or not frozen anymore
  8422.     if (!g_isalive[id] || !g_frozen[id])
  8423.         return;
  8424.    
  8425.     // Unfreeze
  8426.     g_frozen[id] = false;
  8427.    
  8428.     // Restore gravity and maxspeed (bugfix)
  8429.     set_pev(id, pev_gravity, g_frozen_gravity[id])
  8430.     ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
  8431.    
  8432.     // Restore rendering
  8433.     if (g_handle_models_on_separate_ent)
  8434.     {
  8435.         // Nemesis or Survivor glow / remove glow on player model entity
  8436.         if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  8437.             fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  8438.         else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  8439.             fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  8440.         else
  8441.             fm_set_rendering(g_ent_playermodel[id])
  8442.     }
  8443.     else
  8444.     {
  8445.         // Nemesis or Survivor glow / remove glow
  8446.         if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
  8447.             fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
  8448.         else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
  8449.             fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
  8450.         else
  8451.             fm_set_rendering(id)
  8452.     }
  8453.    
  8454.     // Gradually remove screen's blue tint
  8455.     message_begin(MSG_ONE, g_msgScreenFade, _, id)
  8456.     write_short(UNIT_SECOND) // duration
  8457.     write_short(0) // hold time
  8458.     write_short(FFADE_IN) // fade type
  8459.     write_byte(0) // red
  8460.     write_byte(50) // green
  8461.     write_byte(200) // blue
  8462.     write_byte(100) // alpha
  8463.     message_end()
  8464.    
  8465.     // Broken glass sound
  8466.     static sound[64]
  8467.     ArrayGetString(grenade_frost_break, random_num(0, ArraySize(grenade_frost_break) - 1), sound, charsmax(sound))
  8468.     emit_sound(id, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8469.    
  8470.     // Get player's origin
  8471.     static origin2[3]
  8472.     get_user_origin(id, origin2)
  8473.    
  8474.     // Glass shatter
  8475.     message_begin(MSG_PVS, SVC_TEMPENTITY, origin2)
  8476.     write_byte(TE_BREAKMODEL) // TE id
  8477.     write_coord(origin2[0]) // x
  8478.     write_coord(origin2[1]) // y
  8479.     write_coord(origin2[2]+24) // z
  8480.     write_coord(16) // size x
  8481.     write_coord(16) // size y
  8482.     write_coord(16) // size z
  8483.     write_coord(random_num(-50, 50)) // velocity x
  8484.     write_coord(random_num(-50, 50)) // velocity y
  8485.     write_coord(25) // velocity z
  8486.     write_byte(10) // random velocity
  8487.     write_short(g_glassSpr) // model
  8488.     write_byte(10) // count
  8489.     write_byte(25) // life
  8490.     write_byte(BREAK_GLASS) // flags
  8491.     message_end()
  8492.    
  8493.     ExecuteForward(g_fwUserUnfrozen, g_fwDummyResult, id);
  8494. }
  8495.  
  8496. // Remove Stuff Task
  8497. public remove_stuff()
  8498. {
  8499.     static ent
  8500.    
  8501.     // Remove rotating doors
  8502.     if (get_pcvar_num(cvar_removedoors) > 0)
  8503.     {
  8504.         ent = -1;
  8505.         while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "func_door_rotating")) != 0)
  8506.             engfunc(EngFunc_SetOrigin, ent, Float:{8192.0 ,8192.0 ,8192.0})
  8507.     }
  8508.    
  8509.     // Remove all doors
  8510.     if (get_pcvar_num(cvar_removedoors) > 1)
  8511.     {
  8512.         ent = -1;
  8513.         while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "func_door")) != 0)
  8514.             engfunc(EngFunc_SetOrigin, ent, Float:{8192.0 ,8192.0 ,8192.0})
  8515.     }
  8516.    
  8517.     // Triggered lights
  8518.     if (!get_pcvar_num(cvar_triggered))
  8519.     {
  8520.         ent = -1
  8521.         while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "light")) != 0)
  8522.         {
  8523.             dllfunc(DLLFunc_Use, ent, 0); // turn off the light
  8524.             set_pev(ent, pev_targetname, 0) // prevent it from being triggered
  8525.         }
  8526.     }
  8527. }
  8528.  
  8529. // Set Custom Weapon Models
  8530. replace_weapon_models(id, weaponid)
  8531. {
  8532.     switch (weaponid)
  8533.     {
  8534.         case CSW_KNIFE: // Custom knife models
  8535.         {
  8536.             if (g_zombie[id])
  8537.             {
  8538.                 if (g_nemesis[id]) // Nemesis
  8539.                 {
  8540.                     set_pev(id, pev_viewmodel2, model_vknife_nemesis)
  8541.                     set_pev(id, pev_weaponmodel2, "")
  8542.                 }
  8543.                 else // Zombies
  8544.                 {
  8545.                     // Admin knife models?
  8546.                     if (get_pcvar_num(cvar_adminknifemodelszombie) && get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS])
  8547.                     {
  8548.                         set_pev(id, pev_viewmodel2, model_vknife_admin_zombie)
  8549.                         set_pev(id, pev_weaponmodel2, "")
  8550.                     }
  8551.                     else
  8552.                     {
  8553.                         static clawmodel[100]
  8554.                         ArrayGetString(g_zclass_clawmodel, g_zombieclass[id], clawmodel, charsmax(clawmodel))
  8555.                         format(clawmodel, charsmax(clawmodel), "models/zombie_plague/%s", clawmodel)
  8556.                         set_pev(id, pev_viewmodel2, clawmodel)
  8557.                         set_pev(id, pev_weaponmodel2, "")
  8558.                     }
  8559.                 }
  8560.             }
  8561.             else // Humans
  8562.             {
  8563.                 // Admin knife models?
  8564.                 if (get_pcvar_num(cvar_adminknifemodelshuman) && get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS])
  8565.                 {
  8566.                     set_pev(id, pev_viewmodel2, model_vknife_admin_human)
  8567.                     set_pev(id, pev_weaponmodel2, "models/p_knife.mdl")
  8568.                 }
  8569.                 else
  8570.                 {
  8571.                     set_pev(id, pev_viewmodel2, model_vknife_human)
  8572.                     set_pev(id, pev_weaponmodel2, "models/p_knife.mdl")
  8573.                 }
  8574.             }
  8575.         }
  8576.         case CSW_HEGRENADE: // Infection bomb or fire grenade
  8577.         {
  8578.             if (g_zombie[id])
  8579.                 set_pev(id, pev_viewmodel2, model_grenade_infect)
  8580.             else
  8581.                 set_pev(id, pev_viewmodel2, model_grenade_fire)
  8582.         }
  8583.         case CSW_FLASHBANG: // Frost grenade
  8584.         {
  8585.             set_pev(id, pev_viewmodel2, model_grenade_frost)
  8586.         }
  8587.         case CSW_SMOKEGRENADE: // Flare grenade
  8588.         {
  8589.             set_pev(id, pev_viewmodel2, model_grenade_flare)
  8590.         }
  8591.     }
  8592.    
  8593.     // Survivor's custom weapon model
  8594.     static survweaponname[32]
  8595.     get_pcvar_string(cvar_survweapon, survweaponname, charsmax(survweaponname))
  8596.     if (g_survivor[id] && weaponid == cs_weapon_name_to_id(survweaponname))
  8597.         set_pev(id, pev_viewmodel2, model_vweapon_survivor)
  8598.    
  8599.     // Update model on weaponmodel ent
  8600.     if (g_handle_models_on_separate_ent) fm_set_weaponmodel_ent(id)
  8601. }
  8602.  
  8603. // Reset Player Vars
  8604. reset_vars(id, resetall)
  8605. {
  8606.     g_zombie[id] = false
  8607.     g_nemesis[id] = false
  8608.     g_survivor[id] = false
  8609.     g_firstzombie[id] = false
  8610.     g_lastzombie[id] = false
  8611.     g_lasthuman[id] = false
  8612.     g_frozen[id] = false
  8613.     g_nodamage[id] = false
  8614.     g_respawn_as_zombie[id] = false
  8615.     g_nvision[id] = false
  8616.     g_nvisionenabled[id] = false
  8617.     g_flashlight[id] = false
  8618.     g_flashbattery[id] = 100
  8619.     g_canbuy[id] = true
  8620.     g_burning_duration[id] = 0
  8621.    
  8622.     if (resetall)
  8623.     {
  8624.         g_ammopacks[id] = get_pcvar_num(cvar_startammopacks)
  8625.         g_zombieclass[id] = ZCLASS_NONE
  8626.         g_zombieclassnext[id] = ZCLASS_NONE
  8627.         g_damagedealt_human[id] = 0
  8628.         g_damagedealt_zombie[id] = 0
  8629.         WPN_AUTO_ON = 0
  8630.         WPN_STARTID = 0
  8631.         PL_ACTION = 0
  8632.         MENU_PAGE_ZCLASS = 0
  8633.         MENU_PAGE_EXTRAS = 0
  8634.         MENU_PAGE_PLAYERS = 0
  8635.     }
  8636. }
  8637.  
  8638. // Set spectators nightvision
  8639. public spec_nvision(id)
  8640. {
  8641.     // Not connected, alive, or bot
  8642.     if (!g_isconnected[id] || g_isalive[id] || g_isbot[id])
  8643.         return;
  8644.    
  8645.     // Give Night Vision?
  8646.     if (get_pcvar_num(cvar_nvggive))
  8647.     {
  8648.         g_nvision[id] = true
  8649.        
  8650.         // Turn on Night Vision automatically?
  8651.         if (get_pcvar_num(cvar_nvggive) == 1)
  8652.         {
  8653.             g_nvisionenabled[id] = true
  8654.            
  8655.             // Custom nvg?
  8656.             if (get_pcvar_num(cvar_customnvg))
  8657.             {
  8658.                 remove_task(id+TASK_NVISION)
  8659.                 set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  8660.             }
  8661.             else
  8662.                 set_user_gnvision(id, 1)
  8663.         }
  8664.     }
  8665. }
  8666.  
  8667. // Show HUD Task
  8668. public ShowHUD(taskid)
  8669. {
  8670.     static id
  8671.     id = ID_SHOWHUD;
  8672.    
  8673.     // Player died?
  8674.     if (!g_isalive[id])
  8675.     {
  8676.         // Get spectating target
  8677.         id = pev(id, PEV_SPEC_TARGET)
  8678.        
  8679.         // Target not alive
  8680.         if (!g_isalive[id]) return;
  8681.     }
  8682.    
  8683.     // Format classname
  8684.     static class[32], red, green, blue
  8685.    
  8686.     if (g_zombie[id]) // zombies
  8687.     {
  8688.         red = 200
  8689.         green = 250
  8690.         blue = 0
  8691.        
  8692.         if (g_nemesis[id])
  8693.             formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_NEMESIS")
  8694.         else
  8695.             copy(class, charsmax(class), g_zombie_classname[id])
  8696.     }
  8697.     else // humans
  8698.     {
  8699.         red = 0
  8700.         green = 0
  8701.         blue = 255
  8702.        
  8703.         if (g_survivor[id])
  8704.             formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_SURVIVOR")
  8705.         else
  8706.             formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_HUMAN")
  8707.     }
  8708.    
  8709.     // Spectating someone else?
  8710.     if (id != ID_SHOWHUD)
  8711.     {
  8712.         // Show name, health, class, and ammo packs
  8713.         set_hudmessage(255, 255, 255, HUD_SPECT_X, HUD_SPECT_Y, 0, 6.0, 1.1, 0.0, 0.0, -1)
  8714.         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])
  8715.     }
  8716.     else
  8717.     {
  8718.         // Show health, class and ammo packs
  8719.         set_hudmessage(red, green, blue, HUD_STATS_X, HUD_STATS_Y, 0, 6.0, 1.1, 0.0, 0.0, -1)
  8720.         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])
  8721.     }
  8722. }
  8723.  
  8724. // Play idle zombie sounds
  8725. public zombie_play_idle(taskid)
  8726. {
  8727.     // Round ended/new one starting
  8728.     if (g_endround || g_newround)
  8729.         return;
  8730.    
  8731.     static sound[64]
  8732.    
  8733.     // Last zombie?
  8734.     if (g_lastzombie[ID_BLOOD])
  8735.     {
  8736.         ArrayGetString(zombie_idle_last, random_num(0, ArraySize(zombie_idle_last) - 1), sound, charsmax(sound))
  8737.         emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8738.     }
  8739.     else
  8740.     {
  8741.         ArrayGetString(zombie_idle, random_num(0, ArraySize(zombie_idle) - 1), sound, charsmax(sound))
  8742.         emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  8743.     }
  8744. }
  8745.  
  8746. // Madness Over Task
  8747. public madness_over(taskid)
  8748. {
  8749.     g_nodamage[ID_BLOOD] = false
  8750. }
  8751.  
  8752. // Place user at a random spawn
  8753. do_random_spawn(id, regularspawns = 0)
  8754. {
  8755.     static hull, sp_index, i
  8756.    
  8757.     // Get whether the player is crouching
  8758.     hull = (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN
  8759.    
  8760.     // Use regular spawns?
  8761.     if (!regularspawns)
  8762.     {
  8763.         // No spawns?
  8764.         if (!g_spawnCount)
  8765.             return;
  8766.        
  8767.         // Choose random spawn to start looping at
  8768.         sp_index = random_num(0, g_spawnCount - 1)
  8769.        
  8770.         // Try to find a clear spawn
  8771.         for (i = sp_index + 1; /*no condition*/; i++)
  8772.         {
  8773.             // Start over when we reach the end
  8774.             if (i >= g_spawnCount) i = 0
  8775.            
  8776.             // Free spawn space?
  8777.             if (is_hull_vacant(g_spawns[i], hull))
  8778.             {
  8779.                 // Engfunc_SetOrigin is used so ent's mins and maxs get updated instantly
  8780.                 engfunc(EngFunc_SetOrigin, id, g_spawns[i])
  8781.                 break;
  8782.             }
  8783.            
  8784.             // Loop completed, no free space found
  8785.             if (i == sp_index) break;
  8786.         }
  8787.     }
  8788.     else
  8789.     {
  8790.         // No spawns?
  8791.         if (!g_spawnCount2)
  8792.             return;
  8793.        
  8794.         // Choose random spawn to start looping at
  8795.         sp_index = random_num(0, g_spawnCount2 - 1)
  8796.        
  8797.         // Try to find a clear spawn
  8798.         for (i = sp_index + 1; /*no condition*/; i++)
  8799.         {
  8800.             // Start over when we reach the end
  8801.             if (i >= g_spawnCount2) i = 0
  8802.            
  8803.             // Free spawn space?
  8804.             if (is_hull_vacant(g_spawns2[i], hull))
  8805.             {
  8806.                 // Engfunc_SetOrigin is used so ent's mins and maxs get updated instantly
  8807.                 engfunc(EngFunc_SetOrigin, id, g_spawns2[i])
  8808.                 break;
  8809.             }
  8810.            
  8811.             // Loop completed, no free space found
  8812.             if (i == sp_index) break;
  8813.         }
  8814.     }
  8815. }
  8816.  
  8817. // Get Zombies -returns alive zombies number-
  8818. fnGetZombies()
  8819. {
  8820.     static iZombies, id
  8821.     iZombies = 0
  8822.    
  8823.     for (id = 1; id <= g_maxplayers; id++)
  8824.     {
  8825.         if (g_isalive[id] && g_zombie[id])
  8826.             iZombies++
  8827.     }
  8828.    
  8829.     return iZombies;
  8830. }
  8831.  
  8832. // Get Humans -returns alive humans number-
  8833. fnGetHumans()
  8834. {
  8835.     static iHumans, id
  8836.     iHumans = 0
  8837.    
  8838.     for (id = 1; id <= g_maxplayers; id++)
  8839.     {
  8840.         if (g_isalive[id] && !g_zombie[id])
  8841.             iHumans++
  8842.     }
  8843.    
  8844.     return iHumans;
  8845. }
  8846.  
  8847. // Get Nemesis -returns alive nemesis number-
  8848. fnGetNemesis()
  8849. {
  8850.     static iNemesis, id
  8851.     iNemesis = 0
  8852.    
  8853.     for (id = 1; id <= g_maxplayers; id++)
  8854.     {
  8855.         if (g_isalive[id] && g_nemesis[id])
  8856.             iNemesis++
  8857.     }
  8858.    
  8859.     return iNemesis;
  8860. }
  8861.  
  8862. // Get Survivors -returns alive survivors number-
  8863. fnGetSurvivors()
  8864. {
  8865.     static iSurvivors, id
  8866.     iSurvivors = 0
  8867.    
  8868.     for (id = 1; id <= g_maxplayers; id++)
  8869.     {
  8870.         if (g_isalive[id] && g_survivor[id])
  8871.             iSurvivors++
  8872.     }
  8873.    
  8874.     return iSurvivors;
  8875. }
  8876.  
  8877. // Get Alive -returns alive players number-
  8878. fnGetAlive()
  8879. {
  8880.     static iAlive, id
  8881.     iAlive = 0
  8882.    
  8883.     for (id = 1; id <= g_maxplayers; id++)
  8884.     {
  8885.         if (g_isalive[id])
  8886.             iAlive++
  8887.     }
  8888.    
  8889.     return iAlive;
  8890. }
  8891.  
  8892. // Get Random Alive -returns index of alive player number n -
  8893. fnGetRandomAlive(n)
  8894. {
  8895.     static iAlive, id
  8896.     iAlive = 0
  8897.    
  8898.     for (id = 1; id <= g_maxplayers; id++)
  8899.     {
  8900.         if (g_isalive[id])
  8901.             iAlive++
  8902.        
  8903.         if (iAlive == n)
  8904.             return id;
  8905.     }
  8906.    
  8907.     return -1;
  8908. }
  8909.  
  8910. // Get Playing -returns number of users playing-
  8911. fnGetPlaying()
  8912. {
  8913.     static iPlaying, id, team
  8914.     iPlaying = 0
  8915.    
  8916.     for (id = 1; id <= g_maxplayers; id++)
  8917.     {
  8918.         if (g_isconnected[id])
  8919.         {
  8920.             team = fm_cs_get_user_team(id)
  8921.            
  8922.             if (team != FM_CS_TEAM_SPECTATOR && team != FM_CS_TEAM_UNASSIGNED)
  8923.                 iPlaying++
  8924.         }
  8925.     }
  8926.    
  8927.     return iPlaying;
  8928. }
  8929.  
  8930. // Get CTs -returns number of CTs connected-
  8931. fnGetCTs()
  8932. {
  8933.     static iCTs, id
  8934.     iCTs = 0
  8935.    
  8936.     for (id = 1; id <= g_maxplayers; id++)
  8937.     {
  8938.         if (g_isconnected[id])
  8939.         {          
  8940.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_CT)
  8941.                 iCTs++
  8942.         }
  8943.     }
  8944.    
  8945.     return iCTs;
  8946. }
  8947.  
  8948. // Get Ts -returns number of Ts connected-
  8949. fnGetTs()
  8950. {
  8951.     static iTs, id
  8952.     iTs = 0
  8953.    
  8954.     for (id = 1; id <= g_maxplayers; id++)
  8955.     {
  8956.         if (g_isconnected[id])
  8957.         {          
  8958.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_T)
  8959.                 iTs++
  8960.         }
  8961.     }
  8962.    
  8963.     return iTs;
  8964. }
  8965.  
  8966. // Get Alive CTs -returns number of CTs alive-
  8967. fnGetAliveCTs()
  8968. {
  8969.     static iCTs, id
  8970.     iCTs = 0
  8971.    
  8972.     for (id = 1; id <= g_maxplayers; id++)
  8973.     {
  8974.         if (g_isalive[id])
  8975.         {          
  8976.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_CT)
  8977.                 iCTs++
  8978.         }
  8979.     }
  8980.    
  8981.     return iCTs;
  8982. }
  8983.  
  8984. // Get Alive Ts -returns number of Ts alive-
  8985. fnGetAliveTs()
  8986. {
  8987.     static iTs, id
  8988.     iTs = 0
  8989.    
  8990.     for (id = 1; id <= g_maxplayers; id++)
  8991.     {
  8992.         if (g_isalive[id])
  8993.         {          
  8994.             if (fm_cs_get_user_team(id) == FM_CS_TEAM_T)
  8995.                 iTs++
  8996.         }
  8997.     }
  8998.    
  8999.     return iTs;
  9000. }
  9001.  
  9002. // Last Zombie Check -check for last zombie and set its flag-
  9003. fnCheckLastZombie()
  9004. {
  9005.     static id
  9006.     for (id = 1; id <= g_maxplayers; id++)
  9007.     {
  9008.         // Last zombie
  9009.         if (g_isalive[id] && g_zombie[id] && !g_nemesis[id] && fnGetZombies() == 1)
  9010.         {
  9011.             if (!g_lastzombie[id])
  9012.             {
  9013.                 // Last zombie forward
  9014.                 ExecuteForward(g_fwUserLastZombie, g_fwDummyResult, id);
  9015.             }
  9016.             g_lastzombie[id] = true
  9017.         }
  9018.         else
  9019.             g_lastzombie[id] = false
  9020.        
  9021.         // Last human
  9022.         if (g_isalive[id] && !g_zombie[id] && !g_survivor[id] && fnGetHumans() == 1)
  9023.         {
  9024.             if (!g_lasthuman[id])
  9025.             {
  9026.                 // Last human forward
  9027.                 ExecuteForward(g_fwUserLastHuman, g_fwDummyResult, id);
  9028.                
  9029.                 // Reward extra hp
  9030.                 fm_set_user_health(id, pev(id, pev_health) + get_pcvar_num(cvar_humanlasthp))
  9031.             }
  9032.             g_lasthuman[id] = true
  9033.         }
  9034.         else
  9035.             g_lasthuman[id] = false
  9036.     }
  9037. }
  9038.  
  9039. // Save player's stats to database
  9040. save_stats(id)
  9041. {
  9042.     // Check whether there is another record already in that slot
  9043.     if (db_name[id][0] && !equal(g_playername[id], db_name[id]))
  9044.     {
  9045.         // If DB size is exceeded, write over old records
  9046.         if (db_slot_i >= sizeof db_name)
  9047.             db_slot_i = g_maxplayers+1
  9048.        
  9049.         // Move previous record onto an additional save slot
  9050.         copy(db_name[db_slot_i], charsmax(db_name[]), db_name[id])
  9051.         db_ammopacks[db_slot_i] = db_ammopacks[id]
  9052.         db_zombieclass[db_slot_i] = db_zombieclass[id]
  9053.         db_slot_i++
  9054.     }
  9055.    
  9056.     // Now save the current player stats
  9057.     copy(db_name[id], charsmax(db_name[]), g_playername[id]) // name
  9058.     db_ammopacks[id] = g_ammopacks[id]  // ammo packs
  9059.     db_zombieclass[id] = g_zombieclassnext[id] // zombie class
  9060. }
  9061.  
  9062. // Load player's stats from database (if a record is found)
  9063. load_stats(id)
  9064. {
  9065.     // Look for a matching record
  9066.     static i
  9067.     for (i = 0; i < sizeof db_name; i++)
  9068.     {
  9069.         if (equal(g_playername[id], db_name[i]))
  9070.         {
  9071.             // Bingo!
  9072.             g_ammopacks[id] = db_ammopacks[i]
  9073.             g_zombieclass[id] = db_zombieclass[i]
  9074.             g_zombieclassnext[id] = db_zombieclass[i]
  9075.             return;
  9076.         }
  9077.     }
  9078. }
  9079.  
  9080. // Checks if a player is allowed to be zombie
  9081. allowed_zombie(id)
  9082. {
  9083.     if ((g_zombie[id] && !g_nemesis[id]) || g_endround || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && !g_zombie[id] && fnGetHumans() == 1))
  9084.         return false;
  9085.    
  9086.     return true;
  9087. }
  9088.  
  9089. // Checks if a player is allowed to be human
  9090. allowed_human(id)
  9091. {
  9092.     if ((!g_zombie[id] && !g_survivor[id]) || g_endround || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && g_zombie[id] && fnGetZombies() == 1))
  9093.         return false;
  9094.    
  9095.     return true;
  9096. }
  9097.  
  9098. // Checks if a player is allowed to be survivor
  9099. allowed_survivor(id)
  9100. {
  9101.     if (g_endround || g_survivor[id] || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && g_zombie[id] && fnGetZombies() == 1))
  9102.         return false;
  9103.    
  9104.     return true;
  9105. }
  9106.  
  9107. // Checks if a player is allowed to be nemesis
  9108. allowed_nemesis(id)
  9109. {
  9110.     if (g_endround || g_nemesis[id] || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && !g_zombie[id] && fnGetHumans() == 1))
  9111.         return false;
  9112.    
  9113.     return true;
  9114. }
  9115.  
  9116. // Checks if a player is allowed to respawn
  9117. allowed_respawn(id)
  9118. {
  9119.     static team
  9120.     team = fm_cs_get_user_team(id)
  9121.    
  9122.     if (g_endround || team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED || g_isalive[id])
  9123.         return false;
  9124.    
  9125.     return true;
  9126. }
  9127.  
  9128. // Checks if swarm mode is allowed
  9129. allowed_swarm()
  9130. {
  9131.     if (g_endround || !g_newround || task_exists(TASK_WELCOMEMSG))
  9132.         return false;
  9133.    
  9134.     return true;
  9135. }
  9136.  
  9137. // Checks if multi infection mode is allowed
  9138. allowed_multi()
  9139. {
  9140.     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())
  9141.         return false;
  9142.    
  9143.     return true;
  9144. }
  9145.  
  9146. // Checks if plague mode is allowed
  9147. allowed_plague()
  9148. {
  9149.     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
  9150.     || 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)
  9151.         return false;
  9152.    
  9153.     return true;
  9154. }
  9155.  
  9156. // Admin Command. zp_zombie
  9157. command_zombie(id, player)
  9158. {
  9159.     // Show activity?
  9160.     switch (get_pcvar_num(cvar_showactivity))
  9161.     {
  9162.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_INFECT")
  9163.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_INFECT")
  9164.     }
  9165.    
  9166.     // Log to Zombie Plague log file?
  9167.     if (get_pcvar_num(cvar_logcommands))
  9168.     {
  9169.         static logdata[100], authid[32], ip[16]
  9170.         get_user_authid(id, authid, charsmax(authid))
  9171.         get_user_ip(id, ip, charsmax(ip), 1)
  9172.         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)
  9173.         log_to_file("zombieplague.log", logdata)
  9174.     }
  9175.    
  9176.     // New round?
  9177.     if (g_newround)
  9178.     {
  9179.         // Set as first zombie
  9180.         remove_task(TASK_MAKEZOMBIE)
  9181.         make_a_zombie(MODE_INFECTION, player)
  9182.     }
  9183.     else
  9184.     {
  9185.         // Just infect
  9186.         zombieme(player, 0, 0, 0, 0)
  9187.     }
  9188. }
  9189.  
  9190. // Admin Command. zp_human
  9191. command_human(id, player)
  9192. {
  9193.     // Show activity?
  9194.     switch (get_pcvar_num(cvar_showactivity))
  9195.     {
  9196.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_DISINFECT")
  9197.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_DISINFECT")
  9198.     }
  9199.    
  9200.     // Log to Zombie Plague log file?
  9201.     if (get_pcvar_num(cvar_logcommands))
  9202.     {
  9203.         static logdata[100], authid[32], ip[16]
  9204.         get_user_authid(id, authid, charsmax(authid))
  9205.         get_user_ip(id, ip, charsmax(ip), 1)
  9206.         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)
  9207.         log_to_file("zombieplague.log", logdata)
  9208.     }
  9209.    
  9210.     // Turn to human
  9211.     humanme(player, 0, 0)
  9212. }
  9213.  
  9214. // Admin Command. zp_survivor
  9215. command_survivor(id, player)
  9216. {
  9217.     // Show activity?
  9218.     switch (get_pcvar_num(cvar_showactivity))
  9219.     {
  9220.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_SURVIVAL")
  9221.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_SURVIVAL")
  9222.     }
  9223.    
  9224.      // Log to Zombie Plague log file?
  9225.     if (get_pcvar_num(cvar_logcommands))
  9226.     {
  9227.         static logdata[100], authid[32], ip[16]
  9228.         get_user_authid(id, authid, charsmax(authid))
  9229.         get_user_ip(id, ip, charsmax(ip), 1)
  9230.         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)
  9231.         log_to_file("zombieplague.log", logdata)
  9232.     }
  9233.    
  9234.     // New round?
  9235.     if (g_newround)
  9236.     {
  9237.         // Set as first survivor
  9238.         remove_task(TASK_MAKEZOMBIE)
  9239.         make_a_zombie(MODE_SURVIVOR, player)
  9240.     }
  9241.     else
  9242.     {
  9243.         // Turn player into a Survivor
  9244.         humanme(player, 1, 0)
  9245.     }
  9246. }
  9247.  
  9248. // Admin Command. zp_nemesis
  9249. command_nemesis(id, player)
  9250. {
  9251.     // Show activity?
  9252.     switch (get_pcvar_num(cvar_showactivity))
  9253.     {
  9254.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_NEMESIS")
  9255.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_NEMESIS")
  9256.     }
  9257.    
  9258.     // Log to Zombie Plague log file?
  9259.     if (get_pcvar_num(cvar_logcommands))
  9260.     {
  9261.         static logdata[100], authid[32], ip[16]
  9262.         get_user_authid(id, authid, charsmax(authid))
  9263.         get_user_ip(id, ip, charsmax(ip), 1)
  9264.         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)
  9265.         log_to_file("zombieplague.log", logdata)
  9266.     }
  9267.    
  9268.     // New round?
  9269.     if (g_newround)
  9270.     {
  9271.         // Set as first nemesis
  9272.         remove_task(TASK_MAKEZOMBIE)
  9273.         make_a_zombie(MODE_NEMESIS, player)
  9274.     }
  9275.     else
  9276.     {
  9277.         // Turn player into a Nemesis
  9278.         zombieme(player, 0, 1, 0, 0)
  9279.     }
  9280. }
  9281.  
  9282. // Admin Command. zp_respawn
  9283. command_respawn(id, player)
  9284. {
  9285.     // Show activity?
  9286.     switch (get_pcvar_num(cvar_showactivity))
  9287.     {
  9288.         case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_RESPAWN")
  9289.         case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_RESPAWN")
  9290.     }
  9291.    
  9292.     // Log to Zombie Plague log file?
  9293.     if (get_pcvar_num(cvar_logcommands))
  9294.     {
  9295.         static logdata[100], authid[32], ip[16]
  9296.         get_user_authid(id, authid, charsmax(authid))
  9297.         get_user_ip(id, ip, charsmax(ip), 1)
  9298.         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)
  9299.         log_to_file("zombieplague.log", logdata)
  9300.     }
  9301.    
  9302.     // Respawn as zombie?
  9303.     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))
  9304.         g_respawn_as_zombie[player] = true
  9305.    
  9306.     // Override respawn as zombie setting on nemesis and survivor rounds
  9307.     if (g_survround) g_respawn_as_zombie[player] = true
  9308.     else if (g_nemround) g_respawn_as_zombie[player] = false
  9309.    
  9310.     respawn_player_manually(player);
  9311. }
  9312.  
  9313. // Admin Command. zp_swarm
  9314. command_swarm(id)
  9315. {
  9316.     // Show activity?
  9317.     switch (get_pcvar_num(cvar_showactivity))
  9318.     {
  9319.         case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_SWARM")
  9320.         case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_SWARM")
  9321.     }
  9322.    
  9323.     // Log to Zombie Plague log file?
  9324.     if (get_pcvar_num(cvar_logcommands))
  9325.     {
  9326.         static logdata[100], authid[32], ip[16]
  9327.         get_user_authid(id, authid, charsmax(authid))
  9328.         get_user_ip(id, ip, charsmax(ip), 1)
  9329.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER, "CMD_SWARM", fnGetPlaying(), g_maxplayers)
  9330.         log_to_file("zombieplague.log", logdata)
  9331.     }
  9332.    
  9333.     // Call Swarm Mode
  9334.     remove_task(TASK_MAKEZOMBIE)
  9335.     make_a_zombie(MODE_SWARM, 0)
  9336. }
  9337.  
  9338. // Admin Command. zp_multi
  9339. command_multi(id)
  9340. {
  9341.     // Show activity?
  9342.     switch (get_pcvar_num(cvar_showactivity))
  9343.     {
  9344.         case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_MULTI")
  9345.         case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_MULTI")
  9346.     }
  9347.    
  9348.     // Log to Zombie Plague log file?
  9349.     if (get_pcvar_num(cvar_logcommands))
  9350.     {
  9351.         static logdata[100], authid[32], ip[16]
  9352.         get_user_authid(id, authid, charsmax(authid))
  9353.         get_user_ip(id, ip, charsmax(ip), 1)
  9354.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER,"CMD_MULTI", fnGetPlaying(), g_maxplayers)
  9355.         log_to_file("zombieplague.log", logdata)
  9356.     }
  9357.    
  9358.     // Call Multi Infection
  9359.     remove_task(TASK_MAKEZOMBIE)
  9360.     make_a_zombie(MODE_MULTI, 0)
  9361. }
  9362.  
  9363. // Admin Command. zp_plague
  9364. command_plague(id)
  9365. {
  9366.     // Show activity?
  9367.     switch (get_pcvar_num(cvar_showactivity))
  9368.     {
  9369.         case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_PLAGUE")
  9370.         case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_PLAGUE")
  9371.     }
  9372.    
  9373.     // Log to Zombie Plague log file?
  9374.     if (get_pcvar_num(cvar_logcommands))
  9375.     {
  9376.         static logdata[100], authid[32], ip[16]
  9377.         get_user_authid(id, authid, charsmax(authid))
  9378.         get_user_ip(id, ip, charsmax(ip), 1)
  9379.         formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER,"CMD_PLAGUE", fnGetPlaying(), g_maxplayers)
  9380.         log_to_file("zombieplague.log", logdata)
  9381.     }
  9382.    
  9383.     // Call Plague Mode
  9384.     remove_task(TASK_MAKEZOMBIE)
  9385.     make_a_zombie(MODE_PLAGUE, 0)
  9386. }
  9387.  
  9388. // Set proper maxspeed for player
  9389. set_player_maxspeed(id)
  9390. {
  9391.     // If frozen, prevent from moving
  9392.     if (g_frozen[id])
  9393.     {
  9394.         set_pev(id, pev_maxspeed, 1.0)
  9395.     }
  9396.     // Otherwise, set maxspeed directly
  9397.     else
  9398.     {
  9399.         if (g_zombie[id])
  9400.         {
  9401.             if (g_nemesis[id])
  9402.                 set_pev(id, pev_maxspeed, get_pcvar_float(cvar_nemspd))
  9403.             else
  9404.                 set_pev(id, pev_maxspeed, g_zombie_spd[id])
  9405.         }
  9406.         else
  9407.         {
  9408.             if (g_survivor[id])
  9409.                 set_pev(id, pev_maxspeed, get_pcvar_float(cvar_survspd))
  9410.             else if (get_pcvar_float(cvar_humanspd) > 0.0)
  9411.                 set_pev(id, pev_maxspeed, get_pcvar_float(cvar_humanspd))
  9412.         }
  9413.     }
  9414. }
  9415.  
  9416. /*================================================================================
  9417.  [Custom Natives]
  9418. =================================================================================*/
  9419.  
  9420. // Native: zp_get_user_zombie
  9421. public native_get_user_zombie(id)
  9422. {
  9423.     if (!is_user_valid(id))
  9424.     {
  9425.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9426.         return -1;
  9427.     }
  9428.    
  9429.     return g_zombie[id];
  9430. }
  9431.  
  9432. // Native: zp_get_user_nemesis
  9433. public native_get_user_nemesis(id)
  9434. {
  9435.     if (!is_user_valid(id))
  9436.     {
  9437.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9438.         return -1;
  9439.     }
  9440.    
  9441.     return g_nemesis[id];
  9442. }
  9443.  
  9444. // Native: zp_get_user_survivor
  9445. public native_get_user_survivor(id)
  9446. {
  9447.     if (!is_user_valid(id))
  9448.     {
  9449.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9450.         return -1;
  9451.     }
  9452.    
  9453.     return g_survivor[id];
  9454. }
  9455.  
  9456. public native_get_user_first_zombie(id)
  9457. {
  9458.     if (!is_user_valid(id))
  9459.     {
  9460.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9461.         return -1;
  9462.     }
  9463.    
  9464.     return g_firstzombie[id];
  9465. }
  9466.  
  9467. // Native: zp_get_user_last_zombie
  9468. public native_get_user_last_zombie(id)
  9469. {
  9470.     if (!is_user_valid(id))
  9471.     {
  9472.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9473.         return -1;
  9474.     }
  9475.    
  9476.     return g_lastzombie[id];
  9477. }
  9478.  
  9479. // Native: zp_get_user_last_human
  9480. public native_get_user_last_human(id)
  9481. {
  9482.     if (!is_user_valid(id))
  9483.     {
  9484.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9485.         return -1;
  9486.     }
  9487.    
  9488.     return g_lasthuman[id];
  9489. }
  9490.  
  9491. // Native: zp_get_user_zombie_class
  9492. public native_get_user_zombie_class(id)
  9493. {
  9494.     if (!is_user_valid(id))
  9495.     {
  9496.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9497.         return -1;
  9498.     }
  9499.    
  9500.     return g_zombieclass[id];
  9501. }
  9502.  
  9503. // Native: zp_get_user_next_class
  9504. public native_get_user_next_class(id)
  9505. {
  9506.     if (!is_user_valid(id))
  9507.     {
  9508.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9509.         return -1;
  9510.     }
  9511.    
  9512.     return g_zombieclassnext[id];
  9513. }
  9514.  
  9515. // Native: zp_set_user_zombie_class
  9516. public native_set_user_zombie_class(id, classid)
  9517. {
  9518.     if (!is_user_valid(id))
  9519.     {
  9520.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9521.         return false;
  9522.     }
  9523.    
  9524.     if (classid < 0 || classid >= g_zclass_i)
  9525.     {
  9526.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid zombie class id (%d)", classid)
  9527.         return false;
  9528.     }
  9529.    
  9530.     g_zombieclassnext[id] = classid
  9531.     return true;
  9532. }
  9533.  
  9534. // Native: zp_get_user_ammo_packs
  9535. public native_get_user_ammo_packs(id)
  9536. {
  9537.     if (!is_user_valid(id))
  9538.     {
  9539.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9540.         return -1;
  9541.     }
  9542.    
  9543.     return g_ammopacks[id];
  9544. }
  9545.  
  9546. // Native: zp_set_user_ammo_packs
  9547. public native_set_user_ammo_packs(id, amount)
  9548. {
  9549.     if (!is_user_valid(id))
  9550.     {
  9551.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9552.         return false;
  9553.     }
  9554.    
  9555.     g_ammopacks[id] = amount;
  9556.     return true;
  9557. }
  9558.  
  9559. // Native: zp_get_zombie_maxhealth
  9560. public native_get_zombie_maxhealth(id)
  9561. {
  9562.     // ZP disabled
  9563.     if (!g_pluginenabled)
  9564.         return -1;
  9565.    
  9566.     if (!is_user_valid(id))
  9567.     {
  9568.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9569.         return -1;
  9570.     }
  9571.    
  9572.     if (!g_zombie[id] || g_nemesis[id])
  9573.     {
  9574.         log_error(AMX_ERR_NATIVE, "[ZP] Player not a normal zombie (%d)", id)
  9575.         return -1;
  9576.     }
  9577.    
  9578.     if (g_firstzombie[id])
  9579.         return floatround(float(ArrayGetCell(g_zclass_hp, g_zombieclass[id])) * get_pcvar_float(cvar_zombiefirsthp));
  9580.    
  9581.     return ArrayGetCell(g_zclass_hp, g_zombieclass[id]);
  9582. }
  9583.  
  9584. // Native: zp_get_user_batteries
  9585. public native_get_user_batteries(id)
  9586. {
  9587.     if (!is_user_valid(id))
  9588.     {
  9589.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9590.         return -1;
  9591.     }
  9592.    
  9593.     return g_flashbattery[id];
  9594. }
  9595.  
  9596. // Native: zp_set_user_batteries
  9597. public native_set_user_batteries(id, value)
  9598. {
  9599.     // ZP disabled
  9600.     if (!g_pluginenabled)
  9601.         return false;
  9602.    
  9603.     if (!is_user_valid_connected(id))
  9604.     {
  9605.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9606.         return false;
  9607.     }
  9608.    
  9609.     g_flashbattery[id] = clamp(value, 0, 100);
  9610.    
  9611.     if (g_cached_customflash)
  9612.     {
  9613.         // Set the flashlight charge task to update battery status
  9614.         remove_task(id+TASK_CHARGE)
  9615.         set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
  9616.     }
  9617.     return true;
  9618. }
  9619.  
  9620. // Native: zp_get_user_nightvision
  9621. public native_get_user_nightvision(id)
  9622. {
  9623.     if (!is_user_valid(id))
  9624.     {
  9625.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9626.         return -1;
  9627.     }
  9628.    
  9629.     return g_nvision[id];
  9630. }
  9631.  
  9632. // Native: zp_set_user_nightvision
  9633. public native_set_user_nightvision(id, set)
  9634. {
  9635.     // ZP disabled
  9636.     if (!g_pluginenabled)
  9637.         return false;
  9638.    
  9639.     if (!is_user_valid_connected(id))
  9640.     {
  9641.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9642.         return false;
  9643.     }
  9644.    
  9645.     if (set)
  9646.     {
  9647.         g_nvision[id] = true
  9648.        
  9649.         if (!g_isbot[id])
  9650.         {
  9651.             g_nvisionenabled[id] = true
  9652.            
  9653.             // Custom nvg?
  9654.             if (get_pcvar_num(cvar_customnvg))
  9655.             {
  9656.                 remove_task(id+TASK_NVISION)
  9657.                 set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
  9658.             }
  9659.             else
  9660.                 set_user_gnvision(id, 1)
  9661.         }
  9662.         else
  9663.             cs_set_user_nvg(id, 1)
  9664.     }
  9665.     else
  9666.     {
  9667.         // Remove CS nightvision if player owns one (bugfix)
  9668.         cs_set_user_nvg(id, 0)
  9669.        
  9670.         if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
  9671.         else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
  9672.         g_nvision[id] = false
  9673.         g_nvisionenabled[id] = false
  9674.     }
  9675.     return true;
  9676. }
  9677.  
  9678. // Native: zp_infect_user
  9679. public native_infect_user(id, infector, silent, rewards)
  9680. {
  9681.     // ZP disabled
  9682.     if (!g_pluginenabled)
  9683.         return false;
  9684.    
  9685.     if (!is_user_valid_alive(id))
  9686.     {
  9687.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9688.         return false;
  9689.     }
  9690.    
  9691.     // Not allowed to be zombie
  9692.     if (!allowed_zombie(id))
  9693.         return false;
  9694.    
  9695.     // New round?
  9696.     if (g_newround)
  9697.     {
  9698.         // Set as first zombie
  9699.         remove_task(TASK_MAKEZOMBIE)
  9700.         make_a_zombie(MODE_INFECTION, id)
  9701.     }
  9702.     else
  9703.     {
  9704.         // Just infect (plus some checks)
  9705.         zombieme(id, is_user_valid_alive(infector) ? infector : 0, 0, (silent == 1) ? 1 : 0, (rewards == 1) ? 1 : 0)
  9706.     }
  9707.     return true;
  9708. }
  9709.  
  9710. // Native: zp_disinfect_user
  9711. public native_disinfect_user(id, silent)
  9712. {
  9713.     // ZP disabled
  9714.     if (!g_pluginenabled)
  9715.         return false;
  9716.    
  9717.     if (!is_user_valid_alive(id))
  9718.     {
  9719.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9720.         return false;
  9721.     }
  9722.    
  9723.     // Not allowed to be human
  9724.     if (!allowed_human(id))
  9725.         return false;
  9726.    
  9727.     // Turn to human
  9728.     humanme(id, 0, (silent == 1) ? 1 : 0)
  9729.     return true;
  9730. }
  9731.  
  9732. // Native: zp_make_user_nemesis
  9733. public native_make_user_nemesis(id)
  9734. {
  9735.     // ZP disabled
  9736.     if (!g_pluginenabled)
  9737.         return false;
  9738.    
  9739.     if (!is_user_valid_alive(id))
  9740.     {
  9741.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9742.         return false;
  9743.     }
  9744.    
  9745.     // Not allowed to be nemesis
  9746.     if (!allowed_nemesis(id))
  9747.         return false;
  9748.    
  9749.     // New round?
  9750.     if (g_newround)
  9751.     {
  9752.         // Set as first nemesis
  9753.         remove_task(TASK_MAKEZOMBIE)
  9754.         make_a_zombie(MODE_NEMESIS, id)
  9755.     }
  9756.     else
  9757.     {
  9758.         // Turn player into a Nemesis
  9759.         zombieme(id, 0, 1, 0, 0)
  9760.     }
  9761.     return true;
  9762. }
  9763.  
  9764. // Native: zp_make_user_survivor
  9765. public native_make_user_survivor(id)
  9766. {
  9767.     // ZP disabled
  9768.     if (!g_pluginenabled)
  9769.         return false;
  9770.    
  9771.     if (!is_user_valid_alive(id))
  9772.     {
  9773.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9774.         return false;
  9775.     }
  9776.    
  9777.     // Not allowed to be survivor
  9778.     if (!allowed_survivor(id))
  9779.         return false;
  9780.    
  9781.     // New round?
  9782.     if (g_newround)
  9783.     {
  9784.         // Set as first survivor
  9785.         remove_task(TASK_MAKEZOMBIE)
  9786.         make_a_zombie(MODE_SURVIVOR, id)
  9787.     }
  9788.     else
  9789.     {
  9790.         // Turn player into a Survivor
  9791.         humanme(id, 1, 0)
  9792.     }
  9793.    
  9794.     return true;
  9795. }
  9796.  
  9797. // Native: zp_respawn_user
  9798. public native_respawn_user(id, team)
  9799. {
  9800.     // ZP disabled
  9801.     if (!g_pluginenabled)
  9802.         return false;
  9803.    
  9804.     if (!is_user_valid_connected(id))
  9805.     {
  9806.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9807.         return false;
  9808.     }
  9809.    
  9810.     // Respawn not allowed
  9811.     if (!allowed_respawn(id))
  9812.         return false;
  9813.    
  9814.     // Respawn as zombie?
  9815.     g_respawn_as_zombie[id] = (team == ZP_TEAM_ZOMBIE) ? true : false
  9816.    
  9817.     // Respawnish!
  9818.     respawn_player_manually(id)
  9819.     return true;
  9820. }
  9821.  
  9822. // Native: zp_force_buy_extra_item
  9823. public native_force_buy_extra_item(id, itemid, ignorecost)
  9824. {
  9825.     // ZP disabled
  9826.     if (!g_pluginenabled)
  9827.         return false;
  9828.    
  9829.     if (!is_user_valid_alive(id))
  9830.     {
  9831.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9832.         return false;
  9833.     }
  9834.    
  9835.     if (itemid < 0 || itemid >= g_extraitem_i)
  9836.     {
  9837.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid extra item id (%d)", itemid)
  9838.         return false;
  9839.     }
  9840.    
  9841.     buy_extra_item(id, itemid, ignorecost)
  9842.     return true;
  9843. }
  9844.  
  9845. // Native: zp_override_user_model
  9846. public native_override_user_model(id, const newmodel[], modelindex)
  9847. {
  9848.     // ZP disabled
  9849.     if (!g_pluginenabled)
  9850.         return false;
  9851.    
  9852.     if (!is_user_valid_connected(id))
  9853.     {
  9854.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid Player (%d)", id)
  9855.         return false;
  9856.     }
  9857.    
  9858.     // Strings passed byref
  9859.     param_convert(2)
  9860.    
  9861.     // Remove previous tasks
  9862.     remove_task(id+TASK_MODEL)
  9863.    
  9864.     // Custom models stuff
  9865.     static currentmodel[32]
  9866.    
  9867.     if (g_handle_models_on_separate_ent)
  9868.     {
  9869.         // Set the right model
  9870.         copy(g_playermodel[id], charsmax(g_playermodel[]), newmodel)
  9871.         if (g_set_modelindex_offset && modelindex) fm_cs_set_user_model_index(id, modelindex)
  9872.        
  9873.         // Set model on player model entity
  9874.         fm_set_playermodel_ent(id)
  9875.     }
  9876.     else
  9877.     {
  9878.         // Get current model for comparing it with the current one
  9879.         fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
  9880.        
  9881.         // Set the right model, after checking that we don't already have it
  9882.         if (!equal(currentmodel, newmodel))
  9883.         {
  9884.             copy(g_playermodel[id], charsmax(g_playermodel[]), newmodel)
  9885.             if (g_set_modelindex_offset && modelindex) fm_cs_set_user_model_index(id, modelindex)
  9886.            
  9887.             // An additional delay is offset at round start
  9888.             // since SVC_BAD is more likely to be triggered there
  9889.             if (g_newround)
  9890.                 set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
  9891.             else
  9892.                 fm_user_model_update(id+TASK_MODEL)
  9893.         }
  9894.     }
  9895.     return true;
  9896. }
  9897.  
  9898. // Native: zp_has_round_started
  9899. public native_has_round_started()
  9900. {
  9901.     if (g_newround) return 0; // not started
  9902.     if (g_modestarted) return 1; // started
  9903.     return 2; // starting
  9904. }
  9905.  
  9906. // Native: zp_is_nemesis_round
  9907. public native_is_nemesis_round()
  9908. {
  9909.     return g_nemround;
  9910. }
  9911.  
  9912. // Native: zp_is_survivor_round
  9913. public native_is_survivor_round()
  9914. {
  9915.     return g_survround;
  9916. }
  9917.  
  9918. // Native: zp_is_swarm_round
  9919. public native_is_swarm_round()
  9920. {
  9921.     return g_swarmround;
  9922. }
  9923.  
  9924. // Native: zp_is_plague_round
  9925. public native_is_plague_round()
  9926. {
  9927.     return g_plagueround;
  9928. }
  9929.  
  9930. // Native: zp_get_zombie_count
  9931. public native_get_zombie_count()
  9932. {
  9933.     return fnGetZombies();
  9934. }
  9935.  
  9936. // Native: zp_get_human_count
  9937. public native_get_human_count()
  9938. {
  9939.     return fnGetHumans();
  9940. }
  9941.  
  9942. // Native: zp_get_nemesis_count
  9943. public native_get_nemesis_count()
  9944. {
  9945.     return fnGetNemesis();
  9946. }
  9947.  
  9948. // Native: zp_get_survivor_count
  9949. public native_get_survivor_count()
  9950. {
  9951.     return fnGetSurvivors();
  9952. }
  9953.  
  9954. // Native: zp_register_extra_item
  9955. public native_register_extra_item(const name[], cost, team)
  9956. {
  9957.     // ZP disabled
  9958.     if (!g_pluginenabled)
  9959.         return -1;
  9960.    
  9961.     // Strings passed byref
  9962.     param_convert(1)
  9963.    
  9964.     // Arrays not yet initialized
  9965.     if (!g_arrays_created)
  9966.     {
  9967.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register extra item yet (%s)", name)
  9968.         return -1;
  9969.     }
  9970.    
  9971.     if (strlen(name) < 1)
  9972.     {
  9973.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register extra item with an empty name")
  9974.         return -1;
  9975.     }
  9976.    
  9977.     new index, extraitem_name[32]
  9978.     for (index = 0; index < g_extraitem_i; index++)
  9979.     {
  9980.         ArrayGetString(g_extraitem_name, index, extraitem_name, charsmax(extraitem_name))
  9981.         if (equali(name, extraitem_name))
  9982.         {
  9983.             log_error(AMX_ERR_NATIVE, "[ZP] Extra item already registered (%s)", name)
  9984.             return -1;
  9985.         }
  9986.     }
  9987.    
  9988.     // For backwards compatibility
  9989.     if (team == ZP_TEAM_ANY)
  9990.         team = (ZP_TEAM_ZOMBIE|ZP_TEAM_HUMAN)
  9991.    
  9992.     // Add the item
  9993.     ArrayPushString(g_extraitem_name, name)
  9994.     ArrayPushCell(g_extraitem_cost, cost)
  9995.     ArrayPushCell(g_extraitem_team, team)
  9996.    
  9997.     // Set temporary new item flag
  9998.     ArrayPushCell(g_extraitem_new, 1)
  9999.    
  10000.     // Override extra items data with our customizations
  10001.     new i, buffer[32], size = ArraySize(g_extraitem2_realname)
  10002.     for (i = 0; i < size; i++)
  10003.     {
  10004.         ArrayGetString(g_extraitem2_realname, i, buffer, charsmax(buffer))
  10005.        
  10006.         // Check if this is the intended item to override
  10007.         if (!equal(name, buffer))
  10008.             continue;
  10009.        
  10010.         // Remove new item flag
  10011.         ArraySetCell(g_extraitem_new, g_extraitem_i, 0)
  10012.        
  10013.         // Replace caption
  10014.         ArrayGetString(g_extraitem2_name, i, buffer, charsmax(buffer))
  10015.         ArraySetString(g_extraitem_name, g_extraitem_i, buffer)
  10016.        
  10017.         // Replace cost
  10018.         buffer[0] = ArrayGetCell(g_extraitem2_cost, i)
  10019.         ArraySetCell(g_extraitem_cost, g_extraitem_i, buffer[0])
  10020.        
  10021.         // Replace team
  10022.         buffer[0] = ArrayGetCell(g_extraitem2_team, i)
  10023.         ArraySetCell(g_extraitem_team, g_extraitem_i, buffer[0])
  10024.     }
  10025.    
  10026.     // Increase registered items counter
  10027.     g_extraitem_i++
  10028.    
  10029.     // Return id under which we registered the item
  10030.     return g_extraitem_i-1;
  10031. }
  10032.  
  10033. // Function: zp_register_extra_item (to be used within this plugin only)
  10034. native_register_extra_item2(const name[], cost, team)
  10035. {
  10036.     // Add the item
  10037.     ArrayPushString(g_extraitem_name, name)
  10038.     ArrayPushCell(g_extraitem_cost, cost)
  10039.     ArrayPushCell(g_extraitem_team, team)
  10040.    
  10041.     // Set temporary new item flag
  10042.     ArrayPushCell(g_extraitem_new, 1)
  10043.    
  10044.     // Increase registered items counter
  10045.     g_extraitem_i++
  10046. }
  10047.  
  10048. // Native: zp_register_zombie_class
  10049. public native_register_zombie_class(const name[], const info[], const model[], const clawmodel[], hp, speed, Float:gravity, Float:knockback)
  10050. {
  10051.     // ZP disabled
  10052.     if (!g_pluginenabled)
  10053.         return -1;
  10054.    
  10055.     // Strings passed byref
  10056.     param_convert(1)
  10057.     param_convert(2)
  10058.     param_convert(3)
  10059.     param_convert(4)
  10060.    
  10061.     // Arrays not yet initialized
  10062.     if (!g_arrays_created)
  10063.     {
  10064.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register zombie class yet (%s)", name)
  10065.         return -1;
  10066.     }
  10067.    
  10068.     if (strlen(name) < 1)
  10069.     {
  10070.         log_error(AMX_ERR_NATIVE, "[ZP] Can't register zombie class with an empty name")
  10071.         return -1;
  10072.     }
  10073.    
  10074.     new index, zombieclass_name[32]
  10075.     for (index = 0; index < g_zclass_i; index++)
  10076.     {
  10077.         ArrayGetString(g_zclass_name, index, zombieclass_name, charsmax(zombieclass_name))
  10078.         if (equali(name, zombieclass_name))
  10079.         {
  10080.             log_error(AMX_ERR_NATIVE, "[ZP] Zombie class already registered (%s)", name)
  10081.             return -1;
  10082.         }
  10083.     }
  10084.    
  10085.     // Add the class
  10086.     ArrayPushString(g_zclass_name, name)
  10087.     ArrayPushString(g_zclass_info, info)
  10088.    
  10089.     // Using same zombie models for all classes?
  10090.     if (g_same_models_for_all)
  10091.     {
  10092.         ArrayPushCell(g_zclass_modelsstart, 0)
  10093.         ArrayPushCell(g_zclass_modelsend, ArraySize(g_zclass_playermodel))
  10094.     }
  10095.     else
  10096.     {
  10097.         ArrayPushCell(g_zclass_modelsstart, ArraySize(g_zclass_playermodel))
  10098.         ArrayPushString(g_zclass_playermodel, model)
  10099.         ArrayPushCell(g_zclass_modelsend, ArraySize(g_zclass_playermodel))
  10100.         ArrayPushCell(g_zclass_modelindex, -1)
  10101.     }
  10102.    
  10103.     ArrayPushString(g_zclass_clawmodel, clawmodel)
  10104.     ArrayPushCell(g_zclass_hp, hp)
  10105.     ArrayPushCell(g_zclass_spd, speed)
  10106.     ArrayPushCell(g_zclass_grav, gravity)
  10107.     ArrayPushCell(g_zclass_kb, knockback)
  10108.    
  10109.     // Set temporary new class flag
  10110.     ArrayPushCell(g_zclass_new, 1)
  10111.    
  10112.     // Override zombie classes data with our customizations
  10113.     new i, k, buffer[32], Float:buffer2, nummodels_custom, nummodels_default, prec_mdl[100], size = ArraySize(g_zclass2_realname)
  10114.     for (i = 0; i < size; i++)
  10115.     {
  10116.         ArrayGetString(g_zclass2_realname, i, buffer, charsmax(buffer))
  10117.        
  10118.         // Check if this is the intended class to override
  10119.         if (!equal(name, buffer))
  10120.             continue;
  10121.        
  10122.         // Remove new class flag
  10123.         ArraySetCell(g_zclass_new, g_zclass_i, 0)
  10124.        
  10125.         // Replace caption
  10126.         ArrayGetString(g_zclass2_name, i, buffer, charsmax(buffer))
  10127.         ArraySetString(g_zclass_name, g_zclass_i, buffer)
  10128.        
  10129.         // Replace info
  10130.         ArrayGetString(g_zclass2_info, i, buffer, charsmax(buffer))
  10131.         ArraySetString(g_zclass_info, g_zclass_i, buffer)
  10132.        
  10133.         // Replace models, unless using same models for all classes
  10134.         if (!g_same_models_for_all)
  10135.         {
  10136.             nummodels_custom = ArrayGetCell(g_zclass2_modelsend, i) - ArrayGetCell(g_zclass2_modelsstart, i)
  10137.             nummodels_default = ArrayGetCell(g_zclass_modelsend, g_zclass_i) - ArrayGetCell(g_zclass_modelsstart, g_zclass_i)
  10138.            
  10139.             // Replace each player model and model index
  10140.             for (k = 0; k < min(nummodels_custom, nummodels_default); k++)
  10141.             {
  10142.                 ArrayGetString(g_zclass2_playermodel, ArrayGetCell(g_zclass2_modelsstart, i) + k, buffer, charsmax(buffer))
  10143.                 ArraySetString(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k, buffer)
  10144.                
  10145.                 // Precache player model and replace its modelindex with the real one
  10146.                 formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", buffer, buffer)
  10147.                 ArraySetCell(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k, engfunc(EngFunc_PrecacheModel, prec_mdl))
  10148.                 if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
  10149.                 if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
  10150.                 // Precache modelT.mdl files too
  10151.                 copy(prec_mdl[strlen(prec_mdl)-4], charsmax(prec_mdl) - (strlen(prec_mdl)-4), "T.mdl")
  10152.                 if (file_exists(prec_mdl)) engfunc(EngFunc_PrecacheModel, prec_mdl)
  10153.             }
  10154.            
  10155.             // We have more custom models than what we can accommodate,
  10156.             // Let's make some space...
  10157.             if (nummodels_custom > nummodels_default)
  10158.             {
  10159.                 for (k = nummodels_default; k < nummodels_custom; k++)
  10160.                 {
  10161.                     ArrayGetString(g_zclass2_playermodel, ArrayGetCell(g_zclass2_modelsstart, i) + k, buffer, charsmax(buffer))
  10162.                     ArrayInsertStringAfter(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k - 1, buffer)
  10163.                    
  10164.                     // Precache player model and retrieve its modelindex
  10165.                     formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", buffer, buffer)
  10166.                     ArrayInsertCellAfter(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k - 1, engfunc(EngFunc_PrecacheModel, prec_mdl))
  10167.                     if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
  10168.                     if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
  10169.                     // Precache modelT.mdl files too
  10170.                     copy(prec_mdl[strlen(prec_mdl)-4], charsmax(prec_mdl) - (strlen(prec_mdl)-4), "T.mdl")
  10171.                     if (file_exists(prec_mdl)) engfunc(EngFunc_PrecacheModel, prec_mdl)
  10172.                 }
  10173.                
  10174.                 // Fix models end index for this class
  10175.                 ArraySetCell(g_zclass_modelsend, g_zclass_i, ArrayGetCell(g_zclass_modelsend, g_zclass_i) + (nummodels_custom - nummodels_default))
  10176.             }
  10177.            
  10178.             /* --- Not needed since classes can't have more than 1 default model for now ---
  10179.             // We have less custom models than what this class has by default,
  10180.             // Get rid of those extra entries...
  10181.             if (nummodels_custom < nummodels_default)
  10182.             {
  10183.                 for (k = nummodels_custom; k < nummodels_default; k++)
  10184.                 {
  10185.                     ArrayDeleteItem(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + nummodels_custom)
  10186.                 }
  10187.                
  10188.                 // Fix models end index for this class
  10189.                 ArraySetCell(g_zclass_modelsend, g_zclass_i, ArrayGetCell(g_zclass_modelsend, g_zclass_i) - (nummodels_default - nummodels_custom))
  10190.             }
  10191.             */
  10192.         }
  10193.        
  10194.         // Replace clawmodel
  10195.         ArrayGetString(g_zclass2_clawmodel, i, buffer, charsmax(buffer))
  10196.         ArraySetString(g_zclass_clawmodel, g_zclass_i, buffer)
  10197.        
  10198.         // Precache clawmodel
  10199.         formatex(prec_mdl, charsmax(prec_mdl), "models/zombie_plague/%s", buffer)
  10200.         engfunc(EngFunc_PrecacheModel, prec_mdl)
  10201.        
  10202.         // Replace health
  10203.         buffer[0] = ArrayGetCell(g_zclass2_hp, i)
  10204.         ArraySetCell(g_zclass_hp, g_zclass_i, buffer[0])
  10205.        
  10206.         // Replace speed
  10207.         buffer[0] = ArrayGetCell(g_zclass2_spd, i)
  10208.         ArraySetCell(g_zclass_spd, g_zclass_i, buffer[0])
  10209.        
  10210.         // Replace gravity
  10211.         buffer2 = Float:ArrayGetCell(g_zclass2_grav, i)
  10212.         ArraySetCell(g_zclass_grav, g_zclass_i, buffer2)
  10213.        
  10214.         // Replace knockback
  10215.         buffer2 = Float:ArrayGetCell(g_zclass2_kb, i)
  10216.         ArraySetCell(g_zclass_kb, g_zclass_i, buffer2)
  10217.     }
  10218.    
  10219.     // If class was not overriden with customization data
  10220.     if (ArrayGetCell(g_zclass_new, g_zclass_i))
  10221.     {
  10222.         // If not using same models for all classes
  10223.         if (!g_same_models_for_all)
  10224.         {
  10225.             // Precache default class model and replace modelindex with the real one
  10226.             formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", model, model)
  10227.             ArraySetCell(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i), engfunc(EngFunc_PrecacheModel, prec_mdl))
  10228.             if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
  10229.             if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
  10230.             // Precache modelT.mdl files too
  10231.             copy(prec_mdl[strlen(prec_mdl)-4], charsmax(prec_mdl) - (strlen(prec_mdl)-4), "T.mdl")
  10232.             if (file_exists(prec_mdl)) engfunc(EngFunc_PrecacheModel, prec_mdl)
  10233.         }
  10234.        
  10235.         // Precache default clawmodel
  10236.         formatex(prec_mdl, charsmax(prec_mdl), "models/zombie_plague/%s", clawmodel)
  10237.         engfunc(EngFunc_PrecacheModel, prec_mdl)
  10238.     }
  10239.    
  10240.     // Increase registered classes counter
  10241.     g_zclass_i++
  10242.    
  10243.     // Return id under which we registered the class
  10244.     return g_zclass_i-1;
  10245. }
  10246.  
  10247. // Native: zp_get_extra_item_id
  10248. public native_get_extra_item_id(const name[])
  10249. {
  10250.     // ZP disabled
  10251.     if (!g_pluginenabled)
  10252.         return -1;
  10253.    
  10254.     // Strings passed byref
  10255.     param_convert(1)
  10256.    
  10257.     // Loop through every item (not using Tries since ZP should work on AMXX 1.8.0)
  10258.     static i, item_name[32]
  10259.     for (i = 0; i < g_extraitem_i; i++)
  10260.     {
  10261.         ArrayGetString(g_extraitem_name, i, item_name, charsmax(item_name))
  10262.        
  10263.         // Check if this is the item to retrieve
  10264.         if (equali(name, item_name))
  10265.             return i;
  10266.     }
  10267.    
  10268.     return -1;
  10269. }
  10270.  
  10271. // Native: zp_get_zombie_class_id
  10272. public native_get_zombie_class_id(const name[])
  10273. {
  10274.     // ZP disabled
  10275.     if (!g_pluginenabled)
  10276.         return -1;
  10277.    
  10278.     // Strings passed byref
  10279.     param_convert(1)
  10280.    
  10281.     // Loop through every class (not using Tries since ZP should work on AMXX 1.8.0)
  10282.     static i, class_name[32]
  10283.     for (i = 0; i < g_zclass_i; i++)
  10284.     {
  10285.         ArrayGetString(g_zclass_name, i, class_name, charsmax(class_name))
  10286.        
  10287.         // Check if this is the class to retrieve
  10288.         if (equali(name, class_name))
  10289.             return i;
  10290.     }
  10291.    
  10292.     return -1;
  10293. }
  10294.  
  10295. // Native: zp_get_zombie_class_info
  10296. public native_get_zombie_class_info(classid, info[], len)
  10297. {
  10298.     // ZP disabled
  10299.     if (!g_pluginenabled)
  10300.         return false;
  10301.    
  10302.     // Invalid class
  10303.     if (classid < 0 || classid >= g_zclass_i)
  10304.     {
  10305.         log_error(AMX_ERR_NATIVE, "[ZP] Invalid zombie class id (%d)", classid)
  10306.         return false;
  10307.     }
  10308.    
  10309.     // Strings passed byref
  10310.     param_convert(2)
  10311.    
  10312.     // Fetch zombie class info
  10313.     ArrayGetString(g_zclass_info, classid, info, len)
  10314.     return true;
  10315. }
  10316.  
  10317. /*================================================================================
  10318.  [Custom Messages]
  10319. =================================================================================*/
  10320.  
  10321. // Custom Night Vision
  10322. public set_user_nvision(taskid)
  10323. {
  10324.     // Get player's origin
  10325.     static origin[3]
  10326.     get_user_origin(ID_NVISION, origin)
  10327.    
  10328.     // Nightvision message
  10329.     message_begin(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, _, ID_NVISION)
  10330.     write_byte(TE_DLIGHT) // TE id
  10331.     write_coord(origin[0]) // x
  10332.     write_coord(origin[1]) // y
  10333.     write_coord(origin[2]) // z
  10334.     write_byte(get_pcvar_num(cvar_nvgsize)) // radius
  10335.    
  10336.     // Nemesis / Madness / Spectator in nemesis round
  10337.     if (g_nemesis[ID_NVISION] || (g_zombie[ID_NVISION] && g_nodamage[ID_NVISION]) || (!g_isalive[ID_NVISION] && g_nemround))
  10338.     {
  10339.         write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
  10340.         write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
  10341.         write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
  10342.     }
  10343.     // Human / Spectator in normal round
  10344.     else if (!g_zombie[ID_NVISION] || !g_isalive[ID_NVISION])
  10345.     {
  10346.         write_byte(get_pcvar_num(cvar_humnvgcolor[0])) // r
  10347.         write_byte(get_pcvar_num(cvar_humnvgcolor[1])) // g
  10348.         write_byte(get_pcvar_num(cvar_humnvgcolor[2])) // b
  10349.     }
  10350.     // Zombie
  10351.     else
  10352.     {
  10353.         write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
  10354.         write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
  10355.         write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
  10356.     }
  10357.    
  10358.     write_byte(2) // life
  10359.     write_byte(0) // decay rate
  10360.     message_end()
  10361. }
  10362.  
  10363. // Game Nightvision
  10364. set_user_gnvision(id, toggle)
  10365. {
  10366.     // Toggle NVG message
  10367.     message_begin(MSG_ONE, g_msgNVGToggle, _, id)
  10368.     write_byte(toggle) // toggle
  10369.     message_end()
  10370. }
  10371.  
  10372. // Custom Flashlight
  10373. public set_user_flashlight(taskid)
  10374. {
  10375.     // Get player and aiming origins
  10376.     static Float:originF[3], Float:destoriginF[3]
  10377.     pev(ID_FLASH, pev_origin, originF)
  10378.     fm_get_aim_origin(ID_FLASH, destoriginF)
  10379.    
  10380.     // Max distance check
  10381.     if (get_distance_f(originF, destoriginF) > get_pcvar_float(cvar_flashdist))
  10382.         return;
  10383.    
  10384.     // Send to all players?
  10385.     if (get_pcvar_num(cvar_flashshowall))
  10386.         engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, destoriginF, 0)
  10387.     else
  10388.         message_begin(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, _, ID_FLASH)
  10389.    
  10390.     // Flashlight
  10391.     write_byte(TE_DLIGHT) // TE id
  10392.     engfunc(EngFunc_WriteCoord, destoriginF[0]) // x
  10393.     engfunc(EngFunc_WriteCoord, destoriginF[1]) // y
  10394.     engfunc(EngFunc_WriteCoord, destoriginF[2]) // z
  10395.     write_byte(get_pcvar_num(cvar_flashsize)) // radius
  10396.     write_byte(get_pcvar_num(cvar_flashcolor[0])) // r
  10397.     write_byte(get_pcvar_num(cvar_flashcolor[1])) // g
  10398.     write_byte(get_pcvar_num(cvar_flashcolor[2])) // b
  10399.     write_byte(3) // life
  10400.     write_byte(0) // decay rate
  10401.     message_end()
  10402. }
  10403.  
  10404. // Infection special effects
  10405. infection_effects(id)
  10406. {
  10407.     // Screen fade? (unless frozen)
  10408.     if (!g_frozen[id] && get_pcvar_num(cvar_infectionscreenfade))
  10409.     {
  10410.         message_begin(MSG_ONE_UNRELIABLE, g_msgScreenFade, _, id)
  10411.         write_short(UNIT_SECOND) // duration
  10412.         write_short(0) // hold time
  10413.         write_short(FFADE_IN) // fade type
  10414.         if (g_nemesis[id])
  10415.         {
  10416.             write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
  10417.             write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
  10418.             write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
  10419.         }
  10420.         else
  10421.         {
  10422.             write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
  10423.             write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
  10424.             write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
  10425.         }
  10426.         write_byte (255) // alpha
  10427.         message_end()
  10428.     }
  10429.    
  10430.     // Screen shake?
  10431.     if (get_pcvar_num(cvar_infectionscreenshake))
  10432.     {
  10433.         message_begin(MSG_ONE_UNRELIABLE, g_msgScreenShake, _, id)
  10434.         write_short(UNIT_SECOND*4) // amplitude
  10435.         write_short(UNIT_SECOND*2) // duration
  10436.         write_short(UNIT_SECOND*10) // frequency
  10437.         message_end()
  10438.     }
  10439.    
  10440.     // Infection icon?
  10441.     if (get_pcvar_num(cvar_hudicons))
  10442.     {
  10443.         message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, id)
  10444.         write_byte(0) // damage save
  10445.         write_byte(0) // damage take
  10446.         write_long(DMG_NERVEGAS) // damage type - DMG_RADIATION
  10447.         write_coord(0) // x
  10448.         write_coord(0) // y
  10449.         write_coord(0) // z
  10450.         message_end()
  10451.     }
  10452.    
  10453.     // Get player's origin
  10454.     static origin[3]
  10455.     get_user_origin(id, origin)
  10456.    
  10457.     // Tracers?
  10458.     if (get_pcvar_num(cvar_infectiontracers))
  10459.     {
  10460.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10461.         write_byte(TE_IMPLOSION) // TE id
  10462.         write_coord(origin[0]) // x
  10463.         write_coord(origin[1]) // y
  10464.         write_coord(origin[2]) // z
  10465.         write_byte(128) // radius
  10466.         write_byte(20) // count
  10467.         write_byte(3) // duration
  10468.         message_end()
  10469.     }
  10470.    
  10471.     // Particle burst?
  10472.     if (get_pcvar_num(cvar_infectionparticles))
  10473.     {
  10474.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10475.         write_byte(TE_PARTICLEBURST) // TE id
  10476.         write_coord(origin[0]) // x
  10477.         write_coord(origin[1]) // y
  10478.         write_coord(origin[2]) // z
  10479.         write_short(50) // radius
  10480.         write_byte(70) // color
  10481.         write_byte(3) // duration (will be randomized a bit)
  10482.         message_end()
  10483.     }
  10484.    
  10485.     // Light sparkle?
  10486.     if (get_pcvar_num(cvar_infectionsparkle))
  10487.     {
  10488.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10489.         write_byte(TE_DLIGHT) // TE id
  10490.         write_coord(origin[0]) // x
  10491.         write_coord(origin[1]) // y
  10492.         write_coord(origin[2]) // z
  10493.         write_byte(20) // radius
  10494.         write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
  10495.         write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
  10496.         write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
  10497.         write_byte(2) // life
  10498.         write_byte(0) // decay rate
  10499.         message_end()
  10500.     }
  10501. }
  10502.  
  10503. // Nemesis/madness aura task
  10504. public zombie_aura(taskid)
  10505. {
  10506.     // Not nemesis, not in zombie madness
  10507.     if (!g_nemesis[ID_AURA] && !g_nodamage[ID_AURA])
  10508.     {
  10509.         // Task not needed anymore
  10510.         remove_task(taskid);
  10511.         return;
  10512.     }
  10513.    
  10514.     // Get player's origin
  10515.     static origin[3]
  10516.     get_user_origin(ID_AURA, origin)
  10517.    
  10518.     // Colored Aura
  10519.     message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10520.     write_byte(TE_DLIGHT) // TE id
  10521.     write_coord(origin[0]) // x
  10522.     write_coord(origin[1]) // y
  10523.     write_coord(origin[2]) // z
  10524.     write_byte(20) // radius
  10525.     write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
  10526.     write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
  10527.     write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
  10528.     write_byte(2) // life
  10529.     write_byte(0) // decay rate
  10530.     message_end()
  10531. }
  10532.  
  10533. // Make zombies leave footsteps and bloodstains on the floor
  10534. public make_blood(taskid)
  10535. {
  10536.     // Only bleed when moving on ground
  10537.     if (!(pev(ID_BLOOD, pev_flags) & FL_ONGROUND) || fm_get_speed(ID_BLOOD) < 80)
  10538.         return;
  10539.    
  10540.     // Get user origin
  10541.     static Float:originF[3]
  10542.     pev(ID_BLOOD, pev_origin, originF)
  10543.    
  10544.     // If ducking set a little lower
  10545.     if (pev(ID_BLOOD, pev_bInDuck))
  10546.         originF[2] -= 18.0
  10547.     else
  10548.         originF[2] -= 36.0
  10549.    
  10550.     // Send the decal message
  10551.     engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, originF, 0)
  10552.     write_byte(TE_WORLDDECAL) // TE id
  10553.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10554.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10555.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10556.     write_byte(ArrayGetCell(zombie_decals, random_num(0, ArraySize(zombie_decals) - 1)) + (g_czero * 12)) // random decal number (offsets +12 for CZ)
  10557.     message_end()
  10558. }
  10559.  
  10560. // Flare Lighting Effects
  10561. flare_lighting(entity, duration)
  10562. {
  10563.     // Get origin and color
  10564.     static Float:originF[3], color[3]
  10565.     pev(entity, pev_origin, originF)
  10566.     pev(entity, PEV_FLARE_COLOR, color)
  10567.    
  10568.     // Lighting
  10569.     engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, originF, 0)
  10570.     write_byte(TE_DLIGHT) // TE id
  10571.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10572.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10573.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10574.     write_byte(get_pcvar_num(cvar_flaresize)) // radius
  10575.     write_byte(color[0]) // r
  10576.     write_byte(color[1]) // g
  10577.     write_byte(color[2]) // b
  10578.     write_byte(21) //life
  10579.     write_byte((duration < 2) ? 3 : 0) //decay rate
  10580.     message_end()
  10581.    
  10582.     // Sparks
  10583.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10584.     write_byte(TE_SPARKS) // TE id
  10585.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10586.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10587.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10588.     message_end()
  10589. }
  10590.  
  10591. // Burning Flames
  10592. public burning_flame(taskid)
  10593. {
  10594.     // Get player origin and flags
  10595.     static origin[3], flags
  10596.     get_user_origin(ID_BURN, origin)
  10597.     flags = pev(ID_BURN, pev_flags)
  10598.    
  10599.     // Madness mode - in water - burning stopped
  10600.     if (g_nodamage[ID_BURN] || (flags & FL_INWATER) || g_burning_duration[ID_BURN] < 1)
  10601.     {
  10602.         // Smoke sprite
  10603.         message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10604.         write_byte(TE_SMOKE) // TE id
  10605.         write_coord(origin[0]) // x
  10606.         write_coord(origin[1]) // y
  10607.         write_coord(origin[2]-50) // z
  10608.         write_short(g_smokeSpr) // sprite
  10609.         write_byte(random_num(15, 20)) // scale
  10610.         write_byte(random_num(10, 20)) // framerate
  10611.         message_end()
  10612.        
  10613.         // Task not needed anymore
  10614.         remove_task(taskid);
  10615.         return;
  10616.     }
  10617.    
  10618.     // Randomly play burning zombie scream sounds (not for nemesis)
  10619.     if (!g_nemesis[ID_BURN] && !random_num(0, 20))
  10620.     {
  10621.         static sound[64]
  10622.         ArrayGetString(grenade_fire_player, random_num(0, ArraySize(grenade_fire_player) - 1), sound, charsmax(sound))
  10623.         emit_sound(ID_BURN, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
  10624.     }
  10625.    
  10626.     // Fire slow down, unless nemesis
  10627.     if (!g_nemesis[ID_BURN] && (flags & FL_ONGROUND) && get_pcvar_float(cvar_fireslowdown) > 0.0)
  10628.     {
  10629.         static Float:velocity[3]
  10630.         pev(ID_BURN, pev_velocity, velocity)
  10631.         xs_vec_mul_scalar(velocity, get_pcvar_float(cvar_fireslowdown), velocity)
  10632.         set_pev(ID_BURN, pev_velocity, velocity)
  10633.     }
  10634.    
  10635.     // Get player's health
  10636.     static health
  10637.     health = pev(ID_BURN, pev_health)
  10638.    
  10639.     // Take damage from the fire
  10640.     if (health - floatround(get_pcvar_float(cvar_firedamage), floatround_ceil) > 0)
  10641.         fm_set_user_health(ID_BURN, health - floatround(get_pcvar_float(cvar_firedamage), floatround_ceil))
  10642.    
  10643.     // Flame sprite
  10644.     message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
  10645.     write_byte(TE_SPRITE) // TE id
  10646.     write_coord(origin[0]+random_num(-5, 5)) // x
  10647.     write_coord(origin[1]+random_num(-5, 5)) // y
  10648.     write_coord(origin[2]+random_num(-10, 10)) // z
  10649.     write_short(g_flameSpr) // sprite
  10650.     write_byte(random_num(5, 10)) // scale
  10651.     write_byte(200) // brightness
  10652.     message_end()
  10653.    
  10654.     // Decrease burning duration counter
  10655.     g_burning_duration[ID_BURN]--
  10656. }
  10657.  
  10658. // Infection Bomb: Green Blast
  10659. create_blast(const Float:originF[3])
  10660. {
  10661.     // Smallest ring
  10662.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10663.     write_byte(TE_BEAMCYLINDER) // TE id
  10664.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10665.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10666.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10667.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10668.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10669.     engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
  10670.     write_short(g_exploSpr) // sprite
  10671.     write_byte(0) // startframe
  10672.     write_byte(0) // framerate
  10673.     write_byte(4) // life
  10674.     write_byte(60) // width
  10675.     write_byte(0) // noise
  10676.     write_byte(0) // red
  10677.     write_byte(200) // green
  10678.     write_byte(0) // blue
  10679.     write_byte(200) // brightness
  10680.     write_byte(0) // speed
  10681.     message_end()
  10682.    
  10683.     // Medium ring
  10684.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10685.     write_byte(TE_BEAMCYLINDER) // TE id
  10686.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10687.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10688.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10689.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10690.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10691.     engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
  10692.     write_short(g_exploSpr) // sprite
  10693.     write_byte(0) // startframe
  10694.     write_byte(0) // framerate
  10695.     write_byte(4) // life
  10696.     write_byte(60) // width
  10697.     write_byte(0) // noise
  10698.     write_byte(0) // red
  10699.     write_byte(200) // green
  10700.     write_byte(0) // blue
  10701.     write_byte(200) // brightness
  10702.     write_byte(0) // speed
  10703.     message_end()
  10704.    
  10705.     // Largest ring
  10706.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10707.     write_byte(TE_BEAMCYLINDER) // TE id
  10708.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10709.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10710.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10711.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10712.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10713.     engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
  10714.     write_short(g_exploSpr) // sprite
  10715.     write_byte(0) // startframe
  10716.     write_byte(0) // framerate
  10717.     write_byte(4) // life
  10718.     write_byte(60) // width
  10719.     write_byte(0) // noise
  10720.     write_byte(0) // red
  10721.     write_byte(200) // green
  10722.     write_byte(0) // blue
  10723.     write_byte(200) // brightness
  10724.     write_byte(0) // speed
  10725.     message_end()
  10726. }
  10727.  
  10728. // Fire Grenade: Fire Blast
  10729. create_blast2(const Float:originF[3])
  10730. {
  10731.     // Smallest ring
  10732.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10733.     write_byte(TE_BEAMCYLINDER) // TE id
  10734.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10735.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10736.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10737.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10738.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10739.     engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
  10740.     write_short(g_exploSpr) // sprite
  10741.     write_byte(0) // startframe
  10742.     write_byte(0) // framerate
  10743.     write_byte(4) // life
  10744.     write_byte(60) // width
  10745.     write_byte(0) // noise
  10746.     write_byte(200) // red
  10747.     write_byte(100) // green
  10748.     write_byte(0) // blue
  10749.     write_byte(200) // brightness
  10750.     write_byte(0) // speed
  10751.     message_end()
  10752.    
  10753.     // Medium ring
  10754.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10755.     write_byte(TE_BEAMCYLINDER) // TE id
  10756.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10757.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10758.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10759.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10760.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10761.     engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
  10762.     write_short(g_exploSpr) // sprite
  10763.     write_byte(0) // startframe
  10764.     write_byte(0) // framerate
  10765.     write_byte(4) // life
  10766.     write_byte(60) // width
  10767.     write_byte(0) // noise
  10768.     write_byte(200) // red
  10769.     write_byte(50) // green
  10770.     write_byte(0) // blue
  10771.     write_byte(200) // brightness
  10772.     write_byte(0) // speed
  10773.     message_end()
  10774.    
  10775.     // Largest ring
  10776.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10777.     write_byte(TE_BEAMCYLINDER) // TE id
  10778.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10779.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10780.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10781.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10782.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10783.     engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
  10784.     write_short(g_exploSpr) // sprite
  10785.     write_byte(0) // startframe
  10786.     write_byte(0) // framerate
  10787.     write_byte(4) // life
  10788.     write_byte(60) // width
  10789.     write_byte(0) // noise
  10790.     write_byte(200) // red
  10791.     write_byte(0) // green
  10792.     write_byte(0) // blue
  10793.     write_byte(200) // brightness
  10794.     write_byte(0) // speed
  10795.     message_end()
  10796. }
  10797.  
  10798. // Frost Grenade: Freeze Blast
  10799. create_blast3(const Float:originF[3])
  10800. {
  10801.     // Smallest ring
  10802.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10803.     write_byte(TE_BEAMCYLINDER) // TE id
  10804.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10805.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10806.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10807.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10808.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10809.     engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
  10810.     write_short(g_exploSpr) // sprite
  10811.     write_byte(0) // startframe
  10812.     write_byte(0) // framerate
  10813.     write_byte(4) // life
  10814.     write_byte(60) // width
  10815.     write_byte(0) // noise
  10816.     write_byte(0) // red
  10817.     write_byte(100) // green
  10818.     write_byte(200) // blue
  10819.     write_byte(200) // brightness
  10820.     write_byte(0) // speed
  10821.     message_end()
  10822.    
  10823.     // Medium ring
  10824.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10825.     write_byte(TE_BEAMCYLINDER) // TE id
  10826.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10827.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10828.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10829.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10830.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10831.     engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
  10832.     write_short(g_exploSpr) // sprite
  10833.     write_byte(0) // startframe
  10834.     write_byte(0) // framerate
  10835.     write_byte(4) // life
  10836.     write_byte(60) // width
  10837.     write_byte(0) // noise
  10838.     write_byte(0) // red
  10839.     write_byte(100) // green
  10840.     write_byte(200) // blue
  10841.     write_byte(200) // brightness
  10842.     write_byte(0) // speed
  10843.     message_end()
  10844.    
  10845.     // Largest ring
  10846.     engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
  10847.     write_byte(TE_BEAMCYLINDER) // TE id
  10848.     engfunc(EngFunc_WriteCoord, originF[0]) // x
  10849.     engfunc(EngFunc_WriteCoord, originF[1]) // y
  10850.     engfunc(EngFunc_WriteCoord, originF[2]) // z
  10851.     engfunc(EngFunc_WriteCoord, originF[0]) // x axis
  10852.     engfunc(EngFunc_WriteCoord, originF[1]) // y axis
  10853.     engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
  10854.     write_short(g_exploSpr) // sprite
  10855.     write_byte(0) // startframe
  10856.     write_byte(0) // framerate
  10857.     write_byte(4) // life
  10858.     write_byte(60) // width
  10859.     write_byte(0) // noise
  10860.     write_byte(0) // red
  10861.     write_byte(100) // green
  10862.     write_byte(200) // blue
  10863.     write_byte(200) // brightness
  10864.     write_byte(0) // speed
  10865.     message_end()
  10866. }
  10867.  
  10868. // Fix Dead Attrib on scoreboard
  10869. FixDeadAttrib(id)
  10870. {
  10871.     message_begin(MSG_BROADCAST, g_msgScoreAttrib)
  10872.     write_byte(id) // id
  10873.     write_byte(0) // attrib
  10874.     message_end()
  10875. }
  10876.  
  10877. // Send Death Message for infections
  10878. SendDeathMsg(attacker, victim)
  10879. {
  10880.     message_begin(MSG_BROADCAST, g_msgDeathMsg)
  10881.     write_byte(attacker) // killer
  10882.     write_byte(victim) // victim
  10883.     write_byte(1) // headshot flag
  10884.     write_string("infection") // killer's weapon
  10885.     message_end()
  10886. }
  10887.  
  10888. // Update Player Frags and Deaths
  10889. UpdateFrags(attacker, victim, frags, deaths, scoreboard)
  10890. {
  10891.     // Set attacker frags
  10892.     set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) + frags))
  10893.    
  10894.     // Set victim deaths
  10895.     fm_cs_set_user_deaths(victim, cs_get_user_deaths(victim) + deaths)
  10896.    
  10897.     // Update scoreboard with attacker and victim info
  10898.     if (scoreboard)
  10899.     {
  10900.         message_begin(MSG_BROADCAST, g_msgScoreInfo)
  10901.         write_byte(attacker) // id
  10902.         write_short(pev(attacker, pev_frags)) // frags
  10903.         write_short(cs_get_user_deaths(attacker)) // deaths
  10904.         write_short(0) // class?
  10905.         write_short(fm_cs_get_user_team(attacker)) // team
  10906.         message_end()
  10907.        
  10908.         message_begin(MSG_BROADCAST, g_msgScoreInfo)
  10909.         write_byte(victim) // id
  10910.         write_short(pev(victim, pev_frags)) // frags
  10911.         write_short(cs_get_user_deaths(victim)) // deaths
  10912.         write_short(0) // class?
  10913.         write_short(fm_cs_get_user_team(victim)) // team
  10914.         message_end()
  10915.     }
  10916. }
  10917.  
  10918. // Remove Player Frags (when Nemesis/Survivor ignore_frags cvar is enabled)
  10919. RemoveFrags(attacker, victim)
  10920. {
  10921.     // Remove attacker frags
  10922.     set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) - 1))
  10923.    
  10924.     // Remove victim deaths
  10925.     fm_cs_set_user_deaths(victim, cs_get_user_deaths(victim) - 1)
  10926. }
  10927.  
  10928. // Plays a sound on clients
  10929. PlaySound(const sound[])
  10930. {
  10931.     if (equal(sound[strlen(sound)-4], ".mp3"))
  10932.         client_cmd(0, "mp3 play ^"sound/%s^"", sound)
  10933.     else
  10934.         client_cmd(0, "spk ^"%s^"", sound)
  10935. }
  10936.  
  10937. // Prints a colored message to target (use 0 for everyone), supports ML formatting.
  10938. // Note: I still need to make something like gungame's LANG_PLAYER_C to avoid unintended
  10939. // argument replacement when a function passes -1 (it will be considered a LANG_PLAYER)
  10940. zp_colored_print(target, const message[], any:...)
  10941. {
  10942.     static buffer[512], i, argscount
  10943.     argscount = numargs()
  10944.    
  10945.     // Send to everyone
  10946.     if (!target)
  10947.     {
  10948.         static player
  10949.         for (player = 1; player <= g_maxplayers; player++)
  10950.         {
  10951.             // Not connected
  10952.             if (!g_isconnected[player])
  10953.                 continue;
  10954.            
  10955.             // Remember changed arguments
  10956.             static changed[5], changedcount // [5] = max LANG_PLAYER occurencies
  10957.             changedcount = 0
  10958.            
  10959.             // Replace LANG_PLAYER with player id
  10960.             for (i = 2; i < argscount; i++)
  10961.             {
  10962.                 if (getarg(i) == LANG_PLAYER)
  10963.                 {
  10964.                     setarg(i, 0, player)
  10965.                     changed[changedcount] = i
  10966.                     changedcount++
  10967.                 }
  10968.             }
  10969.            
  10970.             // Format message for player
  10971.             vformat(buffer, charsmax(buffer), message, 3)
  10972.            
  10973.             // Send it
  10974.             message_begin(MSG_ONE_UNRELIABLE, g_msgSayText, _, player)
  10975.             write_byte(player)
  10976.             write_string(buffer)
  10977.             message_end()
  10978.            
  10979.             // Replace back player id's with LANG_PLAYER
  10980.             for (i = 0; i < changedcount; i++)
  10981.                 setarg(changed[i], 0, LANG_PLAYER)
  10982.         }
  10983.     }
  10984.     // Send to specific target
  10985.     else
  10986.     {
  10987.         /*
  10988.         // Not needed since you should set the ML argument
  10989.         // to the player's id for a targeted print message
  10990.        
  10991.         // Replace LANG_PLAYER with player id
  10992.         for (i = 2; i < argscount; i++)
  10993.         {
  10994.             if (getarg(i) == LANG_PLAYER)
  10995.                 setarg(i, 0, target)
  10996.         }
  10997.         */
  10998.        
  10999.         // Format message for player
  11000.         vformat(buffer, charsmax(buffer), message, 3)
  11001.        
  11002.         // Send it
  11003.         message_begin(MSG_ONE, g_msgSayText, _, target)
  11004.         write_byte(target)
  11005.         write_string(buffer)
  11006.         message_end()
  11007.     }
  11008. }
  11009.  
  11010. /*================================================================================
  11011.  [Stocks]
  11012. =================================================================================*/
  11013.  
  11014. // Set an entity's key value (from fakemeta_util)
  11015. stock fm_set_kvd(entity, const key[], const value[], const classname[])
  11016. {
  11017.     set_kvd(0, KV_ClassName, classname)
  11018.     set_kvd(0, KV_KeyName, key)
  11019.     set_kvd(0, KV_Value, value)
  11020.     set_kvd(0, KV_fHandled, 0)
  11021.  
  11022.     dllfunc(DLLFunc_KeyValue, entity, 0)
  11023. }
  11024.  
  11025. // Set entity's rendering type (from fakemeta_util)
  11026. stock fm_set_rendering(entity, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16)
  11027. {
  11028.     static Float:color[3]
  11029.     color[0] = float(r)
  11030.     color[1] = float(g)
  11031.     color[2] = float(b)
  11032.    
  11033.     set_pev(entity, pev_renderfx, fx)
  11034.     set_pev(entity, pev_rendercolor, color)
  11035.     set_pev(entity, pev_rendermode, render)
  11036.     set_pev(entity, pev_renderamt, float(amount))
  11037. }
  11038.  
  11039. // Get entity's speed (from fakemeta_util)
  11040. stock fm_get_speed(entity)
  11041. {
  11042.     static Float:velocity[3]
  11043.     pev(entity, pev_velocity, velocity)
  11044.    
  11045.     return floatround(vector_length(velocity));
  11046. }
  11047.  
  11048. // Get entity's aim origins (from fakemeta_util)
  11049. stock fm_get_aim_origin(id, Float:origin[3])
  11050. {
  11051.     static Float:origin1F[3], Float:origin2F[3]
  11052.     pev(id, pev_origin, origin1F)
  11053.     pev(id, pev_view_ofs, origin2F)
  11054.     xs_vec_add(origin1F, origin2F, origin1F)
  11055.  
  11056.     pev(id, pev_v_angle, origin2F);
  11057.     engfunc(EngFunc_MakeVectors, origin2F)
  11058.     global_get(glb_v_forward, origin2F)
  11059.     xs_vec_mul_scalar(origin2F, 9999.0, origin2F)
  11060.     xs_vec_add(origin1F, origin2F, origin2F)
  11061.  
  11062.     engfunc(EngFunc_TraceLine, origin1F, origin2F, 0, id, 0)
  11063.     get_tr2(0, TR_vecEndPos, origin)
  11064. }
  11065.  
  11066. // Find entity by its owner (from fakemeta_util)
  11067. stock fm_find_ent_by_owner(entity, const classname[], owner)
  11068. {
  11069.     while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", classname)) && pev(entity, pev_owner) != owner) { /* keep looping */ }
  11070.     return entity;
  11071. }
  11072.  
  11073. // Set player's health (from fakemeta_util)
  11074. stock fm_set_user_health(id, health)
  11075. {
  11076.     (health > 0) ? set_pev(id, pev_health, float(health)) : dllfunc(DLLFunc_ClientKill, id);
  11077. }
  11078.  
  11079. // Give an item to a player (from fakemeta_util)
  11080. stock fm_give_item(id, const item[])
  11081. {
  11082.     static ent
  11083.     ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, item))
  11084.     if (!pev_valid(ent)) return;
  11085.    
  11086.     static Float:originF[3]
  11087.     pev(id, pev_origin, originF)
  11088.     set_pev(ent, pev_origin, originF)
  11089.     set_pev(ent, pev_spawnflags, pev(ent, pev_spawnflags) | SF_NORESPAWN)
  11090.     dllfunc(DLLFunc_Spawn, ent)
  11091.    
  11092.     static save
  11093.     save = pev(ent, pev_solid)
  11094.     dllfunc(DLLFunc_Touch, ent, id)
  11095.     if (pev(ent, pev_solid) != save)
  11096.         return;
  11097.    
  11098.     engfunc(EngFunc_RemoveEntity, ent)
  11099. }
  11100.  
  11101. // Strip user weapons (from fakemeta_util)
  11102. stock fm_strip_user_weapons(id)
  11103. {
  11104.     static ent
  11105.     ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "player_weaponstrip"))
  11106.     if (!pev_valid(ent)) return;
  11107.    
  11108.     dllfunc(DLLFunc_Spawn, ent)
  11109.     dllfunc(DLLFunc_Use, ent, id)
  11110.     engfunc(EngFunc_RemoveEntity, ent)
  11111. }
  11112.  
  11113. // Collect random spawn points
  11114. stock load_spawns()
  11115. {
  11116.     // Check for CSDM spawns of the current map
  11117.     new cfgdir[32], mapname[32], filepath[100], linedata[64]
  11118.     get_configsdir(cfgdir, charsmax(cfgdir))
  11119.     get_mapname(mapname, charsmax(mapname))
  11120.     formatex(filepath, charsmax(filepath), "%s/csdm/%s.spawns.cfg", cfgdir, mapname)
  11121.    
  11122.     // Load CSDM spawns if present
  11123.     if (file_exists(filepath))
  11124.     {
  11125.         new csdmdata[10][6], file = fopen(filepath,"rt")
  11126.        
  11127.         while (file && !feof(file))
  11128.         {
  11129.             fgets(file, linedata, charsmax(linedata))
  11130.            
  11131.             // invalid spawn
  11132.             if(!linedata[0] || str_count(linedata,' ') < 2) continue;
  11133.            
  11134.             // get spawn point data
  11135.             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)
  11136.            
  11137.             // origin
  11138.             g_spawns[g_spawnCount][0] = floatstr(csdmdata[0])
  11139.             g_spawns[g_spawnCount][1] = floatstr(csdmdata[1])
  11140.             g_spawns[g_spawnCount][2] = floatstr(csdmdata[2])
  11141.            
  11142.             // increase spawn count
  11143.             g_spawnCount++
  11144.             if (g_spawnCount >= sizeof g_spawns) break;
  11145.         }
  11146.         if (file) fclose(file)
  11147.     }
  11148.     else
  11149.     {
  11150.         // Collect regular spawns
  11151.         collect_spawns_ent("info_player_start")
  11152.         collect_spawns_ent("info_player_deathmatch")
  11153.     }
  11154.    
  11155.     // Collect regular spawns for non-random spawning unstuck
  11156.     collect_spawns_ent2("info_player_start")
  11157.     collect_spawns_ent2("info_player_deathmatch")
  11158. }
  11159.  
  11160. // Collect spawn points from entity origins
  11161. stock collect_spawns_ent(const classname[])
  11162. {
  11163.     new ent = -1
  11164.     while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", classname)) != 0)
  11165.     {
  11166.         // get origin
  11167.         new Float:originF[3]
  11168.         pev(ent, pev_origin, originF)
  11169.         g_spawns[g_spawnCount][0] = originF[0]
  11170.         g_spawns[g_spawnCount][1] = originF[1]
  11171.         g_spawns[g_spawnCount][2] = originF[2]
  11172.        
  11173.         // increase spawn count
  11174.         g_spawnCount++
  11175.         if (g_spawnCount >= sizeof g_spawns) break;
  11176.     }
  11177. }
  11178.  
  11179. // Collect spawn points from entity origins
  11180. stock collect_spawns_ent2(const classname[])
  11181. {
  11182.     new ent = -1
  11183.     while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", classname)) != 0)
  11184.     {
  11185.         // get origin
  11186.         new Float:originF[3]
  11187.         pev(ent, pev_origin, originF)
  11188.         g_spawns2[g_spawnCount2][0] = originF[0]
  11189.         g_spawns2[g_spawnCount2][1] = originF[1]
  11190.         g_spawns2[g_spawnCount2][2] = originF[2]
  11191.        
  11192.         // increase spawn count
  11193.         g_spawnCount2++
  11194.         if (g_spawnCount2 >= sizeof g_spawns2) break;
  11195.     }
  11196. }
  11197.  
  11198. // Drop primary/secondary weapons
  11199. stock drop_weapons(id, dropwhat)
  11200. {
  11201.     // Get user weapons
  11202.     static weapons[32], num, i, weaponid
  11203.     num = 0 // reset passed weapons count (bugfix)
  11204.     get_user_weapons(id, weapons, num)
  11205.    
  11206.     // Loop through them and drop primaries or secondaries
  11207.     for (i = 0; i < num; i++)
  11208.     {
  11209.         // Prevent re-indexing the array
  11210.         weaponid = weapons[i]
  11211.        
  11212.         if ((dropwhat == 1 && ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)) || (dropwhat == 2 && ((1<<weaponid) & SECONDARY_WEAPONS_BIT_SUM)))
  11213.         {
  11214.             // Get weapon entity
  11215.             static wname[32], weapon_ent
  11216.             get_weaponname(weaponid, wname, charsmax(wname))
  11217.             weapon_ent = fm_find_ent_by_owner(-1, wname, id)
  11218.            
  11219.             // Hack: store weapon bpammo on PEV_ADDITIONAL_AMMO
  11220.             set_pev(weapon_ent, PEV_ADDITIONAL_AMMO, cs_get_user_bpammo(id, weaponid))
  11221.            
  11222.             // Player drops the weapon and looses his bpammo
  11223.             engclient_cmd(id, "drop", wname)
  11224.             cs_set_user_bpammo(id, weaponid, 0)
  11225.         }
  11226.     }
  11227. }
  11228.  
  11229. // Stock by (probably) Twilight Suzuka -counts number of chars in a string
  11230. stock str_count(const str[], searchchar)
  11231. {
  11232.     new count, i, len = strlen(str)
  11233.    
  11234.     for (i = 0; i <= len; i++)
  11235.     {
  11236.         if(str[i] == searchchar)
  11237.             count++
  11238.     }
  11239.    
  11240.     return count;
  11241. }
  11242.  
  11243. // Checks if a space is vacant (credits to VEN)
  11244. stock is_hull_vacant(Float:origin[3], hull)
  11245. {
  11246.     engfunc(EngFunc_TraceHull, origin, origin, 0, hull, 0, 0)
  11247.    
  11248.     if (!get_tr2(0, TR_StartSolid) && !get_tr2(0, TR_AllSolid) && get_tr2(0, TR_InOpen))
  11249.         return true;
  11250.    
  11251.     return false;
  11252. }
  11253.  
  11254. // Check if a player is stuck (credits to VEN)
  11255. stock is_player_stuck(id)
  11256. {
  11257.     static Float:originF[3]
  11258.     pev(id, pev_origin, originF)
  11259.    
  11260.     engfunc(EngFunc_TraceHull, originF, originF, 0, (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN, id, 0)
  11261.    
  11262.     if (get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen))
  11263.         return true;
  11264.    
  11265.     return false;
  11266. }
  11267.  
  11268. // Simplified get_weaponid (CS only)
  11269. stock cs_weapon_name_to_id(const weapon[])
  11270. {
  11271.     static i
  11272.     for (i = 0; i < sizeof WEAPONENTNAMES; i++)
  11273.     {
  11274.         if (equal(weapon, WEAPONENTNAMES[i]))
  11275.             return i;
  11276.     }
  11277.    
  11278.     return 0;
  11279. }
  11280.  
  11281. // Get User Current Weapon Entity
  11282. stock fm_cs_get_current_weapon_ent(id)
  11283. {
  11284.     // Prevent server crash if entity's private data not initalized
  11285.     if (pev_valid(id) != PDATA_SAFE)
  11286.         return -1;
  11287.    
  11288.     return get_pdata_cbase(id, OFFSET_ACTIVE_ITEM, OFFSET_LINUX);
  11289. }
  11290.  
  11291. // Get Weapon Entity's Owner
  11292. stock fm_cs_get_weapon_ent_owner(ent)
  11293. {
  11294.     // Prevent server crash if entity's private data not initalized
  11295.     if (pev_valid(ent) != PDATA_SAFE)
  11296.         return -1;
  11297.    
  11298.     return get_pdata_cbase(ent, OFFSET_WEAPONOWNER, OFFSET_LINUX_WEAPONS);
  11299. }
  11300.  
  11301. // Set User Deaths
  11302. stock fm_cs_set_user_deaths(id, value)
  11303. {
  11304.     // Prevent server crash if entity's private data not initalized
  11305.     if (pev_valid(id) != PDATA_SAFE)
  11306.         return;
  11307.    
  11308.     set_pdata_int(id, OFFSET_CSDEATHS, value, OFFSET_LINUX)
  11309. }
  11310.  
  11311. // Get User Team
  11312. stock fm_cs_get_user_team(id)
  11313. {
  11314.     // Prevent server crash if entity's private data not initalized
  11315.     if (pev_valid(id) != PDATA_SAFE)
  11316.         return FM_CS_TEAM_UNASSIGNED;
  11317.    
  11318.     return get_pdata_int(id, OFFSET_CSTEAMS, OFFSET_LINUX);
  11319. }
  11320.  
  11321. // Set a Player's Team
  11322. stock fm_cs_set_user_team(id, team)
  11323. {
  11324.     // Prevent server crash if entity's private data not initalized
  11325.     if (pev_valid(id) != PDATA_SAFE)
  11326.         return;
  11327.    
  11328.     set_pdata_int(id, OFFSET_CSTEAMS, team, OFFSET_LINUX)
  11329. }
  11330.  
  11331. // Set User Money
  11332. stock fm_cs_set_user_money(id, value)
  11333. {
  11334.     // Prevent server crash if entity's private data not initalized
  11335.     if (pev_valid(id) != PDATA_SAFE)
  11336.         return;
  11337.    
  11338.     set_pdata_int(id, OFFSET_CSMONEY, value, OFFSET_LINUX)
  11339. }
  11340.  
  11341. // Set User Flashlight Batteries
  11342. stock fm_cs_set_user_batteries(id, value)
  11343. {
  11344.     // Prevent server crash if entity's private data not initalized
  11345.     if (pev_valid(id) != PDATA_SAFE)
  11346.         return;
  11347.    
  11348.     set_pdata_int(id, OFFSET_FLASHLIGHT_BATTERY, value, OFFSET_LINUX)
  11349. }
  11350.  
  11351. // Update Player's Team on all clients (adding needed delays)
  11352. stock fm_user_team_update(id)
  11353. {
  11354.     static Float:current_time
  11355.     current_time = get_gametime()
  11356.    
  11357.     if (current_time - g_teams_targettime >= 0.1)
  11358.     {
  11359.         set_task(0.1, "fm_cs_set_user_team_msg", id+TASK_TEAM)
  11360.         g_teams_targettime = current_time + 0.1
  11361.     }
  11362.     else
  11363.     {
  11364.         set_task((g_teams_targettime + 0.1) - current_time, "fm_cs_set_user_team_msg", id+TASK_TEAM)
  11365.         g_teams_targettime = g_teams_targettime + 0.1
  11366.     }
  11367. }
  11368.  
  11369. // Send User Team Message
  11370. public fm_cs_set_user_team_msg(taskid)
  11371. {
  11372.     // Note to self: this next message can now be received by other plugins
  11373.    
  11374.     // Set the switching team flag
  11375.     g_switchingteam = true
  11376.    
  11377.     // Tell everyone my new team
  11378.     emessage_begin(MSG_ALL, g_msgTeamInfo)
  11379.     ewrite_byte(ID_TEAM) // player
  11380.     ewrite_string(CS_TEAM_NAMES[fm_cs_get_user_team(ID_TEAM)]) // team
  11381.     emessage_end()
  11382.    
  11383.     // Done switching team
  11384.     g_switchingteam = false
  11385. }
  11386.  
  11387. // Set the precached model index (updates hitboxes server side)
  11388. stock fm_cs_set_user_model_index(id, value)
  11389. {
  11390.     // Prevent server crash if entity's private data not initalized
  11391.     if (pev_valid(id) != PDATA_SAFE)
  11392.         return;
  11393.    
  11394.     set_pdata_int(id, OFFSET_MODELINDEX, value, OFFSET_LINUX)
  11395. }
  11396.  
  11397. // Set Player Model on Entity
  11398. stock fm_set_playermodel_ent(id)
  11399. {
  11400.     // Make original player entity invisible without hiding shadows or firing effects
  11401.     fm_set_rendering(id, kRenderFxNone, 255, 255, 255, kRenderTransTexture, 1)
  11402.    
  11403.     // Format model string
  11404.     static model[100]
  11405.     formatex(model, charsmax(model), "models/player/%s/%s.mdl", g_playermodel[id], g_playermodel[id])
  11406.    
  11407.     // Set model on entity or make a new one if unexistant
  11408.     if (!pev_valid(g_ent_playermodel[id]))
  11409.     {
  11410.         g_ent_playermodel[id] = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
  11411.         if (!pev_valid(g_ent_playermodel[id])) return;
  11412.        
  11413.         set_pev(g_ent_playermodel[id], pev_classname, MODEL_ENT_CLASSNAME)
  11414.         set_pev(g_ent_playermodel[id], pev_movetype, MOVETYPE_FOLLOW)
  11415.         set_pev(g_ent_playermodel[id], pev_aiment, id)
  11416.         set_pev(g_ent_playermodel[id], pev_owner, id)
  11417.     }
  11418.    
  11419.     engfunc(EngFunc_SetModel, g_ent_playermodel[id], model)
  11420. }
  11421.  
  11422. // Set Weapon Model on Entity
  11423. stock fm_set_weaponmodel_ent(id)
  11424. {
  11425.     // Get player's p_ weapon model
  11426.     static model[100]
  11427.     pev(id, pev_weaponmodel2, model, charsmax(model))
  11428.    
  11429.     // Set model on entity or make a new one if unexistant
  11430.     if (!pev_valid(g_ent_weaponmodel[id]))
  11431.     {
  11432.         g_ent_weaponmodel[id] = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
  11433.         if (!pev_valid(g_ent_weaponmodel[id])) return;
  11434.        
  11435.         set_pev(g_ent_weaponmodel[id], pev_classname, WEAPON_ENT_CLASSNAME)
  11436.         set_pev(g_ent_weaponmodel[id], pev_movetype, MOVETYPE_FOLLOW)
  11437.         set_pev(g_ent_weaponmodel[id], pev_aiment, id)
  11438.         set_pev(g_ent_weaponmodel[id], pev_owner, id)
  11439.     }
  11440.    
  11441.     engfunc(EngFunc_SetModel, g_ent_weaponmodel[id], model)
  11442. }
  11443.  
  11444. // Remove Custom Model Entities
  11445. stock fm_remove_model_ents(id)
  11446. {
  11447.     // Remove "playermodel" ent if present
  11448.     if (pev_valid(g_ent_playermodel[id]))
  11449.     {
  11450.         engfunc(EngFunc_RemoveEntity, g_ent_playermodel[id])
  11451.         g_ent_playermodel[id] = 0
  11452.     }
  11453.     // Remove "weaponmodel" ent if present
  11454.     if (pev_valid(g_ent_weaponmodel[id]))
  11455.     {
  11456.         engfunc(EngFunc_RemoveEntity, g_ent_weaponmodel[id])
  11457.         g_ent_weaponmodel[id] = 0
  11458.     }
  11459. }
  11460.  
  11461. // Set User Model
  11462. public fm_cs_set_user_model(taskid)
  11463. {
  11464.     set_user_info(ID_MODEL, "model", g_playermodel[ID_MODEL])
  11465. }
  11466.  
  11467. // Get User Model -model passed byref-
  11468. stock fm_cs_get_user_model(player, model[], len)
  11469. {
  11470.     get_user_info(player, "model", model, len)
  11471. }
  11472.  
  11473. // Update Player's Model on all clients (adding needed delays)
  11474. public fm_user_model_update(taskid)
  11475. {
  11476.     static Float:current_time
  11477.     current_time = get_gametime()
  11478.    
  11479.     if (current_time - g_models_targettime >= g_modelchange_delay)
  11480.     {
  11481.         fm_cs_set_user_model(taskid)
  11482.         g_models_targettime = current_time
  11483.     }
  11484.     else
  11485.     {
  11486.         set_task((g_models_targettime + g_modelchange_delay) - current_time, "fm_cs_set_user_model", taskid)
  11487.         g_models_targettime = g_models_targettime + g_modelchange_delay
  11488.     }
  11489. }
Add Comment
Please, Sign In to add comment