Преработка на Nade Modes (Nomexous) v11.2

В този раздел можете да подавате всякакви заявки за намиране, изработка или преработка на плъгини/модове.
Аватар
М.А.Р.И.Х.У.А.Н.А
Извън линия
Потребител
Потребител
Мнения: 64
Регистриран на: 12 Дек 2016, 19:49

Преработка на Nade Modes (Nomexous) v11.2

Мнение от М.А.Р.И.Х.У.А.Н.А » 17 Апр 2018, 14:03

Какво да се премахне :

Да не премахнат всички модове, без trip granades / trip lazer.

Какво да се промени на trip granades / trip lazer:

Да се задейства само и единствено от противник

Какво да се промени на HE граната:

След като противника мине през лазера бомбата да не избухва а да го подпалва ЦЪК!

Какво да се промени при Flash гранатата;

След като противника мине през лазер гранатата да го замразява ЦЪК!

Код за потвърждение: Избери целия код

#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <engine>
#include <fakemeta>
#include <hamsandwich>
#include <xs>

#define VERSION "9.61"

/* -------------------------------
[Plugin Link]
------------------------------- */
/*
 *  https://forums.alliedmods.net/showthread.php?t=75322&page=21
 */

/* -------------------------------
[Changelog]
------------------------------- */
/*
Version 3.0
- Initial release.

Version 3.1
- Changing an item on the second page will rebuild the menu and display on the second page.

Version 4
- Improve to the trip grenade and sounds

Version 5
- Full grenade support + satchel charge mode

Version 5.2
- Automatic save system + team bug fix

Version 5.5
- Nade choose system

Version 5.7
- New menu system

Version 5.8
- Added compatibility with Biohazzard/Zombie Plague Mod. The nades will be removed when a player is turned into a zombie

Version 5.9
- Added new cvar for teamplay the plugin won't follow friendlyfire anymore, bot support

Version 5.9b
- Bug fix -> zombie

Version 6.0
- Nade damage control (all of them)

Version 6.0b
- Nademodes invalid player bug fix + admin spectator bug fix

Version 6.0c
- Nademodes grenade disapearing bug fix + new feature the plugin can be seen on what servers is played on.

Version 7.0
- Nademodes limit added, now plugin works with ghw model change, CSX module removed + laser engine bug fix + less cpu usage

Version 7.0a
- Nademodes invalid entity bug fix, nademodes remove counter bug fix

Version 7.0aa 
- Nademodes invalid entity bug fix in play_sound 

Version 7.0b
- Nademodes code change, now plugin relies on more modules! (More efficient), change part of the code (no more hardcodes)

Version 7.5
- Nademodes smart plugin effects mode added! Changed damage system! Changed primary menu! Now we have stuff organised! Added Homing grenade!

Version 8.0
- Nademodes added hit points system! Made sec explo more customizable!

Version 8.5
- Fixed all known bugs, added client mode selection!

Version 8.6
- Fixed menu drunk cvar bug, and forward drunk bug

Version 8.7
- Added new cvar to fix the SVC_BAD errors -> use this only if the clients report that problem!!!

Version 8.8
- New grenade shot detection method (supports walls now), HP system for other nades modes (NORMAL,IMPACT,HOMING)

Version 8.9
- Added bot support for trip nades

Version 9.0
- Animation and sound for grenades that have been shot, effects when grenades desintegrate, hp system more configurable

Version 9.1
- Shot method a little different now, supports shot through all entities, added penetration

Version 9.2
- Fixed the smoke grenade block problem, fixed secondary explosions server crash

Version 9.3
- Some small code tweaks, made some predefined values for things that you would like to modify

Version 9.4
- Last adjustments

Version 9.5
- Final fixes and some security mesures, final suggestions, removed update owner cvar (unfortunately nothing else could have been done)

Version 9.6
- Team bug fix, Owner set bug fix, Homing now follows team play, Damage system bug fix 

Version 9.61
- Small unregistration bug fix!
*/


/* -------------------------------
[Thanks to]
------------------------------- */
/*
- Grenade Modes by Nomexous
- Shoot Grenades by joaquimandrade
- Testers
- Translators
- Everyone who enjoys having fun with grenades.
*/

new const ACTIVATE[] = 	"weapons/mine_activate.wav"
new const DEPLOY[] =  	"weapons/mine_deploy.wav"
new const CHARGE[] =  	"weapons/mine_charge.wav"
new const GEIGER[] =  	"player/geiger1.wav"
new const PING[] = 		"turret/tu_ping.wav"

new const SOUND_HIT[5][] = { "debris/bustmetal1.wav", "debris/bustmetal2.wav", "debris/metal1.wav", "debris/metal2.wav", "debris/metal3.wav" }

// Defines that can be modified
#define MAX_PLAYERS						32

#define ADMIN_ACCESS					ADMIN_RCON

#define NOTEAM_RGB_R_COLOR 				0
#define NOTEAM_RGB_G_COLOR 				214
#define NOTEAM_RGB_B_COLOR 				198

#define TEAMCT_RGB_R_COLOR				0
#define TEAMCT_RGB_G_COLOR				0
#define TEAMCT_RGB_B_COLOR				255

#define TEAMTE_RGB_R_COLOR				255
#define TEAMTE_RGB_G_COLOR				0
#define TEAMTE_RGB_B_COLOR				0

// Some defines, I suggest not modifying these! Only if you understand the code completely!
#define RING_SIZE_CONSTANT_PROXIMITY 	2.1
#define RING_SIZE_CONSTANT_MOTION	 	9.27

#define SETTINGS_REFRESH_TIME			2.0

#define OFFSET_WEAPONID					43
#define EXTRAOFFSET_WEAPONS				4

#define SMART_RADIUS_RING_SHOW			1500.0
#define CONE_DROP_ANGLE_COSINUS			-0.30
#define EXTRALENGTH_VECTOR				500.0

#define SHOT_PENETRATION_DISTANCE 		4.0
#define SHOT_PENETRATION_READD_TIMES	20
#define SHOT_SECOND_TEST_RADIUS			10.0
#define SHOT_KNIFE_REAL_RADIUS			6.0
#define SHOT_ENTITY_QUEUE_LENGTH		5

#define BOT_MIN_DISTANCE_ATTACH			400.0
#define BOT_WALL_MIN_COSINUS			0.866026
#define BOT_MIN_HEIGHT_ALLOW 			18.0
#define BOT_MIN_CROUCH_HEIGHT_ALLOW 	10.0
#define BOT_MAX_HEIGHT_ALLOW 			55.0
#define BOT_FORCE_CROUCH_HEIGHT_CONST	76.0

#define CVAR_STRING_ALLOC				90
#define CVAR_MAX_ASSIGNED_VALUES		30
#define CVAR_MAX_STRING_LENGTH			10

#define DMG_CS_KNIFE_BULLETS 			(1 << 12 | 1 << 0)

// Macros, made specially to make the code easier to read
#define get_option_true(%1) 					get_pcvar_num(pcvars[%1])
#define toggle_option(%1)						set_pcvar_num(pcvars[%1], !get_pcvar_num(pcvars[%1]))
#define get_option_float(%1)					get_pcvar_float(pcvars[%1])
#define set_option_float(%1,%2)					set_pcvar_float(pcvars[%1], %2)

#define make_explode(%1) 						entity_set_float(%1, EV_FL_dmgtime, 0.0)
#define grenade_can_be_used(%1)					(get_option(OPTION_NADES_IN_EFFECT) & NADE_BIT[%1]) ? 1 : 0
#define allow_grenade_explode(%1)				(get_gametime() < entity_get_float(%1, EV_FL_fuser2)) ? 0 : 1
#define get_grenade_type(%1)					NadeType:entity_get_int(%1, EV_INT_iuser1)
#define set_grenade_allow_explode(%1,%2)		entity_set_float(%1, EV_FL_fuser2, get_gametime() + %2)
#define delay_explosion(%1)						entity_set_float(%1, EV_FL_dmgtime, get_gametime() + get_option_float(OPTION_EXPLOSION_DELAY_TIME))
#define get_trip_grenade_end_origin(%1,%2)		entity_get_vector(%1, EV_VEC_vuser1, %2)
#define set_trip_grenade_end_origin(%1,%2)		entity_set_vector(%1, EV_VEC_vuser1, %2)
#define set_trip_grenade_fly_velocity(%1,%2)	entity_set_vector(%1, EV_VEC_vuser2, %2)
#define get_trip_grenade_fly_velocity(%1,%2)	entity_get_vector(%1, EV_VEC_vuser2, %2)
#define get_trip_grenade_middle_origin(%1,%2)	entity_get_vector(%1, EV_VEC_vuser3, %2)
#define set_trip_grenade_middle_origin(%1,%2)	entity_set_vector(%1, EV_VEC_vuser3, %2)
#define get_trip_grenade_arm_time(%1)			entity_get_float(%1, EV_FL_fuser1)
#define set_trip_grenade_arm_time(%1,%2)		entity_set_float(%1, EV_FL_fuser1, get_gametime() + %2)
#define set_trip_grenade_attached_to(%1,%2) 	entity_set_int(%1, EV_INT_iuser4, %2)
#define get_trip_grenade_attached_to(%1) 		entity_get_int(%1, EV_INT_iuser4)
#define get_trip_grenade_mode(%1) 				TripNadeMode:entity_get_int(%1, EV_INT_iuser3)
#define set_trip_grenade_mode(%1,%2) 			entity_set_int(%1, EV_INT_iuser3, _:%2)
#define play_sound(%1,%2) 						(get_option(OPTION_PLAY_SOUNDS)) ? emit_sound(%1, CHAN_WEAPON, %2, 1.0, ATTN_STATIC, 0, PITCH_NORM) : 0
#define play_sound2(%1,%2) 						(get_option(OPTION_PLAY_SOUNDS)) ? emit_sound(%1, CHAN_ITEM, %2, 1.0, ATTN_STATIC, 0, PITCH_NORM) : 0
#define angle_fraction_by_distance(%1)			floatcos( ( 15000.0 / floatpower( %1, 0.8 ) ), degrees )

// Enums! First time I've ever used them. These should make the code infinitely easier to read.
enum NadeRace
{
	GRENADE_EXPLOSIVE = 0,
	GRENADE_FLASHBANG,
	GRENADE_SMOKEGREN,
}

new const NADE_MODEL[][] = 
{
	"w_hegrenade.mdl", 
	"w_flashbang.mdl", 
	"w_smokegrenade.mdl"
}

new const NADE_NAME[NadeRace][] = 
{
	"He Grenade", 
	"Flashbang", 
	"Smoke Grenade"
}

new const NADE_SETINFO[NadeRace][] =
{
	"_ndmh",
	"_ndmf",
	"_ndms"
}

new const NADE_WPID[NadeRace] = 
{
	CSW_HEGRENADE, 
	CSW_FLASHBANG, 
	CSW_SMOKEGRENADE
}

new const NADE_BIT[NadeRace] =
{
	(1<<0), 
	(1<<1), 
	(1<<2)
}

enum NadeType
{
	NADE_DUD = -1,  
	NADE_NORMAL, 
	NADE_PROXIMITY, 
	NADE_IMPACT, 
	NADE_TRIP, 
	NADE_MOTION, 
	NADE_SATCHEL, 
	NADE_HOMING
}

new UNCOUNTABLE_NADE_MODES 		=	((1 << (_:NADE_DUD + 1)) | (1 << (_:NADE_NORMAL + 1)) | (1 << (_:NADE_IMPACT + 1)) | (1 << (_:NADE_HOMING + 1)))
new SETTINGS_BITSUM 			=	((1 << (_:NADE_PROXIMITY - 1)) | (1 << (_:NADE_IMPACT - 1)) | (1 << (_:NADE_TRIP - 1)) | (1 << (_:NADE_MOTION - 1)) | (1 << (_:NADE_SATCHEL - 1)) | (1 << (_:NADE_HOMING - 1)))

new const NADE_DONT_COUNT 		= (1<<31)

enum Fward
{
	FWD_NONE_ACTIVE 	= 0, 
	FWD_CMDSTART  		= (1<<0), 
	FWD_THINK   		= (1<<1), 
	FWD_SETMODEL  	 	= (1<<2), 
	FWD_TOUCH    		= (1<<3),
	FWD_SEC_EXPLODE 	= (1<<4), 
	FWD_TAKEDAMAGE		= (1<<5), 
	FWD_THINK_POST 		= (1<<6), 
	FWD_MESSAGE 		= (1<<7),
	FWD_HPSYSTEM 		= (1<<8)
}
 
enum TripNadeMode
{
	TRIP_NOT_ATTACHED = 0, 
	TRIP_ATTACHED, 
	TRIP_WAITING, 
	TRIP_SCANNING, 
	TRIP_SHOULD_DETONATE, 
	TRIP_DETONATED
}

enum Option
{
	// Primary Off/On cvar
	OPTION_ENABLE_NADE_MODES, 
	
	// General settings
	OPTION_FRIENDLY_FIRE,
	OPTION_BOT_ALLOW, 
	OPTION_NADES_IN_EFFECT, 
	OPTION_SUPPRESS_FITH, 
	OPTION_DISPLAY_MODE_ON_DRAW, 
	OPTION_PLAY_SOUNDS, 
	OPTION_RESET_MODE_ON_THROW, 
	OPTION_RESOURCE_USE, 
	OPTION_MSG_SVC_BAD,
	OPTION_TEAM_PLAY, 
	OPTION_AFFECT_OWNER, 
	
	// Grenade modes control menu
	OPTION_PROXIMITY_ENABLED, 
	OPTION_IMPACT_ENABLED, 
	OPTION_TRIP_ENABLED, 
	OPTION_MOTION_ENABLED, 
	OPTION_SATCHEL_ENABLED, 
	OPTION_HOMING_ENABLED, 
	
	OPTION_REACT_TRIP_G, 
	OPTION_REACT_TRIP_F, 
	OPTION_REACT_TRIP_S,
	
	// Limit settings
	OPTION_LIMIT_SYSTEM,
	
	OPTION_LIMIT_PROXIMITY, 
	OPTION_LIMIT_TRIP, 
	OPTION_LIMIT_MOTION, 
	OPTION_LIMIT_SATCHEL, 
	
	OPTION_INFINITE_GRENADES, 
	OPTION_INFINITE_FLASHES, 
	OPTION_INFINITE_SMOKES, 
	
	// Hitpoints system settings
	OPTION_MATERIAL_SYSTEM,
	
	OPTION_SEC_EXPLO_AFFECT, 
	
	OPTION_HITPOINT_NORMAL,
	OPTION_HITPOINT_PROXIMITY, 
	OPTION_HITPOINT_IMPACT,
	OPTION_HITPOINT_TRIP, 
	OPTION_HITPOINT_MOTION, 
	OPTION_HITPOINT_SATCHEL, 
	OPTION_HITPOINT_HOMING,
	
	OPTION_HITPOINT_DEATH, 
	OPTION_HITPOINT_FF,
	OPTION_HITPOINT_INTER_DMG,
	
	// Damage settings
	OPTION_DAMAGE_SYSTEM,
	
	OPTION_DMG_THROUGH_WALL,
	OPTION_DMG_SELF,
	OPTION_DMG_TEAMMATES,
	
	OPTION_DMG_NORMAL,
	OPTION_DMG_PROXIMITY,
	OPTION_DMG_IMPACT, 
	OPTION_DMG_TRIP, 
	OPTION_DMG_MOTION, 
	OPTION_DMG_SATCHEL, 
	OPTION_DMG_HOMING, 
	
	// Internal functional settings
	OPTION_EXPLOSION_DELAY_TIME,
	OPTION_RADIUS_SEC_EXPLOSION,
	
	OPTION_ARM_TIME_TRIP, 
	OPTION_ARM_TIME_MOTION, 
	OPTION_ARM_TIME_SATCHEL, 
	OPTION_ARM_TIME_PROXIMITY, 
	
	OPTION_TRIP_DETECT_DISTANCE, 
	OPTION_TRIP_FLY_SPEED, 
	
	OPTION_RADIUS_PROXIMITY,
	OPTION_RADIUS_MOTION,
	
	OPTION_HOMING_SCAN_RANGE,
	OPTION_HOMING_SUPER_RANGE,
	OPTION_HOMING_EXTRATIME,
	OPTION_HOMING_SPEED_ADD
}

enum OptionType
{
	TOPTION_TOGGLE = 1, 
	TOPTION_CELL, 
	TOPTION_FLOAT,
}

new const CFG_FILE_NAME[] = "nade_modes.cfg"
new CFG_FILE[200]

new OptionType:option_type[Option]
new option_value[Option][CVAR_STRING_ALLOC]

new NadeType:mode[MAX_PLAYERS + 1][NadeRace]
new cvar_menu_pos[MAX_PLAYERS + 1]
new collection[MAX_PLAYERS + 1][NadeRace]

new cl_is_bot = 0
new cl_counter[MAX_PLAYERS + 1][NadeRace][NadeType]
new CsTeams:cl_team[MAX_PLAYERS + 1]
new cl_weapon[MAX_PLAYERS + 1]
new cl_entity_queue[MAX_PLAYERS + 1][SHOT_ENTITY_QUEUE_LENGTH]

new settingsmenu[MAX_PLAYERS + 1]
new pcvars[Option]

new beampoint
new shockwave
new nadebits

new callbacks[2]

new modetext[][] = { "Normal", "Proximity", "Impact", "Trip laser", "Motion sensor", "Satchel charge", "Homing" }

new g_maxplayers

new Fward:bs_forward_collection = FWD_NONE_ACTIVE
new g_check_hpsystem = -1
new Trie:trace_attack_reg_class


/* -------------------------------
[Plugin Start]
------------------------------- */
public plugin_precache()
{
	// Track the explosion, we regiter this here so the forward will be before all of them! It is important!
	RegisterHam(Ham_Think, "grenade", "fw_track_explosion")
	
	// Trace attack register trie
	trace_attack_reg_class = TrieCreate()
	
	// We register this here to track shots, it is also important
	register_forward(FM_Spawn, "fw_spawn", 1)
	
	beampoint = precache_model("sprites/laserbeam.spr")
	shockwave = precache_model("sprites/shockwave.spr")
	nadebits  = precache_model("models/chromegibs.mdl")
	
	precache_sound(ACTIVATE)
	precache_sound(CHARGE)
	precache_sound(DEPLOY)
	precache_sound(GEIGER)
	precache_sound(PING)
	
	for (new i=0;i<5;i++)
	{
		precache_sound(SOUND_HIT[i])
	}
}

