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