public plugin_init()
{
	// Plugin registration (normal and net)
	register_plugin("NadeModes", VERSION, "Nomexous & OT")
	register_cvar("nademodes_version", VERSION, FCVAR_SERVER|FCVAR_SPONLY)
	
	// Commands
	register_clcmd("amx_nade_mode_menu", "conjure_menu", ADMIN_ACCESS, "Shows settings menu for grenade modes.")
	register_clcmd("amx_nmm", "conjure_menu", ADMIN_ACCESS, "Shows settings menu for grenade modes.")
	
	register_clcmd("amx_nms", "conjure_cl_menu", ADMIN_ADMIN, "Shows settings for modes for every nade! Client side enable!")
	
	register_clcmd("say /nadehelp", "conjure_help", -1, "Shows help for grenade modes.")
	register_clcmd("say_team /nadehelp", "conjure_help", -1, "Shows help for grenade modes.")
	
	// General Settings Options
	pcvars[OPTION_FRIENDLY_FIRE] = get_cvar_pointer("mp_friendlyfire")
	
	register_option(OPTION_ENABLE_NADE_MODES, "nademodes_enable", "1")
	register_option(OPTION_NADES_IN_EFFECT, "nademodes_nades_in_effect", "7", TOPTION_CELL)
	register_option(OPTION_MSG_SVC_BAD, "nademodes_svc_bad_error_fix", "0")
	
	register_option(OPTION_PLAY_SOUNDS, "nademodes_play_grenade_sounds", "1")
	register_option(OPTION_RESOURCE_USE, "nademodes_effects", "2", TOPTION_CELL)
	
	register_option(OPTION_DISPLAY_MODE_ON_DRAW, "nademodes_display_mode_on_draw", "1")
	register_option(OPTION_RESET_MODE_ON_THROW, "nademodes_reset_mode_on_throw", "0")
	register_option(OPTION_SUPPRESS_FITH, "nademodes_suppress_fire_in_the_hole", "0")
	
	register_option(OPTION_BOT_ALLOW, "nademodes_bot_support", "1")
	
	register_option(OPTION_AFFECT_OWNER, "nademodes_affect_owner", "1")
	register_option(OPTION_TEAM_PLAY, "nademodes_team_play", "1")
	
	// General Settings Option Values
	register_option_value(OPTION_RESOURCE_USE, "0;1;2")
	register_option_value(OPTION_NADES_IN_EFFECT, "0;1;2;3;4;5;6;7")
	
	// Mode Settings Options
	register_option(OPTION_PROXIMITY_ENABLED, "nademodes_proximity_enabled", "1")
	register_option(OPTION_IMPACT_ENABLED, "nademodes_impact_enabled", "1")
	register_option(OPTION_TRIP_ENABLED, "nademodes_trip_enabled", "1")
	register_option(OPTION_MOTION_ENABLED, "nademodes_motion_enabled", "1")
	register_option(OPTION_SATCHEL_ENABLED, "nademodes_satchel_enabled", "1")
	register_option(OPTION_HOMING_ENABLED, "nademodes_homing_enabled", "1")
	
	register_option(OPTION_REACT_TRIP_G, "nademodes_grenade_react", "1")
	register_option(OPTION_REACT_TRIP_F, "nademodes_flash_react", "1")
	register_option(OPTION_REACT_TRIP_S, "nademodes_smoke_react", "1")
	
	// Limit Settings Options
	register_option(OPTION_LIMIT_SYSTEM, "nademodes_limit_system", "2", TOPTION_CELL)
	register_option(OPTION_LIMIT_PROXIMITY, "nademodes_proximity_limit", "5", TOPTION_CELL)
	register_option(OPTION_LIMIT_TRIP, "nademodes_trip_limit", "5", TOPTION_CELL)
	register_option(OPTION_LIMIT_MOTION, "nademodes_motion_limit", "5", TOPTION_CELL)
	register_option(OPTION_LIMIT_SATCHEL, "nademodes_satchel_limit", "5", TOPTION_CELL)
	
	register_option(OPTION_INFINITE_GRENADES, "nademodes_infinite_grenades", "0")
	register_option(OPTION_INFINITE_FLASHES, "nademodes_infinite_flashes", "0")
	register_option(OPTION_INFINITE_SMOKES, "nademodes_infinite_smokes", "0")
	
	// Limit Settings Option Values
	register_option_value(OPTION_LIMIT_SYSTEM, "0;1;2")
	
	register_option_value(OPTION_LIMIT_PROXIMITY, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
	register_option_value(OPTION_LIMIT_TRIP, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
	register_option_value(OPTION_LIMIT_MOTION, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
	register_option_value(OPTION_LIMIT_SATCHEL, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
	
	// Hitpoint Options
	register_option(OPTION_MATERIAL_SYSTEM, "nademodes_material_system", "0", TOPTION_CELL)
	register_option(OPTION_HITPOINT_DEATH, "nademodes_grenade_death","1")
	
	register_option(OPTION_SEC_EXPLO_AFFECT, "nademodes_secondary_explosions_mode", "0")
	
	register_option(OPTION_HITPOINT_NORMAL, "nademodes_hitpoints_normal", "10", TOPTION_CELL)
	register_option(OPTION_HITPOINT_PROXIMITY, "nademodes_hitpoints_proximity", "100", TOPTION_CELL)
	register_option(OPTION_HITPOINT_IMPACT, "nademodes_hitpoints_impact", "10", TOPTION_CELL)
	register_option(OPTION_HITPOINT_TRIP, "nademodes_hitpoints_trip", "100", TOPTION_CELL)
	register_option(OPTION_HITPOINT_MOTION, "nademodes_hitpoints_motion", "100", TOPTION_CELL)
	register_option(OPTION_HITPOINT_SATCHEL, "nademodes_hitpoints_satchel", "100", TOPTION_CELL)
	register_option(OPTION_HITPOINT_HOMING, "nademodes_hitpoints_homing", "10", TOPTION_CELL)
	
	register_option(OPTION_HITPOINT_INTER_DMG, "nademodes_hitpoints_intergrenade_damage", "100", TOPTION_FLOAT)
	register_option(OPTION_HITPOINT_FF, "nademodes_hitpoints_friendlyfire_ammount", "50", TOPTION_FLOAT)
	
	// Hitpoint Options Values
	register_option_value(OPTION_MATERIAL_SYSTEM, "0;1;2")
	
	register_option_value(OPTION_HITPOINT_NORMAL, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
	register_option_value(OPTION_HITPOINT_PROXIMITY, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
	register_option_value(OPTION_HITPOINT_IMPACT, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
	register_option_value(OPTION_HITPOINT_TRIP, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
	register_option_value(OPTION_HITPOINT_MOTION, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
	register_option_value(OPTION_HITPOINT_SATCHEL, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
	register_option_value(OPTION_HITPOINT_HOMING, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
	
	register_option_value(OPTION_HITPOINT_INTER_DMG, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
	register_option_value(OPTION_HITPOINT_FF, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
	
	// Damage System Option Registration
	register_option(OPTION_DAMAGE_SYSTEM, "nademodes_damage_system", "2", TOPTION_CELL)
	
	register_option(OPTION_DMG_THROUGH_WALL, "nademodes_damage_through_wall", "50", TOPTION_CELL)
	register_option(OPTION_DMG_SELF, "nademodes_damage_self", "50", TOPTION_CELL)
	register_option(OPTION_DMG_TEAMMATES, "nademodes_damage_teammate", "50", TOPTION_CELL)
	
	register_option(OPTION_DMG_NORMAL, "nademodes_damage_normal", "1.0", TOPTION_FLOAT)
	register_option(OPTION_DMG_IMPACT, "nademodes_damage_impact", "1.0", TOPTION_FLOAT)
	register_option(OPTION_DMG_PROXIMITY, "nademodes_damage_proximity", "1.0", TOPTION_FLOAT)
	register_option(OPTION_DMG_MOTION, "nademodes_damage_motion", "1.0", TOPTION_FLOAT)
	register_option(OPTION_DMG_SATCHEL, "nademodes_damage_satchel", "1.0", TOPTION_FLOAT)
	register_option(OPTION_DMG_TRIP, "nademodes_damage_trip", "1.0", TOPTION_FLOAT)
	register_option(OPTION_DMG_HOMING, "nademodes_damage_homing", "1.0", TOPTION_FLOAT)
	
	// Damage System Option Values
	register_option_value(OPTION_DAMAGE_SYSTEM, "0;1;2")
	
	register_option_value(OPTION_DMG_THROUGH_WALL, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
	register_option_value(OPTION_DMG_SELF, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
	register_option_value(OPTION_DMG_TEAMMATES, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
	
	register_option_value(OPTION_DMG_NORMAL, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
	register_option_value(OPTION_DMG_IMPACT, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
	register_option_value(OPTION_DMG_MOTION, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
	register_option_value(OPTION_DMG_PROXIMITY, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
	register_option_value(OPTION_DMG_SATCHEL, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
	register_option_value(OPTION_DMG_TRIP, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
	register_option_value(OPTION_DMG_HOMING, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
	
	// Internal Settings Float Options
	register_option(OPTION_EXPLOSION_DELAY_TIME, "nademodes_explosion_delay_time", "60000.0", TOPTION_FLOAT)
	
	register_option(OPTION_RADIUS_SEC_EXPLOSION, "nademodes_secondary_explosion_radius", "275.0", TOPTION_FLOAT)
	
	register_option(OPTION_ARM_TIME_TRIP, "nademodes_trip_grenade_arm_time", "3.0", TOPTION_FLOAT)
	register_option(OPTION_ARM_TIME_PROXIMITY, "nademodes_proximity_arm_time", "2.0", TOPTION_FLOAT)
	register_option(OPTION_ARM_TIME_MOTION, "nademodes_motion_arm_time", "2.0",  TOPTION_FLOAT)
	register_option(OPTION_ARM_TIME_SATCHEL, "nademodes_satchel_arm_time", "2.0", TOPTION_FLOAT)
	
	register_option(OPTION_TRIP_FLY_SPEED, "nademodes_trip_grenade_fly_speed", "400.0", TOPTION_FLOAT)
	register_option(OPTION_TRIP_DETECT_DISTANCE, "nademodes_trip_grenade_detection_limit", "16000.0", TOPTION_FLOAT)
	
	register_option(OPTION_RADIUS_PROXIMITY, "nademodes_proximity_radius", "150.0", TOPTION_FLOAT)
	register_option(OPTION_RADIUS_MOTION, "nademodes_motion_radius", "200.0", TOPTION_FLOAT)
	
	register_option(OPTION_HOMING_SCAN_RANGE, "nademodes_homing_detection_range", "500.0", TOPTION_FLOAT)
	register_option(OPTION_HOMING_SUPER_RANGE, "nademodes_homing_superhoming_range", "100.0", TOPTION_FLOAT)
	register_option(OPTION_HOMING_EXTRATIME, "nademodes_homing_extratime", "0.5", TOPTION_FLOAT)
	register_option(OPTION_HOMING_SPEED_ADD, "nademodes_homing_velocity_deviation", "60.0", TOPTION_FLOAT)
	
	// Internal Settings Option Values
	register_option_value(OPTION_EXPLOSION_DELAY_TIME, "600;700;800;900;1000;1400;1800;2200;2600;3000;4000;5000;6000;10000;60000")
	
	register_option_value(OPTION_RADIUS_SEC_EXPLOSION, "25;50;75;100;125;150;175;200;225;250;275;300;325;350")
	
	register_option_value(OPTION_ARM_TIME_TRIP, "1;1.5;2;2.5;3;3.5;4;4.5;5")
	register_option_value(OPTION_ARM_TIME_PROXIMITY, "1;1.5;2;2.5;3;3.5;4;4.5;5")
	register_option_value(OPTION_ARM_TIME_MOTION, "1;1.5;2;2.5;3;3.5;4;4.5;5")
	register_option_value(OPTION_ARM_TIME_SATCHEL, "1;1.5;2;2.5;3;3.5;4;4.5;5")
	
	register_option_value(OPTION_TRIP_FLY_SPEED, "200;250;300;350;400;450;500;550;600;650;700;750;800;850;900;1000")
	register_option_value(OPTION_TRIP_DETECT_DISTANCE, "400;800;1000;2000;4000;8000;16000")
	
	register_option_value(OPTION_RADIUS_PROXIMITY, "100;110;120;130;140;150;160;170;180;190;200")
	register_option_value(OPTION_RADIUS_MOTION, "150;160;170;180;190;200;210;220;230;240;250")
	
	register_option_value(OPTION_HOMING_SCAN_RANGE,"200;250;300;350;400;450;500;550;600;650;700;750;800;850;900;950;1000")
	register_option_value(OPTION_HOMING_SUPER_RANGE, "40;60;80;100;120;140;160;180;200;220;240;260;280;300")
	register_option_value(OPTION_HOMING_EXTRATIME, "0;0.1;0.2;0.3;0.4;0.5;0.6;0.7;0.8;0.9;1")
	register_option_value(OPTION_HOMING_SPEED_ADD, "10;15;20;25;30;35;40;45;50;55;60;65;70;75;80;85;90;95;100;125;150")
	
	register_event("CurWeapon", "event_armnade", "b", "1=1", "2=4", "2=9", "2=25")
	register_event("CurWeapon", "event_curweapon", "b", "1=1")
	register_event("HLTV", "event_new_round", "a", "1=0", "2=0") 
	
	register_dictionary("nademodes.txt")
	
	callbacks[0] = menu_makecallback("callback_disabled")
	callbacks[1] = menu_makecallback("callback_enabled")
	
	// Get the config dir
	new config[sizeof(CFG_FILE)]
	get_configsdir(config, charsmax(CFG_FILE))
	format(CFG_FILE, charsmax(CFG_FILE), "%s/%s", config, CFG_FILE_NAME)
	
	// Execute the CFG file
	if(file_exists(CFG_FILE))
		server_cmd("exec %s", CFG_FILE)
	
	// Register all the forwards
	RegisterHam(Ham_TakeDamage, 	 "player", "fw_takedamage")
	RegisterHam(Ham_Player_PreThink, "player", "fw_playerprethink")
	
	RegisterHam(Ham_Touch, 		"grenade", "fw_touch")
	RegisterHam(Ham_Think, 		"grenade", "fw_think")
	RegisterHam(Ham_Think, 		"grenade", "fw_think_post", 1)
	RegisterHam(Ham_TakeDamage, "grenade", "fw_grenade_takedamage")
	
	RegisterHam(Ham_TraceAttack, "worldspawn", "fw_global_traceattack", 1)
	RegisterHam(Ham_TraceAttack, "player", "fw_global_traceattack", 1)
	
	register_forward(FM_CmdStart, 	"fw_cmdstart")
	register_forward(FM_SetModel, 	"fw_setmodel", 1)
	register_forward(FM_TraceLine, 	"fw_traceline")
	
	register_message(get_user_msgid("SendAudio"), "fith_audio")
	register_message(get_user_msgid("TextMsg"),  "fith_text")
	
	AddMenuItem("Nade Mode Menu", "amx_nmm", ADMIN_ACCESS, "NadeModes")
	
	set_task(SETTINGS_REFRESH_TIME, "update_forward_registration", 0, "", 0, "b", 0)
}

public plugin_end()
{
	TrieDestroy(trace_attack_reg_class)
	save_cfg()
}

register_option(Option:option, const name[300], const string[], OptionType:type = TOPTION_TOGGLE, flags = 0, Float:value = 0.0)
{
	pcvars[option] = register_cvar(name, string, flags, value)
	option_type[option] = type
	return
}

register_option_value(Option:option, values[CVAR_STRING_ALLOC])
{
	if (option_type[option] == TOPTION_TOGGLE)
		return
	
	option_value[option] = values
}

public save_cfg()
{
	static file[3000]
	format(file, charsmax(file), "echo [NadeModes] Executing config file ...^n")
	
	format(file, charsmax(file), "%s^n// General CVARS^n^n", file)
	
	format(file, charsmax(file), "%snademodes_enable %d^n", file, get_option_true(OPTION_ENABLE_NADE_MODES))
	format(file, charsmax(file), "%snademodes_nades_in_effect %d^n", file, get_option_true(OPTION_NADES_IN_EFFECT))
	
	format(file, charsmax(file), "%snademodes_effects %d^n", file, get_option_true(OPTION_RESOURCE_USE))
	format(file, charsmax(file), "%snademodes_play_grenade_sounds %d^n", file, get_option_true(OPTION_PLAY_SOUNDS))
	format(file, charsmax(file), "%snademodes_svc_bad_error_fix %d^n", file, get_option_true(OPTION_MSG_SVC_BAD))
	
	format(file, charsmax(file), "%snademodes_display_mode_on_draw %d^n", file, get_option_true(OPTION_DISPLAY_MODE_ON_DRAW))
	format(file, charsmax(file), "%snademodes_reset_mode_on_throw %d^n", file, get_option_true(OPTION_RESET_MODE_ON_THROW))
	format(file, charsmax(file), "%snademodes_suppress_fire_in_the_hole %d^n", file, get_option_true(OPTION_SUPPRESS_FITH))
	
	format(file, charsmax(file), "%snademodes_bot_support %d^n", file, get_option_true(OPTION_BOT_ALLOW))
	
	format(file, charsmax(file), "%snademodes_affect_owner %d^n", file, get_option_true(OPTION_AFFECT_OWNER))
	format(file, charsmax(file), "%snademodes_team_play %d^n", file, get_option_true(OPTION_TEAM_PLAY))
	
	format(file, charsmax(file), "%s^n// Mode CVARS^n^n", file)
	
	format(file, charsmax(file), "%snademodes_proximity_enabled %d^n", file, get_option_true(OPTION_PROXIMITY_ENABLED))
	format(file, charsmax(file), "%snademodes_impact_enabled %d^n", file, get_option_true(OPTION_IMPACT_ENABLED))
	format(file, charsmax(file), "%snademodes_trip_enabled %d^n", file, get_option_true(OPTION_TRIP_ENABLED))
	format(file, charsmax(file), "%snademodes_motion_enabled %d^n", file, get_option_true(OPTION_MOTION_ENABLED))
	format(file, charsmax(file), "%snademodes_satchel_enabled %d^n", file, get_option_true(OPTION_SATCHEL_ENABLED))
	format(file, charsmax(file), "%snademodes_homing_enabled %d^n", file, get_option_true(OPTION_HOMING_ENABLED))
	
	format(file, charsmax(file), "%snademodes_grenade_react %d^n", file, get_option_true(OPTION_REACT_TRIP_G))
	format(file, charsmax(file), "%snademodes_flash_react %d^n", file, get_option_true(OPTION_REACT_TRIP_F))
	format(file, charsmax(file), "%snademodes_smoke_react %d^n", file, get_option_true(OPTION_REACT_TRIP_S))
	
	format(file, charsmax(file), "%s^n// Limit & Test CVARS^n^n", file)
	
	format(file, charsmax(file), "%snademodes_limit_system %d^n", file, get_option_true(OPTION_LIMIT_SYSTEM))
	
	format(file, charsmax(file), "%snademodes_proximity_limit %d^n", file, get_option_true(OPTION_LIMIT_PROXIMITY))
	format(file, charsmax(file), "%snademodes_trip_limit %d^n", file, get_option_true(OPTION_LIMIT_TRIP))
	format(file, charsmax(file), "%snademodes_motion_limit %d^n", file, get_option_true(OPTION_LIMIT_MOTION))
	format(file, charsmax(file), "%snademodes_satchel_limit %d^n", file, get_option_true(OPTION_LIMIT_SATCHEL))
	
	format(file, charsmax(file), "%snademodes_infinite_grenades %d^n", file, get_option_true(OPTION_INFINITE_GRENADES))
	format(file, charsmax(file), "%snademodes_infinite_flashes %d^n", file, get_option_true(OPTION_INFINITE_FLASHES))
	format(file, charsmax(file), "%snademodes_infinite_smokes %d^n", file, get_option_true(OPTION_INFINITE_SMOKES))
	
	format(file, charsmax(file), "%s^n// Intergrenade CVARS CVARS^n^n", file)
	
	
	format(file, charsmax(file), "%snademodes_material_system %d^n", file, get_option_true(OPTION_MATERIAL_SYSTEM))
	format(file, charsmax(file), "%snademodes_grenade_death %d^n", file, get_option_true(OPTION_HITPOINT_DEATH))
	
	format(file, charsmax(file), "%snademodes_secondary_explosions_mode %d^n", file, get_option_true(OPTION_SEC_EXPLO_AFFECT))
	format(file, charsmax(file), "%snademodes_secondary_explosion_radius %f^n", file, get_option_float(OPTION_RADIUS_SEC_EXPLOSION))
	
	format(file, charsmax(file), "%snademodes_hitpoints_normal %d^n", file, get_option_true(OPTION_HITPOINT_NORMAL))
	format(file, charsmax(file), "%snademodes_hitpoints_proximity %d^n", file, get_option_true(OPTION_HITPOINT_PROXIMITY))
	format(file, charsmax(file), "%snademodes_hitpoints_impact %d^n", file, get_option_true(OPTION_HITPOINT_IMPACT))
	format(file, charsmax(file), "%snademodes_hitpoints_trip %d^n", file, get_option_true(OPTION_HITPOINT_TRIP))
	format(file, charsmax(file), "%snademodes_hitpoints_motion %d^n", file, get_option_true(OPTION_HITPOINT_MOTION))
	format(file, charsmax(file), "%snademodes_hitpoints_satchel %d^n", file, get_option_true(OPTION_HITPOINT_SATCHEL))
	format(file, charsmax(file), "%snademodes_hitpoints_homing %d^n", file, get_option_true(OPTION_HITPOINT_HOMING))
	
	format(file, charsmax(file), "%snademodes_hitpoints_intergrenade_damage %f^n", file, get_option_float(OPTION_HITPOINT_INTER_DMG))
	format(file, charsmax(file), "%snademodes_hitpoints_friendlyfire_ammount %f^n", file, get_option_float(OPTION_HITPOINT_FF))
	
	format(file, charsmax(file), "%s^n// Damage CVARS^n^n", file)
	
	format(file, charsmax(file), "%snademodes_damage_system %d^n", file, get_option_true(OPTION_DAMAGE_SYSTEM))
	
	format(file, charsmax(file), "%snademodes_damage_self %d^n", file, get_option_true(OPTION_DMG_SELF))
	format(file, charsmax(file), "%snademodes_damage_through_wall %d^n", file, get_option_true(OPTION_DMG_THROUGH_WALL))
	format(file, charsmax(file), "%snademodes_damage_teammate %d^n", file, get_option_true(OPTION_DMG_TEAMMATES))
	
	format(file, charsmax(file), "%snademodes_damage_normal %f^n", file, get_option_float(OPTION_DMG_NORMAL))
	format(file, charsmax(file), "%snademodes_damage_proximity %f^n", file, get_option_float(OPTION_DMG_PROXIMITY))
	format(file, charsmax(file), "%snademodes_damage_impact %f^n", file, get_option_float(OPTION_DMG_IMPACT))
	format(file, charsmax(file), "%snademodes_damage_trip %f^n", file, get_option_float(OPTION_DMG_TRIP))
	format(file, charsmax(file), "%snademodes_damage_motion %f^n", file, get_option_float(OPTION_DMG_MOTION))
	format(file, charsmax(file), "%snademodes_damage_satchel %f^n", file, get_option_float(OPTION_DMG_SATCHEL))
	format(file, charsmax(file), "%snademodes_damage_homing %f^n", file, get_option_float(OPTION_DMG_HOMING))
	
	format(file, charsmax(file), "%s^n// Internal Funcitonal CVARS^n^n", file)
	
	format(file, charsmax(file), "%snademodes_explosion_delay_time %f^n", file, get_option_float(OPTION_EXPLOSION_DELAY_TIME))
	
	format(file, charsmax(file), "%snademodes_proximity_arm_time %f^n", file, get_option_float(OPTION_ARM_TIME_PROXIMITY))
	format(file, charsmax(file), "%snademodes_proximity_radius %f^n", file, get_option_float(OPTION_RADIUS_PROXIMITY))
	
	format(file, charsmax(file), "%snademodes_trip_grenade_arm_time %f^n", file, get_option_float(OPTION_ARM_TIME_TRIP))
	format(file, charsmax(file), "%snademodes_trip_grenade_fly_speed %f^n", file, get_option_float(OPTION_TRIP_FLY_SPEED))
	format(file, charsmax(file), "%snademodes_trip_grenade_detection_limit %f^n", file, get_option_float(OPTION_TRIP_DETECT_DISTANCE))
	
	format(file, charsmax(file), "%snademodes_motion_arm_time %f^n", file, get_option_float(OPTION_ARM_TIME_MOTION))
	format(file, charsmax(file), "%snademodes_motion_radius %f^n", file, get_option_float(OPTION_RADIUS_MOTION))
	
	format(file, charsmax(file), "%snademodes_satchel_arm_time %f^n", file, get_option_float(OPTION_ARM_TIME_SATCHEL))
	
	format(file, charsmax(file), "%snademodes_homing_detection_range %f^n", file, get_option_float(OPTION_HOMING_SCAN_RANGE))
	format(file, charsmax(file), "%snademodes_homing_superhoming_range %f^n", file, get_option_float(OPTION_HOMING_SUPER_RANGE))
	format(file, charsmax(file), "%snademodes_homing_extratime %f^n", file, get_option_float(OPTION_HOMING_EXTRATIME))
	format(file, charsmax(file), "%snademodes_homing_velocity_deviation %f^n", file, get_option_float(OPTION_HOMING_SPEED_ADD))
	
	format(file, charsmax(file), "%s^necho [NadeModes] Settings loaded from config file", file)
	
	delete_file(CFG_FILE)
	write_file(CFG_FILE, file)
}

get_option(Option:option)
{
	return get_pcvar_num(pcvars[OPTION_ENABLE_NADE_MODES]) ? get_pcvar_num(pcvars[option]) : 0
}

/* -------------------------------
[Plugin Commands & Menus]
------------------------------- */
public conjure_help(id)
{
	static help_file[3000]
	
	format(help_file, charsmax(help_file), "%L", id, "NADE_HTML")
	
	delete_file("nmm.htm")
	write_file("nmm.htm", help_file)
	show_motd(id, "nmm.htm", "Mega-Nade Mod")
	
	return PLUGIN_CONTINUE
}

public conjure_cl_menu(id)
{
	cl_menu(id)
	return PLUGIN_HANDLED
}

public conjure_menu(id, level, cid)
{
	if (cmd_access(id, level, cid, 1))
	{
		main_menu(id)
	}
	
	return PLUGIN_HANDLED
}

stock cl_menu(id, page = 0)
{
	static menu, property_number, string[64]
	
	settingsmenu[id] = menu_create("NadeModes - Mode Selection", "clmenu_handler")
	
	menu = settingsmenu[id]
	
	for (new NadeRace:i = GRENADE_EXPLOSIVE; i <= GRENADE_SMOKEGREN; i += GRENADE_FLASHBANG)
	{
		property_number = 2 * collection[id][i]
		
		for (new NadeType:j = NADE_PROXIMITY; j <= NADE_HOMING; j += NADE_PROXIMITY)
		{
			format(string, charsmax(string), "%s %s mode: %s%s", NADE_NAME[i], modetext[_:j], (property_number & (1 << _:j)) ? "\yYes" : "\rNo", (j == NADE_HOMING) ? "^n" : "")
			menu_additem(menu, string)
		}
		
	}
	
	menu_display(id, settingsmenu[id], page)
}


stock main_menu(id)
{
	static menu
	settingsmenu[id] = menu_create("NadeModes - Main Menu", "menu_handler")
	menu = settingsmenu[id]
	
	add_option_toggle(menu, OPTION_ENABLE_NADE_MODES, "Enable nade modes", "Yes", "No")
	
	menu_additem(menu, "Execute config file")
	menu_additem(menu, "General settings", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
	menu_additem(menu, "Mode control menu", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
	menu_additem(menu, "Mode limit & test menu", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
	menu_additem(menu, "Hitpoints menu", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
	menu_additem(menu, "Mode damage settings", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
	menu_additem(menu, "Internal functional settings", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
	
	menu_display(id, settingsmenu[id])
	return PLUGIN_CONTINUE
}

public menu_handler(id, menu, item)
{
	if (item < 0)
	{
		return PLUGIN_HANDLED
	}
	
	switch (item)
	{
		case 0:
		{
			toggle_option(OPTION_ENABLE_NADE_MODES)
		}
		case 1:
		{
			if(file_exists(CFG_FILE))
			{
				server_cmd("exec %s", CFG_FILE)
				update_forward_registration()
			}
			else
			{
				client_print(id, print_chat, "[NDM] Config file not found!")
			}
		}
		
		default:
		{
			menu_destroy(menu)
			cvar_menu(id, 0, item - 1)
			return PLUGIN_HANDLED
		}
	}
	
	
	menu_destroy(menu)
	main_menu(id)
	return PLUGIN_HANDLED
}

stock cvar_menu(id, page = 0, menu_set = 0)
{
	if (menu_set <= 0)
		return PLUGIN_CONTINUE
	
	static menu
	
	switch (menu_set)
	{
		case 1:
		{
			settingsmenu[id] = menu_create("NadeModes - General Settings", "cvar_menu_handler")
			menu = settingsmenu[id]
			
			add_nade_option(menu, OPTION_NADES_IN_EFFECT, "Affected nades")
			
			add_option_tritoggle(menu, OPTION_RESOURCE_USE, "Plugin effects", "\rOff", "\yNormal", "\ySmart Mode")
			add_option_toggle(menu, OPTION_PLAY_SOUNDS, "Grenade sounds", "On", "Off")
			add_option_toggle(menu, OPTION_MSG_SVC_BAD, "SVC_BAD fix", "On^n   \yNote: \wTurn on when the server has this problem!^n", "Off^n   \yNote: \wTurn on when the server has this problem!^n")
			
			add_option_toggle(menu, OPTION_BOT_ALLOW, "Allow bots to use the moded nades", "Yes^n", "No^n") 
			
			add_option_toggle(menu, OPTION_DISPLAY_MODE_ON_DRAW, "Display mode on draw", "Yes", "No")
			add_option_toggle(menu, OPTION_RESET_MODE_ON_THROW, "Reset mode on throw", "Yes^n", "No^n")
			
			add_option_toggle(menu, OPTION_AFFECT_OWNER, "Traps can be activated by owner", "Yes", "No")
			add_option_toggle(menu, OPTION_TEAM_PLAY, "Team play (teammates will not be affected by nades)", "Yes^n", "No^n")
			
			add_option_toggle(menu, OPTION_SUPPRESS_FITH, "Suppress ^"Fire in the hole!^"", "Yes", "No")
			
		}
		case 2:
		{
			settingsmenu[id] = menu_create("NadeModes - Mode Control", "cvar_menu_handler")
			menu = settingsmenu[id]
			
			add_option_toggle(menu, OPTION_PROXIMITY_ENABLED, "Enable proximity grenades", "Yes", "No")
			add_option_toggle(menu, OPTION_IMPACT_ENABLED, "Enable impact grenades", "Yes", "No")
			add_option_toggle(menu, OPTION_TRIP_ENABLED, "Enable trip grenades", "Yes", "No")
			add_option_toggle(menu, OPTION_MOTION_ENABLED, "Enable motion sensor grenades", "Yes", "No")
			add_option_toggle(menu, OPTION_SATCHEL_ENABLED, "Enable satchel charge grenades", "Yes", "No")
			add_option_toggle(menu, OPTION_HOMING_ENABLED, "Enable homing grenades", "Yes^n", "No^n")
			
			add_option_toggle(menu, OPTION_REACT_TRIP_G, "Trip grenade react method", "Boom", "Fly", OPTION_TRIP_ENABLED)
			add_option_toggle(menu, OPTION_REACT_TRIP_F, "Trip flash react method", "Boom", "Fly", OPTION_TRIP_ENABLED)
			add_option_toggle(menu, OPTION_REACT_TRIP_S, "Trip smoke react method", "Boom", "Fly", OPTION_TRIP_ENABLED)
		}
		case 3:
		{
			settingsmenu[id] = menu_create("NadeModes - Limit & Test Menu", "cvar_menu_handler")
			menu = settingsmenu[id]
			
			add_option_tritoggle(menu, OPTION_LIMIT_SYSTEM, "Limit system", "\rOff^n", "\yAvailable for each nade^n", "\yAvailable for general quantity^n")
			
			add_cell_option(menu, OPTION_LIMIT_PROXIMITY, "Proximity throw limit", "grenades", OPTION_LIMIT_SYSTEM)
			add_cell_option(menu, OPTION_LIMIT_TRIP, "Trip grenade throw limit", "grenades", OPTION_LIMIT_SYSTEM)
			add_cell_option(menu, OPTION_LIMIT_MOTION, "Motion throw limit", "grenades", OPTION_LIMIT_SYSTEM)
			add_cell_with_space_option(menu, OPTION_LIMIT_SATCHEL, "Stachel throw limit", "grenades", OPTION_LIMIT_SYSTEM)
			
			add_option_toggle(menu, OPTION_INFINITE_GRENADES, "Infinite grenades", "Yes", "No")
			add_option_toggle(menu, OPTION_INFINITE_FLASHES, "Infinite flashes", "Yes", "No")
			add_option_toggle(menu, OPTION_INFINITE_SMOKES, "Infinite smokes", "Yes", "No")
		}
		case 4:
		{
			settingsmenu[id] = menu_create("NadeModes - Hitpoint Menu", "cvar_menu_handler")
			menu = settingsmenu[id]
			
			add_option_tritoggle(menu, OPTION_MATERIAL_SYSTEM, "Interaction system", "\rOff", "\ySecondary Explosions", "\yHit Point System")
			
			
			
			switch (get_option(OPTION_MATERIAL_SYSTEM))
			{
				case 0:
				{
					add_option_toggle(menu, OPTION_HITPOINT_DEATH, "Nade death", "Explode^n", "Desintegrate^n",OPTION_MATERIAL_SYSTEM)
					
					add_cell_option(menu, OPTION_HITPOINT_NORMAL, "Normal grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
					add_cell_option(menu, OPTION_HITPOINT_PROXIMITY, "Proximity grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
					add_cell_option(menu, OPTION_HITPOINT_IMPACT, "Impact grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
					add_cell_option(menu, OPTION_HITPOINT_TRIP, "Trip grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
					add_cell_option(menu, OPTION_HITPOINT_MOTION, "Motion grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
					add_cell_option(menu, OPTION_HITPOINT_SATCHEL, "Satchel grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
					add_cell_option(menu, OPTION_HITPOINT_HOMING, "Homing grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
				}
				
				case 1:
				{
					add_option_toggle(menu, OPTION_SEC_EXPLO_AFFECT, "Secondary explosions", "\yEach nade affects each!^n", "\yHe grenade affects all^n")
					add_float_option(menu, OPTION_RADIUS_SEC_EXPLOSION, "Secondary explosion radius affection", "units")
				}
				
				case 2:
				{
					add_option_toggle(menu, OPTION_HITPOINT_DEATH, "Nade death", "Explode^n", "Desintegrate^n",OPTION_MATERIAL_SYSTEM)
					
					add_cell_option(menu, OPTION_HITPOINT_NORMAL, "Normal grenade hitpoints", "hitpoints")
					add_cell_option(menu, OPTION_HITPOINT_PROXIMITY, "Proximity grenade hitpoints", "hitpoints", OPTION_PROXIMITY_ENABLED)
					add_cell_option(menu, OPTION_HITPOINT_IMPACT, "Impact grenade hitpoints", "hitpoints", OPTION_IMPACT_ENABLED)
					add_cell_option(menu, OPTION_HITPOINT_TRIP, "Trip grenade hitpoints", "hitpoints", OPTION_TRIP_ENABLED)
					add_cell_option(menu, OPTION_HITPOINT_MOTION, "Motion grenade hitpoints", "hitpoints", OPTION_MOTION_ENABLED)
					add_cell_option(menu, OPTION_HITPOINT_SATCHEL, "Satchel grenade hitpoints", "hitpoints", OPTION_SATCHEL_ENABLED)
					add_cell_option(menu, OPTION_HITPOINT_HOMING, "Homing grenade hitpoints", "hitpoints^n", OPTION_HOMING_ENABLED)
					
					add_float_option(menu, OPTION_HITPOINT_FF, "Friendlyfire", "%", OPTION_MATERIAL_SYSTEM)
					add_float_option(menu, OPTION_HITPOINT_INTER_DMG, "Integrenade damage", "%", OPTION_MATERIAL_SYSTEM)
					
				}
			}
		}
		case 5:
		{
			settingsmenu[id] = menu_create("NadeModes - Damage Settings", "cvar_menu_handler")
			menu = settingsmenu[id]
			
			add_option_tritoggle(menu, OPTION_DAMAGE_SYSTEM, "Damage system", "\rOff^n", "\yActive for every mode^n", "\yEach mode configurable^n")
			
			add_float_option(menu, OPTION_DMG_SELF, "Nade self damage percent", "%", OPTION_DAMAGE_SYSTEM)
			add_float_option(menu, OPTION_DMG_THROUGH_WALL, "Nade through wall damage percent", "%", OPTION_DAMAGE_SYSTEM)
			
			switch (get_option(OPTION_DAMAGE_SYSTEM))
			{
				case 0:
				{
					add_float_option(menu, OPTION_DMG_TEAMMATES, "Team mates damage percent", "%^n", OPTION_DAMAGE_SYSTEM)
				}
				
				case 1:
				{
					add_float_option(menu, OPTION_DMG_TEAMMATES, "Team mates damage percent", "%^n", OPTION_FRIENDLY_FIRE)
					
					add_float_option(menu, OPTION_DMG_NORMAL, "Grenade general damage multiply","times")
				}
				
				case 2:
				{
					add_float_option(menu, OPTION_DMG_TEAMMATES, "Team mates damage percent", "%^n", OPTION_FRIENDLY_FIRE)
					
					add_float_option(menu, OPTION_DMG_NORMAL, "Normal Grenade - damage multiply","times")
					add_float_option(menu, OPTION_DMG_PROXIMITY, "Proximity Grenade - damage multiply","times", OPTION_PROXIMITY_ENABLED)
					add_float_option(menu, OPTION_DMG_IMPACT, "Impact Grenade - damage multiply","times", OPTION_IMPACT_ENABLED)
					add_float_option(menu, OPTION_DMG_TRIP, "Trip Grenade - damage multiply","times", OPTION_TRIP_ENABLED)
					add_float_option(menu, OPTION_DMG_MOTION, "Motion Grenade - damage multiply","times", OPTION_MOTION_ENABLED)
					add_float_option(menu, OPTION_DMG_SATCHEL, "Satchel Grenade - damage multiply","times", OPTION_SATCHEL_ENABLED)
					add_float_option(menu, OPTION_DMG_HOMING, "Homing Grenade - damage multiply","times", OPTION_HOMING_ENABLED)
				}
			}
		}
		case 6:
		{
			settingsmenu[id] = menu_create("NadeModes - Internal Functional Settings", "cvar_menu_handler")
			menu = settingsmenu[id]
			
			add_float_option(menu, OPTION_EXPLOSION_DELAY_TIME, "Grenade general delay explode time", "seconds^n")
			
			add_float_option(menu, OPTION_ARM_TIME_PROXIMITY, "Proximity arm time", "seconds", OPTION_PROXIMITY_ENABLED)
			add_float_option(menu, OPTION_RADIUS_PROXIMITY, "Proximity detection radius", "units^n", OPTION_PROXIMITY_ENABLED)
			
			add_float_option(menu, OPTION_ARM_TIME_TRIP, "Trip grenade arm time", "seconds", OPTION_TRIP_ENABLED)
			add_float_option(menu, OPTION_TRIP_DETECT_DISTANCE, "Trip grenade detection distance", "units", OPTION_TRIP_ENABLED)
			add_float_option(menu, OPTION_TRIP_FLY_SPEED, "Trip grenade fly speed", "units^n", OPTION_TRIP_ENABLED)
			
			add_float_option(menu, OPTION_ARM_TIME_SATCHEL, "Satchel charge arm time", "seconds^n", OPTION_SATCHEL_ENABLED)
			
			add_float_option(menu, OPTION_ARM_TIME_MOTION, "Motion sensor arm time", "seconds", OPTION_MOTION_ENABLED)
			add_float_option(menu, OPTION_RADIUS_MOTION, "Motion sensor detection radius", "units^n", OPTION_MOTION_ENABLED)
			
			add_float_option(menu, OPTION_HOMING_EXTRATIME, "Homing extra arm explosion time", "seconds", OPTION_HOMING_ENABLED)
			add_float_option(menu, OPTION_HOMING_SCAN_RANGE, "Homing grenade detection range", "units", OPTION_HOMING_ENABLED)
			add_float_option(menu, OPTION_HOMING_SUPER_RANGE, "Homing grenade superhoming range", "units", OPTION_HOMING_ENABLED)
			add_float_option(menu, OPTION_HOMING_SPEED_ADD, "Homing grenade follow velocity", "units", OPTION_HOMING_ENABLED)
		}
	}
	
	cvar_menu_pos[id] = menu_set
	menu_display(id, settingsmenu[id], page)
	return PLUGIN_CONTINUE
}

stock add_option_toggle(menu, Option:control_option, const basetext[], const yestext[], const notext[], Option:displayif = Option:-1)
{
	static cmd[4], itemtext[100]
	num_to_str(_:control_option, cmd, charsmax(cmd))
	
	format(itemtext, charsmax(itemtext), "%s: %s%s", basetext, (get_option(control_option) ? "\y" : "\r" ), (get_option(control_option) ? yestext : notext))
	menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}

stock add_option_tritoggle(menu, Option:control_option, const basetext[], const text[], const text2[], const text3[], Option:displayif = Option:-1)
{
	static cmd[4], itemtext[100]
	num_to_str(_:control_option, cmd, charsmax(cmd))
	
	format(itemtext, charsmax(itemtext), "%s:\y %s%s%s", basetext, (get_option(control_option) == 0 ? text : "" ), (get_option(control_option) == 1 ? text2 : "" ), (get_option(control_option) == 2 ? text3 : "" ))
	menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}

stock add_nade_option(menu, Option:control_option, const basetext[])
{
	static cmd[4], itemtext[100]
	num_to_str(_:control_option, cmd, charsmax(cmd))
	
	format(itemtext, charsmax(itemtext), "%s:%s%s%s%s^n", basetext, (get_option(control_option) ? "\y" : " \rNone" ), ((get_option(control_option) & NADE_BIT[GRENADE_EXPLOSIVE]) ? " He" : ""), ((get_option(control_option) & NADE_BIT[GRENADE_FLASHBANG]) ? " Flash" : ""), ((get_option(control_option) & NADE_BIT[GRENADE_SMOKEGREN]) ? " Smoke" : ""))
	menu_additem(menu, itemtext, cmd, _, _)
}

stock add_float_option(menu, Option:control_option, const basetext[], const unit[], Option:displayif = Option:-1)
{
	static cmd[4], itemtext[100], value[20]
	float_to_str(get_option_float(control_option), value, charsmax(value))
	format(value, charsmax(value), "%0.2f", get_option_float(control_option))
	
	num_to_str(_:control_option, cmd, charsmax(cmd))
	
	format(itemtext, charsmax(itemtext), "%s: \y%s \r%s", basetext, value, unit)
	menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}

stock add_cell_option(menu, Option:control_option, const basetext[], const unit[], Option:displayif = Option:-1)
{
	static cmd[4], itemtext[100], value[20]
	num_to_str(get_option(control_option), value, charsmax(value))
	format(value, charsmax(value), "%d", get_option(control_option))
	if (!get_option(control_option))
	{
		value = "Off"
	}
	
	num_to_str(_:control_option, cmd, charsmax(cmd))
	
	format(itemtext, charsmax(itemtext), "%s: \y%s \r%s", basetext, value, get_option(control_option) ? unit : "")
	menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}

stock add_cell_with_space_option(menu, Option:control_option, const basetext[], const unit[], Option:displayif = Option:-1)
{
	static cmd[4], itemtext[100], value[20]
	num_to_str(get_option(control_option), value, charsmax(value))
	format(value, charsmax(value), "%d", get_option(control_option))
	if (!get_option(control_option))
	{
		value = "Off"
	}
	
	num_to_str(_:control_option, cmd, charsmax(cmd))
	
	format(itemtext, charsmax(itemtext), "%s: \y%s \r%s^n", basetext, value, get_option(control_option) ? unit : "")
	menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}


public cvar_menu_handler(id, menu, item)
{
	new access, info[4], callback
	menu_item_getinfo(menu, item, access, info, charsmax(info), _, _, callback)
	
	if (item < 0)
	{
		update_forward_registration()
		save_cfg()
		main_menu(id)
		return PLUGIN_HANDLED
	}
	
	new cvar = str_to_num(info)
	
	switch (option_type[Option:cvar])
	{
		case TOPTION_TOGGLE:
		{
			toggle_option(Option:cvar)
		}
		case TOPTION_CELL:
		{
			new value_string[CVAR_STRING_ALLOC]
			format(value_string, charsmax(value_string), "%s;", option_value[Option:cvar])
			
			new values[CVAR_MAX_ASSIGNED_VALUES][CVAR_MAX_STRING_LENGTH]
			new true_value[CVAR_MAX_ASSIGNED_VALUES]
			
			new last = 0, newpos = 0, k = 0;
			
			for (new i=0;i<CVAR_STRING_ALLOC;i++)
			{
				if(equal(value_string[i], ";", 1))
				{
					newpos = i
				}
				
				if (newpos > last)
				{					
					for (new j=last;j<newpos;j++)
					{
						format(values[k], CVAR_MAX_STRING_LENGTH - 1, "%s%s", values[k], value_string[j])
					}
					
					last = newpos + 1
					k++
				}
				
				if (k == CVAR_MAX_ASSIGNED_VALUES)
				{
					break
				}
			}
			
			new bool:ok = false
			new counter = 0
			
			for (new i=0;i<k;i++)
			{
				counter++
				
				true_value[i] = str_to_num(values[i])
				
				if (ok == true)
				{
					set_pcvar_num(pcvars[Option:cvar], true_value[i])
					counter = 0
					break
				}
				
				if (true_value[i] == get_option(Option:cvar))
					ok = true
			}
			
			if (counter == k)
			{
				set_pcvar_num(pcvars[Option:cvar], true_value[0])
			}
		}
		case TOPTION_FLOAT:
		{
			new value_string_float[CVAR_STRING_ALLOC]
			format(value_string_float, charsmax(value_string_float), "%s;", option_value[Option:cvar])
			
			new values_float[CVAR_MAX_ASSIGNED_VALUES][CVAR_MAX_STRING_LENGTH]
			new Float:true_value_float[CVAR_MAX_ASSIGNED_VALUES]
			
			new last = 0, newpos = 0, k = 0;
			
			for (new i=0;i<CVAR_STRING_ALLOC;i++)
			{
				if(equal(value_string_float[i], ";", 1))
				{
					newpos = i
				}
				
				if (newpos > last)
				{					
					for (new j=last;j<newpos;j++)
					{
						format(values_float[k], CVAR_MAX_STRING_LENGTH - 1, "%s%s", values_float[k], value_string_float[j])
					}
					
					last = newpos + 1
					k++
				}
				
				if (k == CVAR_MAX_ASSIGNED_VALUES)
				{
					break
				}
			}
			
			new bool:ok=false
			new counter = 0
			
			for (new i=0;i<k;i++)
			{
				counter++
				
				true_value_float[i] = str_to_float(values_float[i])
				
				if (ok == true)
				{
					set_pcvar_float(pcvars[Option:cvar], true_value_float[i])
					counter = 0
					break
				}
				
				if (true_value_float[i] == get_option_float(Option:cvar))
					ok = true
			}
			
			if (counter == k)
			{
				set_pcvar_float(pcvars[Option:cvar], true_value_float[0])
			}
			
		}
	}
	
	menu_destroy(menu)
	update_forward_registration()
	cvar_menu(id, item / 7, cvar_menu_pos[id])
	save_cfg()
	return PLUGIN_HANDLED
}

public clmenu_handler(id, menu, item)
{
	if (item < 0)
	{
		return PLUGIN_HANDLED
	}
	
	static page, place
	
	page = item / _:NADE_HOMING
	place = (item % _:NADE_HOMING)
	
	if ( collection[id][NadeRace:page] & (1 << place) )
	{
		collection[id][NadeRace:page] &= ~(1 << place)
	}
	else
	{
		collection[id][NadeRace:page] |= (1 << place)
	}
	
	client_cmd(id, "setinfo %s %d", NADE_SETINFO[NadeRace:page], collection[id][NadeRace:page])
	
	menu_destroy(menu)
	cl_menu(id, item / 7)
	
	return PLUGIN_HANDLED
}

public callback_disabled(id, menu, item)
{
	return ITEM_DISABLED
}

public callback_enabled(id, menu, item)
{
	return ITEM_ENABLED
}

/* -------------------------------
[Client Internet Forwards]
------------------------------- */
public client_connect(id)
{
	mode[id][GRENADE_EXPLOSIVE] = NADE_NORMAL
	mode[id][GRENADE_FLASHBANG] = NADE_NORMAL
	mode[id][GRENADE_SMOKEGREN] = NADE_NORMAL
	
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_MOTION] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_TRIP] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_MOTION] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_TRIP] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_MOTION] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_TRIP] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_SATCHEL] = 0
}

public client_putinserver(id)
{
	// Add the bot property if user is bot
	if (is_user_bot(id))
		cl_is_bot |= (1<<(id-1))
}

public client_disconnect(id)
{
	// Remove the bot property (doesn't matter wether it was true or false)
	cl_is_bot &= ~(1<<(id-1))
	
	mode[id][GRENADE_EXPLOSIVE] = NADE_NORMAL
	mode[id][GRENADE_FLASHBANG] = NADE_NORMAL
	mode[id][GRENADE_SMOKEGREN] = NADE_NORMAL
	
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_MOTION] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_TRIP] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_MOTION] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_TRIP] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_MOTION] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_TRIP] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_SATCHEL] = 0
	
	cl_team[id] = CS_TEAM_UNASSIGNED
}

public client_infochanged(id)
{
	static string[33],number
	
	get_user_info(id, NADE_SETINFO[GRENADE_EXPLOSIVE], string, charsmax(string))
	
	if (!string[0])
	{
		number = SETTINGS_BITSUM
		client_cmd(id, "setinfo %s %d", NADE_SETINFO[GRENADE_EXPLOSIVE], number)
	}
	else
		number = str_to_num(string)
	
	collection[id][GRENADE_EXPLOSIVE] = number
	
	get_user_info(id, NADE_SETINFO[GRENADE_FLASHBANG], string, charsmax(string))
	
	if (!string[0])
	{
		number = SETTINGS_BITSUM
		client_cmd(id, "setinfo %s %d", NADE_SETINFO[GRENADE_FLASHBANG], number)
	}
	else
		number = str_to_num(string)
	
	collection[id][GRENADE_FLASHBANG] = number
	
	get_user_info(id, NADE_SETINFO[GRENADE_SMOKEGREN], string, charsmax(string))
	
	if (!string[0])
	{
		number = SETTINGS_BITSUM
		client_cmd(id, "setinfo %s %d", NADE_SETINFO[GRENADE_SMOKEGREN], number)
	}
	else
		number = str_to_num(string)
	
	collection[id][GRENADE_SMOKEGREN] = number
	
	return PLUGIN_CONTINUE
}

/* -------------------------------
[Forwards Registration Toggle]
------------------------------- */
public update_forward_registration()
{
	// Here we also update some global constants
	g_maxplayers = get_maxplayers()
	
	if (g_check_hpsystem == -1)
	{
		g_check_hpsystem = get_option_true(OPTION_MATERIAL_SYSTEM)
	}
	else
	{
		if (!get_option_true(OPTION_ENABLE_NADE_MODES) && get_option_true(OPTION_MATERIAL_SYSTEM) == 2)
		{
			new i=-1
			while ((i = find_ent_by_class(i, "grenade")))
			{
				if (!is_grenade(i))
					continue
				
				if (entity_get_float(i, EV_FL_health))
				{
					entity_set_float(i, EV_FL_takedamage, DAMAGE_NO)
				}
			}
		}
		
		if (g_check_hpsystem != get_option_true(OPTION_MATERIAL_SYSTEM))
		{
			if ((get_option_true(OPTION_MATERIAL_SYSTEM) == 0 || get_option_true(OPTION_MATERIAL_SYSTEM) == 1) && g_check_hpsystem == 2)
			{
				new i=-1
				while ((i = find_ent_by_class(i, "grenade")))
				{
					if (!is_grenade(i))
						continue
					
					if (entity_get_float(i, EV_FL_health))
					{
						entity_set_float(i, EV_FL_takedamage, DAMAGE_NO)
					}
				}
			}
			
			if (get_option_true(OPTION_MATERIAL_SYSTEM) == 2 && (g_check_hpsystem == 1 || g_check_hpsystem == 0))
			{
				
				new i=-1
				while ((i = find_ent_by_class(i, "grenade")))
				{
					if (!is_grenade(i))
						continue
					
					if (entity_get_float(i, EV_FL_health))
					{
						entity_set_float(i, EV_FL_takedamage, DAMAGE_YES)
					}
				}
			}
		}
		
		g_check_hpsystem = get_option_true(OPTION_MATERIAL_SYSTEM)
	}
	
	if (get_option(OPTION_ENABLE_NADE_MODES))
	{
		bs_forward_collection |= FWD_CMDSTART | FWD_SETMODEL | FWD_THINK | FWD_TOUCH 
		
		if (get_option(OPTION_DAMAGE_SYSTEM))
		{
			bs_forward_collection |= FWD_TAKEDAMAGE
		}
		else
		{
			bs_forward_collection &= ~FWD_TAKEDAMAGE
		}
		
		if (get_option(OPTION_RESOURCE_USE))
		{
			bs_forward_collection |= FWD_THINK_POST
		}
		else
		{
			bs_forward_collection &= ~FWD_THINK_POST
		}
		
		if (!get_option(OPTION_MATERIAL_SYSTEM) || get_option(OPTION_MATERIAL_SYSTEM) > 2 || get_option(OPTION_MATERIAL_SYSTEM) < 0)
		{
			bs_forward_collection &= ~(FWD_SEC_EXPLODE | FWD_HPSYSTEM)
		}
		
		if (get_option(OPTION_MATERIAL_SYSTEM) == 1)
		{
			bs_forward_collection |= FWD_SEC_EXPLODE
		}
		else
		{
			bs_forward_collection &= ~FWD_SEC_EXPLODE
		}
		
		if (get_option(OPTION_MATERIAL_SYSTEM) == 2)
		{
			bs_forward_collection |= FWD_HPSYSTEM
		}
		else
		{
			bs_forward_collection &= ~FWD_HPSYSTEM
		}
		
		if (get_option(OPTION_SUPPRESS_FITH))
		{
			bs_forward_collection |= FWD_MESSAGE
		}
		else
		{
			bs_forward_collection &= ~FWD_MESSAGE
		}
		
	}
	else
	{
		bs_forward_collection = FWD_NONE_ACTIVE
	}
}
/* -------------------------------
[Events]
------------------------------- */
public event_armnade(id)
{
	static nade
	
	switch (read_data(2))
	{
		case CSW_HEGRENADE: 	nade = _:GRENADE_EXPLOSIVE
		case CSW_FLASHBANG: 	nade = _:GRENADE_FLASHBANG
		case CSW_SMOKEGRENADE: 	nade = _:GRENADE_SMOKEGREN
		default: return PLUGIN_CONTINUE
	}
	
	if (get_option(OPTION_INFINITE_GRENADES + Option:nade))
	{
		cs_set_user_bpammo(id, NADE_WPID[NadeRace:nade], 2000)
	}
	
	if (get_option(OPTION_DISPLAY_MODE_ON_DRAW) && grenade_can_be_used(NadeRace:nade))
	{
		client_print(id, print_center, "Mode: %s", modetext[_:mode[id][NadeRace:nade]])
	}
	
	if (get_option(OPTION_ENABLE_NADE_MODES) && !is_mode_enabled(id, mode[id][NadeRace:nade], NadeRace:nade))
	{
		changemode(id, NadeRace:nade)
	}
	
	return PLUGIN_CONTINUE
}

public event_curweapon(id)
{
	cl_weapon[id] = read_data(2)
}

public event_new_round()
{
	static players[32], count, id
	get_players(players, count)
	
	for (new i=0;i<count;i++)
	{
		id = players[i]
		cl_counter[id][GRENADE_EXPLOSIVE][NADE_MOTION] = 0
		cl_counter[id][GRENADE_EXPLOSIVE][NADE_PROXIMITY] = 0
		cl_counter[id][GRENADE_EXPLOSIVE][NADE_TRIP] = 0
		cl_counter[id][GRENADE_EXPLOSIVE][NADE_SATCHEL] = 0
		cl_counter[id][GRENADE_FLASHBANG][NADE_MOTION] = 0
		cl_counter[id][GRENADE_FLASHBANG][NADE_PROXIMITY] = 0
		cl_counter[id][GRENADE_FLASHBANG][NADE_TRIP] = 0
		cl_counter[id][GRENADE_FLASHBANG][NADE_SATCHEL] = 0
		cl_counter[id][GRENADE_SMOKEGREN][NADE_MOTION] = 0
		cl_counter[id][GRENADE_SMOKEGREN][NADE_PROXIMITY] = 0
		cl_counter[id][GRENADE_SMOKEGREN][NADE_TRIP] = 0
		cl_counter[id][GRENADE_SMOKEGREN][NADE_SATCHEL] = 0
	}
	
	
	static ent
	
	ent = -1
	while ((ent = find_ent_by_class(ent, "grenade")))
	{
		if(is_grenade(ent) && get_grenade_type(ent) != NADE_NORMAL)
			entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_KILLME)
	}
	
	return PLUGIN_CONTINUE
}

/* -------------------------------
[Message Engine Forwads]
------------------------------- */
public fith_audio(msg_id, msg_dest, entity)
{
	if (!(bs_forward_collection & FWD_MESSAGE))
		return PLUGIN_CONTINUE
	
	// Get the string that holds the message and test it to see wether to block it or not
	static string[18]
	get_msg_arg_string(2, string, charsmax(string))
	
	if (equal(string, "%!MRAD_FIREINHOLE")) return PLUGIN_HANDLED
	
	return PLUGIN_CONTINUE
}

public fith_text(msg_id, msg_dest, entity)
{
	if (!(bs_forward_collection & FWD_MESSAGE))
		return PLUGIN_CONTINUE
	
	static string[18]
	
	// Get the string that holds the message and test it to see wether to block it or not
	if (get_msg_args() == 5) // CS
	{
		get_msg_arg_string(5, string, charsmax(string))
	}
	else
	{
		if (get_msg_args() == 6) // CZ
		{
			get_msg_arg_string(6, string, charsmax(string))
		}
		else
		{
			return PLUGIN_CONTINUE
		}
	}
	
	return (equal(string, "#Fire_in_the_hole")) ? PLUGIN_HANDLED : PLUGIN_CONTINUE
}

/* -------------------------------
[Ham & Fakemeta Forwards]
------------------------------- */
public fw_playerprethink(id)
{
	if (!is_user_connected(id) || is_user_connecting(id) || is_user_hltv(id))
		return HAM_IGNORED
	
	switch (cs_get_user_team(id))
	{
		case CS_TEAM_T: cl_team[id] = CS_TEAM_T
		case CS_TEAM_CT: cl_team[id] = CS_TEAM_CT
		default: return HAM_IGNORED
	}
	
	return HAM_IGNORED
}

public fw_cmdstart(id, uc_handle, seed)
{
	if (!(bs_forward_collection & FWD_CMDSTART))
		return FMRES_IGNORED
	
	if (!is_user_alive(id))
		return FMRES_IGNORED
	
	static bool:key[MAX_PLAYERS + 1] = {false, ...}
	
	static buttons
	buttons = get_uc(uc_handle, UC_Buttons)
	
	if ((buttons & IN_ATTACK2))
	{
		if (!key[id])
		{
			#if AMXX_VERSION_NUM < 180
			static dummy
			
			switch (get_user_weapon(id, dummy, dummy))
			{
				case CSW_HEGRENADE: 	changemode(id, GRENADE_EXPLOSIVE)
				case CSW_FLASHBANG: 	changemode(id, GRENADE_FLASHBANG)
				case CSW_SMOKEGRENADE: 	changemode(id, GRENADE_SMOKEGREN)
			}
			#endif
			
			#if AMXX_VERSION_NUM >= 180
			switch (get_user_weapon(id))
			{
				case CSW_HEGRENADE: 	changemode(id, GRENADE_EXPLOSIVE)
				case CSW_FLASHBANG: 	changemode(id, GRENADE_FLASHBANG)
				case CSW_SMOKEGRENADE:	changemode(id, GRENADE_SMOKEGREN)
			}
			#endif
		}
		
		key[id] = true
	}
	else
	{
		key[id] = false
	}
	
	return FMRES_IGNORED
}

public fw_setmodel(ent, model[])
{
	if (!pev_valid(ent))
	{
		return FMRES_IGNORED
	}
	
	// Not yet thrown
	if (entity_get_float(ent, EV_FL_gravity) == 0.0)
	{
		return FMRES_IGNORED
	}
	
	for (new i=0;i<3;i++)
	{
		if (containi(model, NADE_MODEL[i]) != -1)
		{
			set_pdata_int(ent, OFFSET_WEAPONID, NADE_WPID[NadeRace:i], EXTRAOFFSET_WEAPONS)
			
			if (bs_forward_collection & FWD_SETMODEL)
				grenade_process(pev(ent, pev_owner), ent, NadeRace:i)
			
			break
		}
	}
	
	return FMRES_IGNORED
}

grenade_process(id, grenade, NadeRace:nade)
{
	if ((cl_is_bot & (1<<(id-1))) && get_option(OPTION_BOT_ALLOW) && grenade_can_be_used(nade))
	{
		// We place the NADE_TRIP last so we can easily make another choice if it doesn't work ;)
		static const NadeType:random_vec[] = {NADE_NORMAL, NADE_IMPACT, NADE_MOTION, NADE_PROXIMITY, NADE_HOMING, NADE_TRIP}
		static NadeType:decision
		
		decision = random_vec[random_num(0, charsmax(random_vec))]
		mode[id][nade] = decision
		
		if (is_mode_enabled(id, mode[id][nade], nade))
		{
			if (decision == NADE_TRIP)
			{
				static loop[4][2] = { {0, 1}, {0, -1}, {1, 1}, {1, -1} }
				// Search in order: axis +X axis -X axis +Y axis -Y axis
				
				new Float:origin[3], Float:end[3], Float:fdest[3], Float:calc_vector[3], Float:height, Float: minimum, Float:distance = 9999999.999, Float:fraction
				new trace = create_tr2()
				
				entity_get_vector(id, EV_VEC_origin, origin)
				
				xs_vec_copy(origin, end)
				end[2] += 16000.0
				
				engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, trace)
				
				get_tr2(trace, TR_vecEndPos, end)
				
				xs_vec_sub(end, origin, end)
				
				height = xs_vec_len(end)
				
				
				xs_vec_copy(origin, end)
				end[2] -= 16000.0
				
				engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, trace)
				
				get_tr2(trace, TR_vecEndPos, end)
				
				xs_vec_sub(end, origin, end)
				
				height += xs_vec_len(end)
				
				if ( height > BOT_FORCE_CROUCH_HEIGHT_CONST)
				{
					minimum = BOT_MIN_HEIGHT_ALLOW
				}
				else
				{
					minimum = BOT_MIN_CROUCH_HEIGHT_ALLOW
					height -= BOT_MIN_CROUCH_HEIGHT_ALLOW
					
				}
				
				if ( height > BOT_MAX_HEIGHT_ALLOW )
				{
					height = BOT_MAX_HEIGHT_ALLOW
				}
				
				if (xs_vec_len(end) < height)
				{
					xs_vec_mul_scalar(end, - random_float(minimum - xs_vec_len(end),height  - xs_vec_len(end)) / xs_vec_len(end), end)
					xs_vec_add(end, origin, origin)
				}
				else
				{
					if (xs_vec_len(end) < height)
					{
						xs_vec_mul_scalar(end,  (xs_vec_len(end) - random_float(minimum, height)) / xs_vec_len(end), end)
						xs_vec_add(end, origin, origin)
					}
					else
					{
						xs_vec_mul_scalar(end, (xs_vec_len(end) - random_float(minimum, height)) / xs_vec_len(end), end)
						xs_vec_add(end, origin, origin)
					}
				}
				
				for(new i=0;i<4;i++)
				{
					// Add search direction
					xs_vec_copy(origin, end)
					end[loop[i][0]] = origin[loop[i][0]] + (16000.0 * float(loop[i][1]))
					
					// Trace to get the entity where we can attach our nade
					engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, trace)
					
					// Get fraction to see if it has hited something
					get_tr2(trace, TR_flFraction, fraction)
					
					if (fraction < 1.0)
					{
						if ( (!is_attachable_surface(get_tr2(trace, TR_pHit))) || get_tr2(trace, TR_AllSolid) )
						{
							continue
						}
						
						// Get plane normal for the wall
						get_tr2(trace, TR_vecPlaneNormal, calc_vector)
						
						// Check if we have a wall
						if ( xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) > BOT_WALL_MIN_COSINUS || xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) < (-BOT_WALL_MIN_COSINUS) )
						{
							continue
						}
						
						// We use the end point for extra calculations
						get_tr2(trace, TR_vecEndPos, end)
						
						xs_vec_sub(origin, end, calc_vector)
						
						if (xs_vec_len(calc_vector) < distance)
						{
							distance = xs_vec_len(calc_vector)
							xs_vec_normalize(calc_vector, calc_vector)
							xs_vec_mul_scalar(calc_vector, 1.5, calc_vector)
							xs_vec_add(end, calc_vector, end)
							xs_vec_copy(end, fdest)
						}
					}
					
				}
				
				for(new i=0;i<2;i++)
				{
					for(new j=2;j<4;j++)
					{
						// Add search direction
						xs_vec_copy(origin, end)
						
						end[loop[i][0]] = origin[loop[i][0]] + (16000.0 * float(loop[i][1]))
						end[loop[j][0]] = origin[loop[j][0]] + (16000.0 * float(loop[j][1]))
						
						engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, trace)
						
						get_tr2(trace, TR_flFraction, fraction)
						
						if (fraction < 1.0)
						{
							if ( (!is_attachable_surface(get_tr2(trace, TR_pHit))) || get_tr2(trace, TR_AllSolid) )
							{
								continue
							}
							
							get_tr2(trace, TR_vecPlaneNormal, calc_vector)
							
							if ( xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) > BOT_WALL_MIN_COSINUS || xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) < (-BOT_WALL_MIN_COSINUS) )
							{
								continue
							}
							
							get_tr2(trace, TR_vecEndPos, end)
							
							xs_vec_sub(origin, end, calc_vector)
							
							if (xs_vec_len(calc_vector) < distance)
							{
								distance = xs_vec_len(calc_vector)
								xs_vec_normalize(calc_vector, calc_vector)
								xs_vec_mul_scalar(calc_vector, 3.0, calc_vector)
								xs_vec_add(end, calc_vector, end)
								xs_vec_copy(end, fdest)
							}
							
						}
						
					}
				}
				
				free_tr2(trace)
				
				xs_vec_sub(fdest, origin, calc_vector)
				
				if (xs_vec_len(calc_vector) <= BOT_MIN_DISTANCE_ATTACH)
				{
					xs_vec_normalize(calc_vector, calc_vector)
					xs_vec_mul_scalar(calc_vector, 20.0, calc_vector)
					entity_set_vector(grenade, EV_VEC_velocity, calc_vector)
					entity_set_int(grenade, EV_INT_movetype, MOVETYPE_FLY)
					entity_set_origin(grenade, fdest)
					set_grenade_type(grenade, mode[id][nade])
					
				}
				else
				{
					decision = random_vec[random_num(0, charsmax(random_vec) - 1)]
					mode[id][nade] = decision
					set_grenade_type(grenade, mode[id][nade])
				}
				
			}
			else
			{
				set_grenade_type(grenade, mode[id][nade])
			}
		}
		else
		{
			mode[id][nade] = NADE_NORMAL
			set_grenade_type(grenade, mode[id][nade])
		}
		
		return
	}
	
	if (get_option(OPTION_ENABLE_NADE_MODES) && is_mode_enabled(id, mode[id][nade], nade) && grenade_can_be_used(nade))
	{
		set_grenade_type(grenade, mode[id][nade])
	}
	
	if (get_option(OPTION_RESET_MODE_ON_THROW))
	{
		mode[id][nade] = NADE_NORMAL
	}
	
	return
}

public fw_spawn(ent)
{
	if (!pev_valid(ent))
		return FMRES_IGNORED
	
	static classname[32]
	pev(ent, pev_classname, classname, charsmax(classname))
	
	if(!TrieKeyExists(trace_attack_reg_class, classname))
	{
		RegisterHam(Ham_TraceAttack, classname, "fw_global_traceattack", 1)
		TrieSetCell(trace_attack_reg_class, classname, true)
	}
	
	return FMRES_IGNORED
}

public fw_track_explosion(grenade)
{
	if (entity_get_float(grenade, EV_FL_dmgtime) > get_gametime())
		return HAM_IGNORED
	
	static NadeType:type, owner, not_count
	owner = entity_get_edict(grenade, EV_ENT_owner)
	type = get_grenade_type(grenade)
	
	if (_:type & NADE_DONT_COUNT)
		not_count = true
	else
		not_count = false
	
	type &= ~NadeType:NADE_DONT_COUNT
	
	if (!is_user_connected(owner) || is_user_connecting(owner) || cl_team[owner] == CS_TEAM_UNASSIGNED)
	{
		entity_set_int(grenade, EV_INT_flags, entity_get_int(grenade, EV_INT_flags) | FL_KILLME)
		return HAM_IGNORED
	}
	
	if (not_count)
	{
		return HAM_IGNORED
	}
	else
	{
		if (get_grenade_race(grenade) == _:GRENADE_SMOKEGREN)
		{
			if (entity_get_float(grenade, EV_FL_animtime) == 0.0)
			{
				return HAM_IGNORED
			}
			else
			{
				entity_set_float(grenade, EV_FL_animtime, 0.0)
			}
			
			clear_line(grenade)
		}
		else
		{
			clear_line(grenade)
		}
		
		if (!(_:UNCOUNTABLE_NADE_MODES & (1 << (_:type + 1))))
			cl_counter[owner][NadeRace:get_grenade_race(grenade)][type] -= 1
		
		entity_set_int(grenade, EV_INT_iuser1, entity_get_int(grenade, EV_INT_iuser1) | NADE_DONT_COUNT)
	}
	
	
	if (!(bs_forward_collection & FWD_SEC_EXPLODE))
		return HAM_IGNORED
	
	new Float:origin[3]
	new Float:range
	entity_get_vector(grenade, EV_VEC_origin, origin)
	range = get_option_float(OPTION_RADIUS_SEC_EXPLOSION)
	
	new i
	i = g_maxplayers
	
	if (!get_option(OPTION_SEC_EXPLO_AFFECT) && get_grenade_race(grenade) == _:GRENADE_EXPLOSIVE)
	{
		while ((i = find_ent_in_sphere(i, origin, range)))
		{
			if (i == grenade)
				continue
			
			if (is_grenade(i))
			{
				if (entity_get_float(i, EV_FL_animtime) == 0.0 && get_grenade_race(i) == _:GRENADE_SMOKEGREN)
				{
					continue
				}
				
				make_explode(i)
				
				if (get_grenade_race(i) == _:GRENADE_SMOKEGREN)
				{
					entity_set_int(i, EV_INT_flags, entity_get_int(i, EV_INT_flags) | FL_ONGROUND)
					dllfunc(DLLFunc_Think, i)
				}
			}
		}
	}
	else
	{
		static race
		race = get_grenade_race(grenade)
		
		while ((i = find_ent_in_sphere(i, origin, range)))
		{
			if (i == grenade)
				continue
			
			if (is_grenade(i))
			{
				if (get_grenade_race(i) == race)
				{
					if (entity_get_float(i, EV_FL_animtime) == 0.0 && race == _:GRENADE_SMOKEGREN)
					{
						continue
					}
					
					make_explode(i)
					
					if (race == _:GRENADE_SMOKEGREN)
					{
						entity_set_int(i, EV_INT_flags, entity_get_int(i, EV_INT_flags) | FL_ONGROUND)
						dllfunc(DLLFunc_Think, i)
					}
				}
			}
		}
	}

	return HAM_IGNORED
}

public fw_think(ent)
{
	if (!(bs_forward_collection & FWD_THINK))
		return HAM_IGNORED
	
	static i, Float:origin[3], Float:porigin[3], trace = 0, Float:fraction, owner, bs_holds
	static Float:radius, affect_owner, team_play
	
	affect_owner = get_option(OPTION_AFFECT_OWNER)
	team_play = get_option(OPTION_TEAM_PLAY)
	
	entity_get_vector(ent, EV_VEC_origin, origin)
	
	owner = entity_get_edict(ent, EV_ENT_owner)
	
	if (!is_user_connected(owner) || is_user_connecting(owner) || cl_team[owner] == CS_TEAM_UNASSIGNED)
	{
		entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_KILLME)
		return HAM_IGNORED
	}
	
	if (entity_get_float(ent, EV_FL_dmgtime) <= get_gametime())
		return HAM_IGNORED
	
	switch (get_grenade_type(ent))
	{
		case NADE_DUD:
		{
			return HAM_SUPERCEDE
		}
		
		case NADE_NORMAL:
		{
			return HAM_IGNORED
		}
		
		case NADE_PROXIMITY:
		{
			if (!allow_grenade_explode(ent))
				return HAM_IGNORED
			
			i = -1
			radius = get_option_float(OPTION_RADIUS_PROXIMITY)
			
			while ((i = find_ent_in_sphere(i, origin, radius)))
			{
				if (i > g_maxplayers)
					return HAM_IGNORED
				
				if (!is_user_alive(i))
					continue
					
				if (i == owner)
				{
					if (affect_owner)
					{
						make_explode(ent)
						return HAM_IGNORED
					}
					else
					{
						continue
					}
				}
				
				if (!team_play)
				{
					make_explode(ent)
					return HAM_IGNORED
				}
				else
				{
					if (cl_team[i] != cl_team[owner])
					{
						make_explode(ent)
						return HAM_IGNORED
					}
				}
			}
			
			return HAM_IGNORED
		}
		
		case NADE_TRIP:
		{
			static hit, Float:point[3], Float:normal[3], Float:temp[3], Float:end[3], Float:fly[3]
			static Float:fly_speed, Float:detect_distance, Float:arm_time
			
			fly_speed = get_option_float(OPTION_TRIP_FLY_SPEED)
			detect_distance = get_option_float(OPTION_TRIP_DETECT_DISTANCE)
			arm_time = get_option_float(OPTION_ARM_TIME_TRIP)
			
			switch (get_trip_grenade_mode(ent))
			{
				case TRIP_NOT_ATTACHED, TRIP_DETONATED:
				{
					return HAM_IGNORED
				}
				
				case TRIP_ATTACHED:
				{
					static loop[6][2] = { {2, 1}, {2, -1}, {0, 1}, {0, -1}, {1, 1}, {1, -1} }
					// Search in order: +Z axis -Z axis +X axis -X axis +Y axis -Y axis
					
					trace = create_tr2()
					
					for (new i; i < 6; i++)
					{
						xs_vec_copy(origin, point)
						
						point[loop[i][0]] = origin[loop[i][0]] + (2.0 * float(loop[i][1]))
						
						engfunc(EngFunc_TraceLine, origin, point, IGNORE_MONSTERS, ent, trace)
						
						get_tr2(trace, TR_flFraction, fraction)
						
						if (fraction < 1.0)
						{
							hit = get_tr2(trace, TR_pHit)
							
							if (!is_attachable_surface(hit))
							{
								set_grenade_type(ent, NADE_DUD)
								free_tr2(trace)
								return HAM_IGNORED
							}
							
							get_tr2(trace, TR_vecPlaneNormal, normal)
							
							set_trip_grenade_attached_to(ent, hit)
							
							// Calculate and store fly velocity.
							xs_vec_mul_scalar(normal, fly_speed, temp)
							set_trip_grenade_fly_velocity(ent, temp)
							
							// Calculate and store endpoint.
							xs_vec_mul_scalar(normal, detect_distance, temp)
							xs_vec_add(temp, origin, end)
							
							// Trace to it
							engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, ent, trace)
							get_tr2(trace, TR_flFraction, fraction)
							
							// Final endpoint with no possible wall collision
							xs_vec_mul_scalar(normal, (detect_distance * fraction), temp)
							xs_vec_add(temp, origin, end)
							set_trip_grenade_end_origin(ent, end)
							
							xs_vec_mul_scalar(temp, 0.5, temp)
							xs_vec_add(temp, origin, temp)
							set_trip_grenade_middle_origin(ent, temp)
							
							set_trip_grenade_arm_time(ent, arm_time)
							
							play_sound(ent, DEPLOY)
							
							entity_set_vector(ent, EV_VEC_velocity, Float:{0.0, 0.0, 0.0}) // Stop if from moving
							
							entity_set_int(ent, EV_INT_sequence, 0) // Otherwise, grenade might make wierd motions.
							
							set_trip_grenade_mode(ent, TRIP_WAITING)
							
							set_task(0.1, "trip_activation", ent)
							
							free_tr2(trace)
							return HAM_IGNORED
						}
					}
					
					// If we reach here, we have serious problems. This means that the grenade hit something like a func_breakable
					// that disappeared before the scan was able to take place. Now, the grenade is floating in mid air. So we just
					// kaboom it!!!
					
					make_explode(ent)
					
					if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
					{
						entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
					}
					
					return HAM_IGNORED
				}
				
				case TRIP_WAITING:
				{
					
					if (!is_attachable_surface(get_trip_grenade_attached_to(ent)))
					{
						make_explode(ent)
					
						if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
						{
							entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
							clear_line(ent)
						}
						
						return HAM_IGNORED
					}
					
					if (get_gametime() > get_trip_grenade_arm_time(ent))
					{
						set_trip_grenade_mode(ent, TRIP_SCANNING)
						play_sound(ent, ACTIVATE)
					}
					
					return HAM_IGNORED
				}
				
				case TRIP_SCANNING:
				{
					if (!is_attachable_surface(get_trip_grenade_attached_to(ent)))
					{
						make_explode(ent)
						
						if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
						{
							entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
							clear_line(ent)
						}
						
						return HAM_IGNORED
					}
					
					trace = create_tr2()
					
					get_trip_grenade_end_origin(ent, end)
					engfunc(EngFunc_TraceLine, end, origin, DONT_IGNORE_MONSTERS, 0, trace)
					
					static target
					target = get_tr2(trace, TR_pHit)
					
					if (is_user_alive(target))
					{
						if (owner == target)
						{
							if (affect_owner)
							{
								set_trip_grenade_mode(ent, TRIP_SHOULD_DETONATE)
								free_tr2(trace)
								entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
								return HAM_IGNORED
							}
							else
							{
								free_tr2(trace)
								entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
								return HAM_IGNORED
							}
						}
						
						if (!team_play)
						{
							set_trip_grenade_mode(ent, TRIP_SHOULD_DETONATE)
						}
						else
						{
							if (cl_team[owner] != cl_team[target])
								set_trip_grenade_mode(ent, TRIP_SHOULD_DETONATE)
						}
					}
					
					free_tr2(trace)
					entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
					return HAM_IGNORED
				}
				
				case TRIP_SHOULD_DETONATE:
				{
					static mode
					mode = get_trip_grenade_react_method(ent)
					set_trip_grenade_mode(ent, TRIP_DETONATED)
					
					clear_line(ent)
					play_sound(ent, ACTIVATE)
					
					if (mode == 0)
					{
						cl_counter[owner][NadeRace:get_grenade_race(ent)][NADE_TRIP] -= 1
						get_trip_grenade_fly_velocity(ent, fly)
						get_trip_grenade_end_origin(ent, end)
						entity_set_vector(ent, EV_VEC_velocity, fly) 			// Send the grenade on its way.
						set_grenade_type(ent, NADE_IMPACT)		 				// Kaboom!
					}
					else
					{
						make_explode(ent)
						
						if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
						{
							entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
							clear_line(ent)
						}
					}
					
					return HAM_IGNORED
				}
			}
		}
		
		case NADE_MOTION:
		{
			if (!allow_grenade_explode(ent))
				return HAM_IGNORED
			
			static Float:v[3], Float:velocity
			
			i = -1
			bs_holds = 0
			trace = create_tr2()
			radius = get_option_float(OPTION_RADIUS_MOTION)
			
			while ((i = find_ent_in_sphere(i, origin, radius)))
			{
				if (i >= g_maxplayers)
				{
					entity_set_int(ent, EV_INT_iuser2, bs_holds)
					free_tr2(trace)
					return HAM_IGNORED
				}
				
				if (!is_user_alive(i))
					continue
				
				entity_get_vector(i, EV_VEC_origin, porigin)
				
				engfunc(EngFunc_TraceLine, origin, porigin, IGNORE_MONSTERS, 0, trace)
				get_tr2(trace, TR_flFraction, fraction)
				
				if (fraction < 1.0)
					continue
				
				entity_get_vector(i, EV_VEC_velocity, v)
				velocity = xs_vec_len(v)
				
				if (velocity > 200.0)
				{
					if (i == owner)
					{
						if (affect_owner)
						{
							make_explode(ent)
							free_tr2(trace)
							return HAM_IGNORED
						}
						else
						{
							bs_holds |= (1<<(i-1))
							continue
						}
					}
					if (!team_play)
					{
						make_explode(ent)
						free_tr2(trace)
						return HAM_IGNORED
					}
					else
					{
						if (cl_team[i] != cl_team[owner])
						{
							make_explode(ent)
							free_tr2(trace)
							return HAM_IGNORED
						}
					}
					
					bs_holds |= (1<<(i-1))
					entity_set_int(ent, EV_INT_iuser2, bs_holds)
					play_sound(ent, GEIGER)
				}
				else if (velocity == 0.0)
				{
					continue
				}
				else
				{
					play_sound(ent, GEIGER)
					
					// Add the player to the bitsum if he is moving
					bs_holds |= (1<<(i-1))
				}
				
			}
			
			entity_set_int(ent, EV_INT_iuser2, bs_holds)
			free_tr2(trace)
			return HAM_IGNORED
		}
		
		case NADE_SATCHEL:
		{
			if (!allow_grenade_explode(ent))
				return HAM_IGNORED
			
			if (entity_get_int(owner, EV_INT_button) & IN_USE)
			{
				make_explode(ent)
				
				if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
				{
					entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
				}
			}
			
			
			return HAM_IGNORED
		}
		
		case NADE_HOMING:
		{
			static target, Float:extravel
			target = entity_get_int(ent, EV_INT_iuser2)
			extravel = get_option_float(OPTION_HOMING_SPEED_ADD)
			
			if (target == 0)
			{
				static i, Float:distance
				i = -1
				distance = get_option_float(OPTION_HOMING_SCAN_RANGE)
				
				while ((i = find_ent_in_sphere(i, origin, distance)))
				{
					if (!is_user_alive(i))
						continue
					
					if (i == owner)
						continue
					
					if ((cl_team[i] != cl_team[owner] && team_play) || !team_play)
					{
						static Float:o[3]
						entity_get_vector(i, EV_VEC_origin, o)
						static Float:new_distance
						new_distance = get_distance_f(o, origin)
						
						if (new_distance < distance)
						{
							distance = new_distance
							entity_set_int(ent, EV_INT_iuser2, i)
						}
					}
				}
				
				return HAM_IGNORED
			}
			else if (!is_user_alive(target))
			{
				return HAM_IGNORED
			}
			else if (is_in_los(ent, target))
			{
				//set_user_rendering(target)
				static Float:velocity[3], Float:aim[3], Float:targetorigin[3], Float:velocity_normal[3], Float:aim_normal[3]
				
				entity_get_vector(target, EV_VEC_origin, targetorigin)
				
				entity_get_vector(ent, EV_VEC_velocity, velocity)
				
				xs_vec_sub(targetorigin, origin, aim)
				
				xs_vec_normalize(velocity, velocity_normal)
				xs_vec_normalize(aim, aim_normal)
				
				play_sound(ent, PING)
				
				if (velocity_normal[0] < aim_normal[0])
				{
					velocity[0] += extravel
				}
				else if (velocity_normal[0] > aim_normal[0])
				{
					velocity[0] -= extravel
				}
				
				if (velocity_normal[1] < aim_normal[1])
				{
					velocity[1] += extravel
				}
				else if (velocity_normal[1] > aim_normal[1])
				{
					velocity[1] -= extravel
				}
				
				if (velocity_normal[2] < aim_normal[2])
				{
					velocity[2] += extravel
				}
				else if (velocity_normal[2] > aim_normal[2])
				{
					velocity[2] -= extravel
				}
				
				velocity[2] += 5.0
				
				entity_set_vector(ent, EV_VEC_velocity, velocity)
				
				// When within blasting range, make our homing grenade think much much faster; results in better homing.
				if (get_distance_f(origin, targetorigin) < get_option_float(OPTION_HOMING_SUPER_RANGE))
				{
					entity_set_float(ent, EV_FL_nextthink, (get_gametime() + 0.05))
				}
				else
				{
					entity_set_float(ent, EV_FL_nextthink, (get_gametime() + 0.15))
				}
			}
			
			return HAM_IGNORED
		}
	}
	
	return HAM_IGNORED
}

public trip_activation(ent)
{
	if (is_valid_ent(ent))
		play_sound(ent, CHARGE)
}

public fw_think_post(ent)
{
	if (!(bs_forward_collection & FWD_THINK_POST))
		return HAM_IGNORED
	
	if (!is_valid_ent(ent))
		return HAM_IGNORED
	
	static owner, Float:origin[3], Float:gametime
	
	gametime = get_gametime()
	
	if (entity_get_float(ent, EV_FL_dmgtime) <= gametime)
		return HAM_IGNORED
	
	entity_get_vector(ent, EV_VEC_origin, origin)
	owner = entity_get_edict(ent, EV_ENT_owner)
	
	if (!is_user_connected(owner) || is_user_connecting(owner) || cl_team[owner] == CS_TEAM_UNASSIGNED)
	{
		entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_KILLME)
		return HAM_IGNORED
	}
	
	switch (get_grenade_type(ent))
	{
		case NADE_PROXIMITY:
		{
			if (!allow_grenade_explode(ent))
				return HAM_IGNORED
			
			if (entity_get_float(ent, EV_FL_fuser4) <= gametime)
			{						
				entity_set_float(ent, EV_FL_fuser4, gametime + 2.0)
				
				if (entity_get_int(ent, EV_INT_flags) & FL_ONGROUND)
				{
					if (!get_option(OPTION_TEAM_PLAY))
					{
						if (get_option(OPTION_RESOURCE_USE) == 1)
						{
							show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5)
						}
						else
						{
							static i
							i = -1
							
							while ( (i = find_ent_in_sphere(i, origin, SMART_RADIUS_RING_SHOW)) )
							{
								if (i > g_maxplayers)
									break
								
								if (!is_user_alive(i) || (cl_is_bot & (1<<(i-1))))
									continue
								
								show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, _, _, _, i)
							}
						}
					}
					else
					{
						switch (cl_team[owner])
						{
							case CS_TEAM_T: 
							{
								if (get_option(OPTION_RESOURCE_USE) == 1)
								{
									show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR)
								}
								else
								{
									static i
									i = -1
									
									while ( (i = find_ent_in_sphere(i, origin, SMART_RADIUS_RING_SHOW)) )
									{
										if (i > g_maxplayers)
											break
										
										if (!is_user_alive(i) || (cl_is_bot & (1<<(i-1))))
											continue
										
										show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, i)
									}
								}
								
							}
							case CS_TEAM_CT:
							{
								if (get_option(OPTION_RESOURCE_USE) == 1)
								{
									show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR)
								}
								else
								{
									static i
									i = -1
									
									while ( (i = find_ent_in_sphere(i, origin, SMART_RADIUS_RING_SHOW)) )
									{
										if (i > g_maxplayers)
											break
										
										if (!is_user_alive(i) || (cl_is_bot & (1<<(i-1))))
											continue
										
										show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, i)
									}
								}
							}
						}
					}
				}
			}
		}
		
		case NADE_MOTION:
		{
			static bs_holds
			bs_holds = entity_get_int(ent, EV_INT_iuser2)
			
			if (bs_holds && entity_get_float(ent, EV_FL_fuser4) <= gametime)
			{
				entity_set_float(ent, EV_FL_fuser4, get_gametime() + 0.1)
				
				if (!get_option(OPTION_TEAM_PLAY))
				{
					if ( get_option(OPTION_RESOURCE_USE) == 1)
					{
						show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1)
					}
					else
					{
						for (new i=1;i<=g_maxplayers;i++)
						{
							if (bs_holds & (1<<(i-1)))
								show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, _, _, _, i)
						}
					}
				}
				else
				{
					switch (cl_team[owner])
					{
						case CS_TEAM_T:
						{
							if ( get_option(OPTION_RESOURCE_USE) == 1 )
							{
								show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR)
							}
							else
							{
								for (new i=1;i<=g_maxplayers;i++)
								{
									if (bs_holds & (1<<(i-1)))
										show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, i)
								}
							}
						}
						case CS_TEAM_CT:
						{
							if ( get_option(OPTION_RESOURCE_USE) == 1 )
							{
								show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR)
							}
							else
							{
								for (new i=1;i<=g_maxplayers;i++)
								{
									if (bs_holds & (1<<(i-1)))
										show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, i)
								}
							}
						}
						default:
						{
							if ( get_option(OPTION_RESOURCE_USE) == 1 )
							{
								show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, _, _, _)
							}
							else
							{
								for (new i=1;i<=g_maxplayers;i++)
								{
									if (bs_holds & (1<<(i-1)))
										show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, _, _, _, i)
								}
							}
						}
					}
				}
			}
		}
		
		case NADE_TRIP:
		{
			if (get_trip_grenade_mode(ent) != TRIP_SCANNING)
				return HAM_IGNORED
			
			// We do this in order to make the trip nades be 10000% more accurate!
			entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
			
			if (entity_get_float(ent, EV_FL_fuser4) <= gametime)
			{
				new Float:end[3]
				get_trip_grenade_end_origin(ent, end)
				
				if (get_option(OPTION_RESOURCE_USE) == 1)
				{
					if (!get_option(OPTION_TEAM_PLAY))
					{
						draw_line_from_entity_broadcast(ent, end, 5, _, _, _)
					}
					else
					{
						switch (cl_team[owner])
						{
							case CS_TEAM_T:
							{
								draw_line_from_entity_broadcast(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR)
							}
							case CS_TEAM_CT:
							{
								draw_line_from_entity_broadcast(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR)
							}
							default:
							{
								draw_line_from_entity_broadcast(ent, end, 5, _, _, _)
							}
						}
					}
					
					entity_set_float(ent, EV_FL_fuser4, gametime + 0.5)
					return HAM_IGNORED
				}
				
				static  Float:first[3], Float:second[3], Float:porigin[3], Float:anglefraction, Float:third[3], Float:fourth[3]
				
				xs_vec_sub(origin,end,first)
				anglefraction = angle_fraction_by_distance(xs_vec_len(first))
				
				if (xs_vec_len(first) <= 800.0)
				{
					get_trip_grenade_middle_origin(ent, first) 
					
					if (!get_option(OPTION_TEAM_PLAY))
					{
						draw_line_from_entity(ent, end, 5, _, _, _, 0, first)
					}
					else
					{
						switch (cl_team[owner])
						{
							case CS_TEAM_T:
							{
								draw_line_from_entity(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, 0, first)
							}
							case CS_TEAM_CT:
							{
								draw_line_from_entity(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, 0, first)
							}
							default:
							{
								draw_line_from_entity(ent, end, 5, _, _, _, 0, first)
							}
						}
					}
					
					entity_set_float(ent, EV_FL_fuser4, gametime + 0.5)
					return HAM_IGNORED
				}
				
				xs_vec_mul_scalar(first,EXTRALENGTH_VECTOR / xs_vec_len(first),first)
				xs_vec_sub(end,first,fourth)
				xs_vec_add(origin,first,first)
				
				static players[32],num,id
				get_players(players,num,"ac")
				
				for (new i=0;i<num;i++)
				{
					id = players[i]
					entity_get_vector(id, EV_VEC_origin, porigin)
					
					xs_vec_sub(porigin, fourth, second)
					xs_vec_normalize(second, second)
					
					xs_vec_sub(porigin, first, third)
					xs_vec_normalize(third, third)
					
					xs_vec_sub(first,fourth,first)
					xs_vec_normalize(first,first)
					
					if ( xs_vec_dot(first,second) <= CONE_DROP_ANGLE_COSINUS || (0 - xs_vec_dot(first,third)) <= CONE_DROP_ANGLE_COSINUS )
						continue
					
					if ( xs_vec_dot(first, second) >= anglefraction )
					{
						if (!get_option(OPTION_TEAM_PLAY))
						{
							draw_line_from_entity(ent, end, 5, _, _, _, id)
						}
						else
						{
							switch (cl_team[owner])
							{
								case CS_TEAM_T:
								{
									draw_line_from_entity(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, id)
								}
								case CS_TEAM_CT:
								{
									draw_line_from_entity(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, id)
								}
								default:
								{
									draw_line_from_entity(ent, end, 5, _, _, _, id)
								}
							}
						}
					}
					else
					{
						if ( (0 - xs_vec_dot(first, third)) >= anglefraction )
						{
							if (!get_option(OPTION_TEAM_PLAY))
							{
								draw_line_from_entity(ent, end, 5, _, _, _, id)
							}
							else
							{
								switch (cl_team[owner])
								{
									case CS_TEAM_T:
									{
										draw_line_from_entity(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, id)
									}
									case CS_TEAM_CT:
									{
										draw_line_from_entity(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, id)
									}
									default:
									{
										draw_line_from_entity(ent, end, 5, _, _, _, id)
									}
								}
							}
						}
					}
				}
				
				entity_set_float(ent, EV_FL_fuser4, gametime + 0.5)
				
			}
		}
		
		default : return HAM_IGNORED
	}
	
	return HAM_IGNORED
}

public fw_touch(toucher, touched)
{
	if (!(bs_forward_collection & FWD_TOUCH))
		return HAM_IGNORED
	
	switch (get_grenade_type(toucher))
	{
		case NADE_IMPACT:
		{
			if (is_solid(touched))
			{
				make_explode(toucher)
				
				entity_set_float(toucher, EV_FL_nextthink, get_gametime() + 0.001)
				
				if (NadeRace:get_grenade_race(toucher) == GRENADE_SMOKEGREN)
				{
					entity_set_int(toucher, EV_INT_flags, entity_get_int(toucher, EV_INT_flags) | FL_ONGROUND)
				}
			}
		}
		
		case NADE_TRIP:
		{
			static classname[10]
			entity_get_string(touched, EV_SZ_classname, classname, charsmax(classname))
			
			if (get_trip_grenade_mode(toucher) > TRIP_NOT_ATTACHED || is_user_connected(touched))
			{
				return HAM_IGNORED
			}
			else
			{
				if (is_solid(touched))
				{
					entity_set_int(toucher, EV_INT_movetype, MOVETYPE_NONE)
					set_trip_grenade_mode(toucher, TRIP_ATTACHED)
					return (containi(classname, "door") != -1) ? HAM_SUPERCEDE : HAM_IGNORED
				}
			}
		}
	}
	
	return HAM_IGNORED
}

public fw_takedamage(victim, inflictor, attacker, Float:damage, damagebits)
{
	if (!(bs_forward_collection & FWD_TAKEDAMAGE))
		return HAM_IGNORED
	
	static aclassname[7], iclassname[8]
	
	entity_get_string(attacker,  EV_SZ_classname, aclassname, charsmax(aclassname))
	entity_get_string(inflictor,  EV_SZ_classname, iclassname, charsmax(iclassname))
	
	if ((damagebits & DMG_BLAST))
		return HAM_IGNORED
	
	if (!equal(aclassname, "player") || !equal(iclassname, "grenade"))
		return HAM_IGNORED
	
	if (attacker == victim)
	{
		damage *= (get_option_float(OPTION_DMG_SELF) / 100.0)
	}
	else
	{
		if (cl_team[attacker] == cl_team[victim] && get_option(OPTION_FRIENDLY_FIRE))
		{
			damage *= 0.02 * get_option_float(OPTION_DMG_TEAMMATES)
		}
	}
	
	static trace, Float:origin[3], Float:user_origin[3], Float:fraction
	trace = create_tr2()
	entity_get_vector(victim, EV_VEC_origin, user_origin)
	entity_get_vector(inflictor, EV_VEC_origin, origin)
	origin[2] += 2.0
	engfunc(EngFunc_TraceLine, user_origin, origin, IGNORE_MONSTERS, victim, trace)

	get_tr2(trace, TR_flFraction, fraction)
	
	if (fraction < 1.0)
	{
		damage *= (get_option_float(OPTION_DMG_THROUGH_WALL) / 100.0)
	}
	
	free_tr2(trace)
	
	if ( get_option(OPTION_DAMAGE_SYSTEM) == 1)
	{
		damage *= get_option_float(OPTION_DMG_NORMAL)
	}
	else
	{
		new type = _:get_grenade_type(inflictor)
		type &= ~NADE_DONT_COUNT
		
		switch ( type )
		{
			case NADE_NORMAL:
			{
				damage *= get_option_float(OPTION_DMG_NORMAL)
			}
			
			case NADE_PROXIMITY:
			{
				damage *= get_option_float(OPTION_DMG_PROXIMITY)
			}
			
			case NADE_IMPACT:
			{
				damage *= get_option_float(OPTION_DMG_IMPACT)
			}
			
			case NADE_TRIP:
			{
				damage *= get_option_float(OPTION_DMG_TRIP)
			}
			
			case NADE_MOTION:
			{
				damage *= get_option_float(OPTION_DMG_MOTION)
			}
			
			case NADE_SATCHEL:
			{
				damage *= get_option_float(OPTION_DMG_SATCHEL)
			}
			
			case NADE_HOMING:
			{
				damage *= get_option_float(OPTION_DMG_HOMING)
			}
			
			default:
			{
				damage *= get_option_float(OPTION_DMG_NORMAL)
			}
		}
	}
	
	SetHamParamFloat(4, damage)
	
	return HAM_HANDLED
}

public fw_grenade_takedamage(grenade, inflictor, attacker, Float:damage, bits)
{
	if (!(bs_forward_collection & FWD_HPSYSTEM))
		return HAM_IGNORED
	
	if (inflictor == grenade)
	{
		SetHamReturnInteger(0)
		return HAM_SUPERCEDE
	}
	
	new Float:health, Float:origin[3], ok = false
	health = entity_get_float(grenade, EV_FL_health)
	
	if (!(1 <= attacker <= g_maxplayers))
		return HAM_SUPERCEDE
	
	entity_get_vector(grenade, EV_VEC_origin, origin)
	
	if (entity_get_edict(grenade, EV_ENT_owner) != attacker && cl_team[entity_get_edict(grenade, EV_ENT_owner)] == cl_team[attacker])
	{
		damage *= get_option_float(OPTION_HITPOINT_FF) / 100.0
		ok = true
	}
	
	new string[8]
	entity_get_string(inflictor, EV_SZ_classname, string, charsmax(string))
	
	if (equal(string,"grenade"))
	{
		damage *= get_option_float(OPTION_HITPOINT_INTER_DMG) / 100.0
		ok = true
	}
	
	play_sound2(grenade, SOUND_HIT[random_num(0,4)])
	
	if (floatcmp(damage,health) != -1)
	{
		static NadeType:type, owner
		owner = entity_get_edict(grenade, EV_ENT_owner)
		type = get_grenade_type(grenade)
		type &= ~NadeType:NADE_DONT_COUNT
		
		if (get_option(OPTION_HITPOINT_DEATH))
		{
			make_explode(grenade)
			
			if (NadeRace:get_grenade_race(grenade) == GRENADE_SMOKEGREN)
			{
				entity_set_int(grenade, EV_INT_flags, entity_get_int(grenade, EV_INT_flags) | FL_ONGROUND)
				dllfunc(DLLFunc_Think, grenade)
				clear_line(grenade)
			}
			
			return HAM_SUPERCEDE
		}
		
		entity_set_int(grenade, EV_INT_flags, entity_get_int(grenade, EV_INT_flags) | FL_KILLME)
		cl_counter[owner][NadeRace:get_grenade_race(grenade)][type] -= 1
		
		if (get_option(OPTION_RESOURCE_USE))
			metal_gibs(origin)
		
		clear_line(grenade)
		
		return HAM_SUPERCEDE
	}
	
	if (ok)
	{
		SetHamParamFloat(4, damage)
		return HAM_HANDLED
	}
	
	return HAM_IGNORED
}

public fw_traceline(Float:start[3], Float:end[3], conditions, id, trace)
{
	if (!(bs_forward_collection & FWD_HPSYSTEM))
		return FMRES_IGNORED
	
	if (!is_user_alive(id))
		return FMRES_IGNORED
	
	if (cl_weapon[id] != CSW_KNIFE)
		return FMRES_IGNORED
	
	if (pev_valid(get_tr2(trace,TR_pHit)))
		return FMRES_IGNORED
	
	static Float:vec_end[3], i
	i = g_maxplayers
	
	get_tr2(trace, TR_vecEndPos, vec_end)
	
	while ((i = find_ent_in_sphere(i, vec_end, SHOT_SECOND_TEST_RADIUS)))
	{
		if (is_grenade(i))
		{
			static Float:origin[3]
			pev(i,pev_origin,origin)
			xs_vec_sub(origin,vec_end,origin)
			if (xs_vec_len(origin) > SHOT_KNIFE_REAL_RADIUS)
				continue
			
			set_tr2(trace, TR_pHit, i)
			break
		}
	}
	
	return FMRES_HANDLED
}

public fw_global_traceattack(ent, attacker, Float:damage, Float:direction[3], tracehdl, damagebits)
{
	if (!(bs_forward_collection & FWD_HPSYSTEM))
		return FMRES_IGNORED
	
	if (attacker > g_maxplayers || attacker < 1)
		return HAM_IGNORED
	
	if (cl_weapon[attacker] == CSW_KNIFE)
		return HAM_IGNORED
	
	static Float:origin[3],Float:offs[3]
	pev(attacker,pev_origin,origin)
	pev(attacker,pev_view_ofs,offs)
	xs_vec_add(origin,offs,origin)
	
	static Float:end[3], Float:point[3], Float:origin_nade[3], Float:track[3]
	get_tr2(tracehdl,TR_vecEndPos,end)
	
	xs_vec_sub(end,origin,point)
	xs_vec_mul_scalar(point, SHOT_PENETRATION_DISTANCE / xs_vec_len(point), point)
	xs_vec_add(end, point, end)
	
	new trace = create_tr2()
	
	static grenade
	static bool:ok
	static bool:reset_queue
	
	grenade = -1
	reset_queue = false
	
	while ((grenade = find_ent_by_class(grenade,"grenade")))
	{
		ok = false
		entity_get_vector(grenade, EV_VEC_origin, origin_nade)
		
		for (new i=0;i<SHOT_ENTITY_QUEUE_LENGTH;i++)
		{
			if (grenade == cl_entity_queue[attacker][i])
			{
				cl_entity_queue[attacker][i] = 0;
				ok = true;
				reset_queue = true;
				break;
			}
		}
		
		if (ok)
		{
			continue;
		}
		
		engfunc(EngFunc_TraceModel,origin,end,HULL_POINT,grenade,trace)
		
		if(get_tr2(trace,TR_pHit) == grenade)
		{
			ExecuteHamB(Ham_TraceAttack, grenade, attacker, damage, direction, trace, damagebits)
			
			insert_in_queue(attacker, grenade)
		}
		else
		{
			new times = 1
			
			xs_vec_sub(origin_nade, end, track)
			
			while (times != SHOT_PENETRATION_READD_TIMES + 1 && xs_vec_len(track) > SHOT_SECOND_TEST_RADIUS)
			{
				xs_vec_add(end, point, track)
				
				for (new i=1;i<=times;++i)
				{
					xs_vec_add(track, point, track)
				}
				
				xs_vec_sub(origin_nade, track, track)
				
				times++;
			}
			
			if ( xs_vec_len(track) <= SHOT_SECOND_TEST_RADIUS )
			{
				set_tr2(trace, TR_pHit, grenade)
				
				xs_vec_add(origin_nade, track, track)
				set_tr2(trace, TR_vecEndPos, track)
				
				ExecuteHamB(Ham_TraceAttack, grenade, attacker, (damage / 2), direction, trace, damagebits)
				
				insert_in_queue(attacker, grenade)
			}
		}
	}
	
	if (reset_queue)
	{
		for (new i=0;i<SHOT_ENTITY_QUEUE_LENGTH;i++)
		{
			cl_entity_queue[attacker][i] = 0
		}
	}
	
	free_tr2(trace)
	
	return HAM_IGNORED
}

/* -------------------------------
[Plugin Zombie Mod Compatibility Forwards]
------------------------------- */
public zp_user_infected_post(id, infector)
{
	// Reset the mode on infection
	mode[id][GRENADE_EXPLOSIVE] = NADE_NORMAL
	mode[id][GRENADE_FLASHBANG] = NADE_NORMAL
	mode[id][GRENADE_SMOKEGREN] = NADE_NORMAL
	
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_MOTION] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_TRIP] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_MOTION] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_TRIP] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_MOTION] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_TRIP] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_SATCHEL] = 0
	
	static ent
	ent = -1
	
	// Get all the grenade entities
	while ((ent = find_ent_by_class(ent, "grenade")))
	{
		if (entity_get_edict(ent, EV_ENT_owner) != id)
			continue
		
		// Set the remove property if they aren't normal nades
		if(is_grenade(ent) && get_grenade_type(ent) != NADE_NORMAL)
			entity_set_int(ent, EV_INT_flags , entity_get_int(ent, EV_INT_flags) | FL_KILLME)
	}	
	
	return PLUGIN_CONTINUE
}

public event_infect(id, attacker)
{
	// Reset the mode on infection
	mode[id][GRENADE_EXPLOSIVE] = NADE_NORMAL
	mode[id][GRENADE_FLASHBANG] = NADE_NORMAL
	mode[id][GRENADE_SMOKEGREN] = NADE_NORMAL
	
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_MOTION] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_TRIP] = 0
	cl_counter[id][GRENADE_EXPLOSIVE][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_MOTION] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_TRIP] = 0
	cl_counter[id][GRENADE_FLASHBANG][NADE_SATCHEL] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_MOTION] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_PROXIMITY] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_TRIP] = 0
	cl_counter[id][GRENADE_SMOKEGREN][NADE_SATCHEL] = 0
	
	static ent
	ent = -1
	
	// Get all the grenade entities
	while ((ent = find_ent_by_class(ent, "grenade")))
	{
		if (entity_get_edict(ent, EV_ENT_owner) != id)
			continue
		
		// Set the remove property if they aren't normal nades
		if(is_grenade(ent) && get_grenade_type(ent) != NADE_NORMAL)
			entity_set_int(ent, EV_INT_flags , entity_get_int(ent, EV_INT_flags) | FL_KILLME)
	}	
	
	return PLUGIN_CONTINUE
}

/* -------------------------------
[Usefull Functions -> NadeMode Tolls]
------------------------------- */
public is_mode_enabled(id, NadeType:type, NadeRace:nade)
{
	switch (type)
	{
		case NADE_NORMAL:
		{
			return 1
		}
		
		case NADE_PROXIMITY:
		{
			if (!get_option(OPTION_PROXIMITY_ENABLED))
				return 0
			
			if ( !(collection[id][nade] & (1 << (_:type - 1))) )
				return 0
			
			if (!get_option(OPTION_LIMIT_SYSTEM))
				return 1
			
			if (!get_option(OPTION_LIMIT_PROXIMITY))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_PROXIMITY))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_PROXIMITY))
				return 1
			
			return 0
		}
		
		case NADE_IMPACT:
		{
			if ( !(collection[id][nade] & (1 << (_:type - 1))) )
				return 0
			
			return get_option(OPTION_IMPACT_ENABLED)
		}
		
		case NADE_TRIP:
		{
			if (!get_option(OPTION_TRIP_ENABLED))
				return 0
			
			if ( !(collection[id][nade] & (1 << (_:type - 1))) )
				return 0
			
			if (!get_option(OPTION_LIMIT_SYSTEM))
				return 1
			
			if (!get_option(OPTION_LIMIT_TRIP))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_TRIP))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_TRIP))
				return 1
			
			return 0
		}
		
		case NADE_MOTION:
		{
			if (!get_option(OPTION_MOTION_ENABLED))
				return 0
			
			if ( !(collection[id][nade] & (1 << (_:type - 1))) )
				return 0
			
			if (!get_option(OPTION_LIMIT_SYSTEM))
				return 1
			
			if (!get_option(OPTION_LIMIT_MOTION))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_MOTION))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_MOTION))
				return 1
			
			return 0
		}
		
		case NADE_SATCHEL:
		{
			if (!get_option(OPTION_SATCHEL_ENABLED))
				return 0
			
			if ( !(collection[id][nade] & (1 << (_:type - 1))) )
				return 0
			
			if (!get_option(OPTION_LIMIT_SYSTEM))
				return 1
			
			if (!get_option(OPTION_LIMIT_SATCHEL))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_SATCHEL))
				return 1
			
			if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_SATCHEL))
				return 1
			
			return 0
		}
		
		case NADE_HOMING:
		{
			if ( !(collection[id][nade] & (1 << (_:type - 1))) )
				return 0
			
			return get_option(OPTION_HOMING_ENABLED)
		}
	}
	
	return 1
}

public changemode(id, NadeRace:NADE_TYPE)
{
	if (!(grenade_can_be_used(NADE_TYPE)))
	{
		return
	}
	
	if (!is_mode_enabled(id, ++mode[id][NADE_TYPE], NADE_TYPE))
	{
		changemode(id, NADE_TYPE)
		return
	}
	
	switch (mode[id][NADE_TYPE])
	{
		case NADE_NORMAL:
		{
			client_print(id, print_center, "Mode - Normal")
		}
		
		case NADE_PROXIMITY:
		{
			client_print(id, print_center, "Mode - Proximity")
		}
		
		case NADE_IMPACT:
		{
			client_print(id, print_center, "Mode - Impact")
		}
		
		case NADE_TRIP:
		{
			client_print(id, print_center, "Mode - Trip laser")
		}
		
		case NADE_MOTION:
		{
			client_print(id, print_center, "Mode - Motion sensor")
		}
		
		case NADE_SATCHEL:
		{
			client_print(id, print_center, "Mode - Satchel charge")
		}
		
		case NADE_HOMING:
		{
			client_print(id, print_center, "Mode - Homing")
		}
		
		default:
		{
			mode[id][NADE_TYPE] = NADE_NORMAL
			client_print(id, print_center, "Mode - Normal")
		}
	}
}

/* -------------------------------
[Usefull Functions -> Grenade Property Set/Get]
------------------------------- */
public is_grenade(ent)
{
	if (!is_valid_ent(ent))
	{
		return 0
	}
	
	static weapon_id
	weapon_id = cs_get_weapon_id(ent)
	
	for (new i=0;i<3;i++)
	{
		if (weapon_id == NADE_WPID[NadeRace:i])
			return 1
	}
	
	return 0
}

public get_grenade_race(grenade)
{
	switch (cs_get_weapon_id(grenade))
	{
		case CSW_HEGRENADE: 	return _:GRENADE_EXPLOSIVE
		case CSW_FLASHBANG: 	return _:GRENADE_FLASHBANG
		case CSW_SMOKEGRENADE: 	return _:GRENADE_SMOKEGREN
	}
	
	return -1
}

set_grenade_type(grenade, NadeType:g_type, bool:property = true)
{
	if (!is_valid_ent(grenade)) return
	
	static NadeRace:nade
	static owner
	
	owner = entity_get_edict(grenade, EV_ENT_owner)
	
	nade = NadeRace:get_grenade_race(grenade)
	
	// Set grenade properties and empty the slots so we can put some info
	entity_set_int(grenade, EV_INT_iuser1, _:g_type)
	entity_set_int(grenade, EV_INT_iuser2, 0)
	entity_set_int(grenade, EV_INT_iuser3, 0)
	entity_set_int(grenade, EV_INT_iuser4, 0)
	
	entity_set_vector(grenade, EV_VEC_vuser1, Float:{0.0, 0.0, 0.0})
	entity_set_vector(grenade, EV_VEC_vuser2, Float:{0.0, 0.0, 0.0})
	entity_set_vector(grenade, EV_VEC_vuser3, Float:{0.0, 0.0, 0.0})
	entity_set_vector(grenade, EV_VEC_vuser4, Float:{0.0, 0.0, 0.0})
	
	if (property == true)
	{
		switch (g_type)
		{
			case NADE_DUD:
			{
				entity_set_int(grenade, EV_INT_movetype, MOVETYPE_BOUNCE)
				entity_set_vector(grenade, EV_VEC_velocity, Float:{0.0, 0.0, 0.0})
			}
			
			case NADE_NORMAL:
			{
				entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_NORMAL)))
				
				if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_NORMAL))
				{
					entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
				}
			}
			
			case NADE_PROXIMITY:
			{
				delay_explosion(grenade)
				set_grenade_allow_explode(grenade, get_option_float(OPTION_ARM_TIME_PROXIMITY))
				
				entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_PROXIMITY)))
				
				if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_PROXIMITY))
				{
					entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
				}
				
				cl_counter[owner][nade][NADE_PROXIMITY] += 1
			}
			
			case NADE_IMPACT:
			{
				delay_explosion(grenade)
				entity_set_int(grenade, EV_INT_movetype, MOVETYPE_BOUNCE)
				
				entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_IMPACT)))
				
				if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_IMPACT))
				{
					entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
				}
			}
			
			// I don't recommend setting a grenade to trip if it was another type in the first place.
			case NADE_TRIP:
			{
				delay_explosion(grenade)
				
				entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_TRIP)))
				
				if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_TRIP))
				{
					entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
				}
				
				cl_counter[owner][nade][NADE_TRIP] += 1
			}
			
			case NADE_MOTION:
			{
				delay_explosion(grenade)
				set_grenade_allow_explode(grenade, get_option_float(OPTION_ARM_TIME_MOTION))
				
				entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_MOTION)))
				
				if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_MOTION))
				{
					entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
				}
				
				cl_counter[owner][nade][NADE_MOTION] += 1
			}
			
			case NADE_SATCHEL:
			{
				delay_explosion(grenade)
				set_grenade_allow_explode(grenade,  get_option_float(OPTION_ARM_TIME_SATCHEL))
				
				entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_SATCHEL)))
				
				if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_SATCHEL))
				{
					entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
				}
				
				cl_counter[owner][nade][NADE_SATCHEL] += 1
			}
			
			case NADE_HOMING:
			{
				entity_set_float(grenade, EV_FL_dmgtime, entity_get_float(grenade, EV_FL_dmgtime) + get_option_float(OPTION_HOMING_EXTRATIME))
				
				entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_HOMING)))
				
				if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_HOMING))
				{
					entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
				}
			}
		}
	}
}

public get_trip_grenade_react_method(grenade)
{
	new NadeRace:grenade_race = NadeRace:get_grenade_race(grenade)
	
	switch (grenade_race)
	{
		case GRENADE_EXPLOSIVE: return get_option(OPTION_REACT_TRIP_G)
		case GRENADE_FLASHBANG: return get_option(OPTION_REACT_TRIP_F)
		case GRENADE_SMOKEGREN: return get_option(OPTION_REACT_TRIP_S)
	}
	
	return -1
}

/* -------------------------------
[Usefull Functions -> Surface and solid tests + line of sight]
------------------------------- */
public bool:is_solid(ent)
{
	// Here we account for ent = 0, where 0 means it's part of the map (and therefore is solid)
	return ( ent ? ( (entity_get_int(ent, EV_INT_solid) > SOLID_TRIGGER) ? true : false ) : true )
}

public bool:is_attachable_surface(entity)
{
	static Float:velocity[3]
	
	if (is_valid_ent(entity))
	{
		if (!is_solid(entity)) return false 									// This is for func_breakables. The entity technically exists, but isn't solid.
		entity_get_vector(entity, EV_VEC_velocity, velocity) 					// This is for func_doors. The grenade touches the door, causing it to move.
		return (xs_vec_equal(velocity, Float:{0.0, 0.0, 0.0}) ? true : false)
	}
	
	return true
}

public bool:is_in_los(grenade_ent, player)
{
	static Float:start[3], Float:end[3]
	entity_get_vector(grenade_ent, EV_VEC_origin, start)
	entity_get_vector(player, EV_VEC_origin, end)
	
	start[2] += 2.0
	
	static ptr
	ptr = create_tr2()
	
	engfunc(EngFunc_TraceLine, start, end, IGNORE_MONSTERS, grenade_ent, ptr)
	
	static Float:dist
	get_tr2(ptr, TR_flFraction, dist)
	
	free_tr2(ptr)
	
	return ((dist == 1.0) ? true : false)
}

public insert_in_queue(id, ent_id)
{
	for (new i=0;i<SHOT_ENTITY_QUEUE_LENGTH;i++)
	{
		if (cl_entity_queue[id][i] == 0)
		{
			cl_entity_queue[id][i] = ent_id
			break;
		}
		
		if (i == SHOT_ENTITY_QUEUE_LENGTH - 1)
		{
			server_print("[NDM] Error! Unable to save so much entities!")
			server_print("[NDM] Increase the value of the ^"SHOT_ENTITY_QUEUE_LENGTH^" define and recompile!")
			log_amx("[NDM] Error! Unable to save so much entities")
			log_amx("[NDM] Increase the value of the ^"SHOT_ENTITY_QUEUE_LENGTH^" define and recompile!")
		}
	}
}
/* -------------------------------
[Message Functions]
------------------------------- */
draw_line_from_entity(entid, Float:end[3], staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR, id = 0, Float:pvs[3] = {0.0, 0.0, 0.0})
{
	( id == 0 ) ? engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, pvs, 0) : engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ONE : MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, pvs, id)
	write_byte(TE_BEAMENTPOINT)
	write_short(entid)	// start entity
	engfunc(EngFunc_WriteCoord, end[0])
	engfunc(EngFunc_WriteCoord, end[1])
	engfunc(EngFunc_WriteCoord, end[2])
	write_short(beampoint)
	write_byte(0)
	write_byte(0)
	write_byte(staytime)
	write_byte(10)
	write_byte(0)
	write_byte(R)
	write_byte(G)
	write_byte(B)
	write_byte(127)
	write_byte(1)
	message_end()	
}

stock draw_line(Float:start[3], Float:end[3], staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR)
{
	engfunc(EngFunc_MessageBegin, MSG_ALL, SVC_TEMPENTITY, Float:{0.0,0.0,0.0}, 0)
	write_byte(TE_BEAMPOINTS)
	engfunc(EngFunc_WriteCoord, start[0])
	engfunc(EngFunc_WriteCoord, start[1])
	engfunc(EngFunc_WriteCoord, start[2])
	engfunc(EngFunc_WriteCoord, end[0])
	engfunc(EngFunc_WriteCoord, end[1])
	engfunc(EngFunc_WriteCoord, end[2])
	write_short(beampoint)
	write_byte(0)
	write_byte(0)
	write_byte(staytime)
	write_byte(10)
	write_byte(0)
	write_byte(R)
	write_byte(G)
	write_byte(B)
	write_byte(127)
	write_byte(1)
	message_end()	
}

draw_line_from_entity_broadcast(entid, Float:end[3], staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR)
{
	engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ALL : MSG_BROADCAST, SVC_TEMPENTITY, {0.0, 0.0, 0.0}, 0)
	write_byte(TE_BEAMENTPOINT)
	write_short(entid)	// start entity
	engfunc(EngFunc_WriteCoord, end[0])
	engfunc(EngFunc_WriteCoord, end[1])
	engfunc(EngFunc_WriteCoord, end[2])
	write_short(beampoint)
	write_byte(0)
	write_byte(0)
	write_byte(staytime)
	write_byte(10)
	write_byte(0)
	write_byte(R)
	write_byte(G)
	write_byte(B)
	write_byte(127)
	write_byte(1)
	message_end()	
}

clear_line(entid)
{
	message_begin(MSG_ALL, SVC_TEMPENTITY)
	write_byte(TE_KILLBEAM)
	write_short(entid)
	message_end()
}

show_ring(Float:origin[3], Float:addict, staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR , id = 0)
{
	( id == 0 ) ? engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ALL : MSG_BROADCAST, SVC_TEMPENTITY, {0.0, 0.0, 0.0}, 0) : engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ONE : MSG_ONE_UNRELIABLE , SVC_TEMPENTITY, {0.0, 0.0, 0.0}, id)
	write_byte(TE_BEAMCYLINDER)										 			 // TE_BEAMCYLINDER
	engfunc(EngFunc_WriteCoord, origin[0])										 // start X
	engfunc(EngFunc_WriteCoord, origin[1])										 // start Y
	engfunc(EngFunc_WriteCoord, origin[2])										 // start Z
	engfunc(EngFunc_WriteCoord, origin[0])										 // something X
	engfunc(EngFunc_WriteCoord, origin[1])										 // something Y
	engfunc(EngFunc_WriteCoord, origin[2] + addict)								 // something Z
	write_short(shockwave) 														 // sprite
	write_byte(0) 																 // startframe
	write_byte(0) 																 // framerate
	write_byte(staytime) 														 // life
	write_byte(60) 																 // width
	write_byte(0) 																 // noise
	write_byte(R) 																 // red
	write_byte(G) 																 // green
	write_byte(B) 																 // blue
	write_byte(100) 															 // brightness
	write_byte(0)																 // speed
	message_end()
}

metal_gibs(const Float: origin[3])
{
	message_begin(get_option(OPTION_MSG_SVC_BAD) ? MSG_ALL : MSG_BROADCAST, SVC_TEMPENTITY, {0, 0, 0}, 0)
	write_byte(TE_BREAKMODEL)									 				 // TE_BREAKMODEL
	engfunc(EngFunc_WriteCoord,origin[0])						 				 // x
	engfunc(EngFunc_WriteCoord,origin[1])						 				 // y
	engfunc(EngFunc_WriteCoord,origin[2] + 24)					 				 // z
	engfunc(EngFunc_WriteCoord,20.0)											 // size x
	engfunc(EngFunc_WriteCoord,20.0)							 				 // size y
	engfunc(EngFunc_WriteCoord,20.0)											 // size z
	engfunc(EngFunc_WriteCoord,random_num(-50,50))				 				 // velocity x
	engfunc(EngFunc_WriteCoord,random_num(-50,50))								 // velocity y
	engfunc(EngFunc_WriteCoord,25.0)							 				 // velocity z
	write_byte(10)																 // random velocity
	write_short(nadebits) 										 				 // model
	write_byte(10) 												 				 // count
	write_byte(25) 																 // life
	write_byte(2)												 				 // flags: BREAK_METAL
	message_end()
}
Последно промяна от OciXCrom на 17 Апр 2018, 19:36, променено общо 1 път.
Причина: Какво прави темата в раздел ПРЕРАБОТЕНИ плъгини?

Аватар
You Owe Me
Извън линия
Потребител
Потребител
Мнения: 185
Регистриран на: 07 Мар 2018, 19:34
Местоположение: Пред компютъра
Получена благодарност: 2 пъти

Преработка на Nade Modes (Nomexous) v11.2

Мнение от You Owe Me » 17 Апр 2018, 14:27

Значи за модовете, има си команда в самия плъгин който може да се спират/пускат модове и да си го настроиш само за модовете които искаш обаче те мързи да четеш :) командата е - amx_nmm

Добавено преди 3 минути 43 секунди:
Ето ти плъгин за замразяваща граната - https://forums.alliedmods.net/showthread.php?t=41126

Добавено преди 1 минута 9 секунди:
Ето ти плъгин за огнена граната (napalm) https://forums.alliedmods.net/showthread.php?p=659532

Добавено преди 11 минути 11 секунди:
И да добавя, че в менюто amx_nmm можеш да настроиш дали гранатата да експлодира ако собственика я е докоснал, тоест пишеш amx_nmm в конзолата, излиза ти меню, натискаш 3, след това 9, и накрая натискаш на опцията: Trap can be activated by owner, и там трябва да е No, това е от мен дано съм ти помогнал. :)
I am actually not a Harry Potter FAN, but this song below is HOT AF :crazy:

Аватар
М.А.Р.И.Х.У.А.Н.А
Извън линия
Потребител
Потребител
Мнения: 64
Регистриран на: 12 Дек 2016, 19:49

Преработка на Nade Modes (Nomexous) v11.2

Мнение от М.А.Р.И.Х.У.А.Н.А » 17 Апр 2018, 15:16

След като съм го пуснал е имало защо.
1 - като ги изключиш от сма. нормал мода си остава и менуто се маха.
2 - като ги изключиш от менюто пак нормал мода си е включен + това като настройваш от менюто някой неща сървъра крашва.
За това искам всичко ненужно да се премахне.

Ще съм ви благодарен, ако изпълните заявката ми.

Аватар
You Owe Me
Извън линия
Потребител
Потребител
Мнения: 185
Регистриран на: 07 Мар 2018, 19:34
Местоположение: Пред компютъра
Получена благодарност: 2 пъти

Преработка на Nade Modes (Nomexous) v11.2

Мнение от You Owe Me » 17 Апр 2018, 19:08

М.А.Р.И.Х.У.А.Н.А написа: 17 Апр 2018, 15:16 След като съм го пуснал е имало защо.
1 - като ги изключиш от сма. нормал мода си остава и менуто се маха.
2 - като ги изключиш от менюто пак нормал мода си е включен + това като настройваш от менюто някой неща сървъра крашва.
За това искам всичко ненужно да се премахне.

Ще съм ви благодарен, ако изпълните заявката ми.
Абсолютно всяко едно нещо което си описал се изключва от менюто, включително и нормалния мод. Няма как сървъра ти да "crash" ей така без причина, явно си пречи с друг плъгин или просто си измисляш за да може да се направи както ти си казал, в което няма никакъв смисъл при положение, че може от монюто да се редактира
I am actually not a Harry Potter FAN, but this song below is HOT AF :crazy:

Публикувай отговор
  • Подобни теми
    Отговори
    Преглеждания
     Последно мнение

Обратно към “Заявки за плъгини”

Кой е на линия

Потребители разглеждащи този форум: Bing [Bot] и 21 госта