/* Plugin generated by AMXX-Studio */

#include <amxmodx>
#include <amxmisc>
#include <engine>
#include <fakemeta>
#include <fakemeta_util>
#include <cstrike>
#include <hamsandwich>
#include <dhudmessage>
#include <fun>
#include <td_const>

#pragma dynamic 32768 

#define PLUGIN "TD: New"
#define VERSION "1.0"
#define AUTHOR "GT Team"

#define DEBUG

#define MAX_WAVE 100
#define MAX_LEVEL 8
#define MAX_MONSTERS 30

#define pev_monster_type	pev_iuser1
#define pev_monster_track	pev_iuser2
#define pev_monster_maxhealth	pev_iuser3
#define pev_monster_speed	pev_iuser4
#define pev_monster_healthbar	pev_euser1

new gszWaveConfigDir[] 	= "addons/amxmodx/configs/Tower Defense";
new gszCvarConfigFile[] = "addons/amxmodx/configs/td_cvars.cfg";
new gszModelsConfigFile[] = "addons/amxmodx/configs/td_models.ini";
new gszSoundConfigFile[] = "addons/amxmodx/configs/td_sounds.cfg";
new gszPrefix[]	= "[TD]"
//new gszMonsterPrefix[] = "[P]"
new gszLogFile[] = "Tower Defense.log"
new MAX_MAP_TURRETS
new const giLevelFrags[MAX_LEVEL] = {12, 20, 38, 58, 70, 87, 100, 9999}
new const giMaxAmmo[31] = {0,52,0,90,1,32,1,100,90,1,120,100,100,90,90,90,100,120,30,120,200,32,90,120,90,2,35,90,90,0,100};


enum e_Forwards {
	FORWARD_STARTWAVE,
	FORWARD_ENDWAVE,
	FORWARD_MONSTER_KILLED,
	FORWARD_RESET_GAME
}
enum e_Models {
	MODEL_NORMAL,
	MODEL_FAST,
	MODEL_STRENGHT,
	MODEL_BOSS,
	MODEL_BONUS,
	MODEL_TOWER
}
enum e_Cvar {
	CVAR_BASE_HEALTH,
	CVAR_TIME_TO_WAVE,
	CVAR_MONSTER_DAMAGE,
	CVAR_BOSS_DAMAGE,
	CVAR_KILL_GOLD,
	CVAR_KILL_MONEY,
	CVAR_KILL_BONUS_GOLD,
	CVAR_KILL_BOSS_GOLD,
	CVAR_KILL_BP_AMMO,
	CVAR_BLOCK_CMD_KILL,
	CVAR_KILL_MONSTER_FX,
	CVAR_ONE_PLAYER_MODE
}

enum e_Tasks {
	TASK_COUNTDOWN = 334,
	TASK_HUD_INFO = 376,
	TASK_SEND_MONSTER = 404,
	TASK_PLAYER_SPAWN = 437,
	TASK_MONSTER_DEATH = 487
}

enum e_Sync {
	SYNC_WAVE_INFO,
	SYNC_DAMAGE,
	SYNC_END_GAME,
}

enum e_Sound {
	SOUND_START_WAVE,
	SOUND_COIN,
	SOUND_ACTIVATED,
	SOUND_COUNTDOWN,
	SOUND_MONSTER_DIE_1,
	SOUND_MONSTER_DIE_2,
	SOUND_MONSTER_DIE_3,
	SOUND_MONSTER_DIE_4,
	SOUND_MONSTER_HIT_1,
	SOUND_MONSTER_HIT_2,
	SOUND_MONSTER_HIT_3,
	SOUND_MONSTER_HIT_4,
	SOUND_MONSTER_1,
	SOUND_MONSTER_2,
	SOUND_MONSTER_3,
	SOUND_MONSTER_4,
	SOUND_BOSS_DIE,
	SOUND_BONUS_DIE,
	SOUND_PLAYER_LEVELUP,
	SOUND_PLAYER_USE_LIGHTING,
	SOUND_CLEAR_WAVE
}

new gszEntityBar[3][] = {
	"sprites/TD/healthbar1.spr",	//1
	"sprites/TD/healthbar2.spr",	//2
	"sprites/TD/healthbar3.spr"	//3
}

new gszRoundName[e_RoundType][33] = {
	"BRAK",
	"NORMALNA",
	"SZYBCIOR",
	"KOKSY",
	"BOSS",
	"BONUS"
}

new gszSkills[MAX_LEVEL-1][64] = {
	"Zadajesz 2 obrazenia wiecej.",
	"Jestes 10% szybszy.",
	"Otrzymujesz za kazde zabicie 1-no zloto wiecej",
	"Dostajesz o $150 wiecej",
	"Jestes 25% szybszy",
	"Zadajesz 8 obrazen wiecej",
	"Mozesz atakowac piorunem potwora co 30s klawiszem 'X'"
}

new gForward[e_Forwards]
new gWaveInfo[MAX_WAVE][e_WaveInfo]
new gCvarInfo[e_Cvar]
new gModels[4][e_Models][33]
new gSounds[e_Sound][128]


new gTasks[e_Tasks]
new gSyncInfo[e_Sync]
new gPlayerInfo[33][e_Player]


new bool:gGame = true;
new bool:gOnePlayerMode = false;
new bool:gWaveIsStarted = false
new bool:gGameIsStarted = false
new bool:gCanWalk = false
new bool:gTurretsAvailable = false
new bool:gModelTurret = false

//new bool:gGameIsPaused = false


new Float:gfStartOrigin[3];
new Float:gfEndOrigin[3];
new Float:gfTowerOrigin[3]


new Float:gfPlayerHudPosition[33][2]
new Float:gfPlayerHealthbarScale[33];
new Float:gfPlayerLightingTime[33];
new giPlayerHudColor[33][3]
new giPlayerHealthbar[33];


new gszMapName[33];

new giWaveNum;
new giWave;

new giMaxPlayers; 
new giBaseHealth;

new giMonsterAlive;
new giSendsMonster;


new giSpriteBloodDrop
new giSpriteBloodSpray;
new giSpriteExplode
new giSpriteSpawn[] = "sprites/TD/spawn.spr"
new giSpriteLighting


public plugin_natives()
{
	register_native("td_is_special_wave", "is_special_wave", 1)
	register_native("td_is_special_monster", "is_special_monster", 1)
	register_native("td_is_healthbar", "td_is_healthbar", 1)
	register_native("td_is_monster", "td_is_monster", 1)
	
	register_native("td_get_game_status", "_td_get_game_status", 1)
	register_native("td_set_game_status", "_td_set_game_status", 1)
	
	register_native("td_get_wave", "_td_get_wave", 1)
	register_native("td_set_wave", "_td_set_wave", 1)
	register_native("td_get_wavenum", "_td_get_wavenum", 1)
	
	register_native("td_get_wave_info", "_td_get_wave_info", 1)
	register_native("td_set_wave_info", "_td_set_wave_info", 1)
	
	register_native("td_get_user_info", "_td_get_user_info", 1)
	register_native("td_set_user_info", "_td_set_user_info", 1)
	
	register_native("td_get_max_level", "_td_get_max_level", 1)
	register_native("td_get_max_monsters", "_td_get_max_monsters", 1)
	register_native("td_get_max_wave", "_td_get_max_wave", 1)
	
	register_native("td_get_monster_type", "_td_get_monster_type", 1)
	register_native("td_get_monster_health", "_td_get_monster_health", 1)
	register_native("td_get_monster_healthbar", "_td_get_monster_healthbar", 1)
	
	register_native("td_remove_tower", "_td_remove_tower", 1)
	register_native("td_remove_monsters", "_td_remove_monsters", 1)
		
	register_native("td_get_start_origin", "_td_get_start_origin")
	register_native("td_get_end_origin", "_td_get_end_origin")
	
	register_native("td_get_round_name", "_td_get_round_name", 1)
	register_native("td_kill_monster", "MonsterKilled", 1)
	
	register_native("max_map_turrets", "_td_get_max_map_turrets", 1)
}

public plugin_precache() {
#if defined DEBUG
	log_to_file(gszLogFile, "		DEBUG MODE ON")
	log_to_file(gszLogFile, "DEBUG: Sprawdzam poprawnosc plikow konfiguracyjnych...")

#endif

	LoadModels();
	LoadSound();
	
	//Krew
	giSpriteBloodDrop = precache_model("sprites/blood.spr")
	giSpriteBloodSpray = precache_model("sprites/bloodspray.spr")
	
	//Piorun
	giSpriteLighting = precache_model("sprites/lgtning.spr")
	
	//Wybuch
	giSpriteExplode = precache_model("sprites/TD/zerogxplode.spr")
	
	
	precache_model(giSpriteSpawn);
	
	//Dzwieki
	
	
	for(new i; i < _:e_Sound ; i++) {
		precache_sound(gSounds[e_Sound:i]);
	}
	
	//Healthbary
	for(new i ; i < ( sizeof gszEntityBar ) ; i++)
		precache_model(gszEntityBar[i])
	
	//Potwory
	new szModelDir[] = "models/TD"
	new szModel[64]
	
	for(new i ; i < _:e_Models ; i++) {
		for(new j ; j < 4; j++) {
			formatex(szModel, 63,"%s/%s.mdl", szModelDir, gModels[j][e_Models:i])
			precache_model(szModel);
		}
	}
	
	
}

public plugin_init() 
{
	register_plugin(PLUGIN, VERSION, AUTHOR)

	gForward[FORWARD_STARTWAVE] = CreateMultiForward("td_startwave", ET_CONTINUE, FP_CELL, FP_CELL, FP_CELL)
	gForward[FORWARD_ENDWAVE] = CreateMultiForward("td_endwave", ET_CONTINUE, FP_CELL)
	gForward[FORWARD_MONSTER_KILLED] = CreateMultiForward("td_monster_killed", ET_CONTINUE, FP_CELL, FP_CELL, FP_CELL)
	gForward[FORWARD_RESET_GAME] = CreateMultiForward("td_reset_game", ET_CONTINUE)
	
	register_event("HLTV", "HLTV", "a", "1=0", "2=0")
	register_logevent("LogEventNewRound", 2, "1=Round_Start")
	
	/*Monster*/
	RegisterHam(Ham_TakeDamage, "info_target", "TakeDamage")// przed zadaniem obr.
	RegisterHam(Ham_TakeDamage, "player", "TakeDamagePlayer")
	RegisterHam(Ham_Killed, "info_target", "MonsterKilled")
	RegisterHam(Ham_Spawn, "player", "PlayerSpawn", 1) //po odrodzeniu
	RegisterHam(Ham_Touch, "info_target", "touchMonsterTrack", 1)
	RegisterHam(Ham_AddPlayerItem, "player", "C4Remove")
	register_think("monster", "thinkMonsterThink")
	
	register_forward(FM_AddToFullPack, "fwAddToFullPack", 1)
	register_forward(FM_ClientKill, "PlayerCmdKill")

	register_clcmd("say /start", "cmdOnePlayerMode");
	register_clcmd("say /skill", "cmdmenuPlayerSkill");
	register_clcmd("say /info", "cmdInfoRound")
	register_clcmd("say /menu",  "cmdmenuPlayer");
	register_clcmd("radio2",     "cmdUseLighting")
	register_clcmd("jointeam", "PlayerJointTeam")
	register_message(get_user_msgid("SayText"), "SayText")
	
	/* 	    CVARY 	    */
	
	// to jest ustalane w pliku konfiguracyjnym wavo'w
	gCvarInfo[CVAR_BASE_HEALTH] 	= register_cvar("td_base_health", "80");
	gCvarInfo[CVAR_TIME_TO_WAVE] 	= register_cvar("td_time_to_wave", "12")
	gCvarInfo[CVAR_MONSTER_DAMAGE] 	= register_cvar("td_damage", "4");
	gCvarInfo[CVAR_BOSS_DAMAGE] 	= register_cvar("td_boss_damage", "8");
	// =====
	
	gCvarInfo[CVAR_KILL_GOLD] 	= register_cvar("td_kill_gold", "3");
	gCvarInfo[CVAR_KILL_BONUS_GOLD]	= register_cvar("td_kill_bonus_gold", "10");
	gCvarInfo[CVAR_KILL_BOSS_GOLD] 	= register_cvar("td_kill_boss_gold", "6");
	gCvarInfo[CVAR_KILL_MONEY] 	= register_cvar("td_kill_money", "650");
	gCvarInfo[CVAR_KILL_BP_AMMO] 	= register_cvar("td_kill_bp_ammo", "15");

	gCvarInfo[CVAR_BLOCK_CMD_KILL] 	= register_cvar("td_block_cmd_kill", "1");
	
	gCvarInfo[CVAR_ONE_PLAYER_MODE]	= register_cvar("td_one_player_mode", "1");
	
	gCvarInfo[CVAR_KILL_MONSTER_FX] = register_cvar("td_kill_monster_fx", "1");
	
	gSyncInfo[SYNC_WAVE_INFO] = CreateHudSyncObj();
	gSyncInfo[SYNC_DAMAGE] = CreateHudSyncObj();
	gSyncInfo[SYNC_END_GAME] = CreateHudSyncObj();
	
	/* WCZYTYWANIE KONFIGURACJI */
	
	giMaxPlayers = get_maxplayers();
	
	get_mapname(gszMapName, 32);
	
	LoadWave(gszMapName)
	CheckMap();

}
public C4Remove(id, weap)
{
	if(weap == CSW_C4)
	{
		entity_set_int(id, EV_INT_body, 0)
		cs_set_user_plant(id, 0, 0)
		SetHamReturnInteger( false )
		return HAM_SUPERCEDE
	}
	return HAM_IGNORED
}
public cmdInfoRound(id)
{
	if(is_user_connected(id) && gGame && (MAX_WAVE >= giWave >= 1) && gWaveIsStarted)
	{
		static szTemp[64],szText[128]
		new iMonsterNum = is_special_wave(giWave)?gWaveInfo[giWave][WAVE_MONSTER_NUM]+1:gWaveInfo[giWave][WAVE_MONSTER_NUM]
			
		formatex(szText, 127, "WAVE: %d | %s [ %d %s ]", giWave, gszRoundName[gWaveInfo[giWave][WAVE_ROUND_TYPE]],iMonsterNum, (iMonsterNum>=5?"Potworow":iMonsterNum>1?"Potwory":iMonsterNum==1?"Potwor":iMonsterNum==0?"Potwor":""));
		if((!is_special_wave(giWave) && iMonsterNum) || (is_special_wave(giWave) && (iMonsterNum-1) > 0)) {	
			formatex(szTemp, 63, "^nHP: %d^nSPEED: %d", gWaveInfo[giWave][WAVE_MONSTER_HEALTH], gWaveInfo[giWave][WAVE_MONSTER_SPEED])
			add(szText, 127, szTemp);
		}
		
		if(gWaveInfo[giWave][WAVE_ROUND_TYPE] == ROUND_BOSS) {
			formatex(szTemp, 63, "^n^nBOSS :^nHP: %d^nSPEED: %d", gWaveInfo[giWave][WAVE_SPECIAL_HEALTH], gWaveInfo[giWave][WAVE_SPECIAL_SPEED])
			add(szText, 127, szTemp)
		}
		else if(gWaveInfo[giWave][WAVE_ROUND_TYPE] == ROUND_BONUS) {
			formatex(szTemp, 63, "^n^nBONUS:^nHP: %d^nSPEED: %d", gWaveInfo[giWave][WAVE_SPECIAL_HEALTH], gWaveInfo[giWave][WAVE_SPECIAL_SPEED])
			add(szText, 127, szTemp)
		}
		set_hudmessage(255, 255, 255, 0.50, 0.65, 2, 9.0, 5.0, 0.05, 3.0, -1)
		ShowSyncHudMsg(id, gSyncInfo[SYNC_WAVE_INFO], szText)
	}
}
public PlayerJointTeam(id)
{
	if(!is_user_connected(id) || !get_user_team(id) || get_user_team(id) == 3)
		return PLUGIN_CONTINUE
	return PLUGIN_HANDLED_MAIN
}
public plugin_cfg()
{
	LoadCvar();
	CheckGamePossibility()
}

public touchMonsterTrack(monster, track)
{
	if(!td_is_monster(monster) || !is_valid_ent(track))
		return PLUGIN_CONTINUE;
		
	new szClass[16], szFormat[33], iTrack;
	pev(track, pev_targetname, szClass, 15)
	
	iTrack = pev(monster, pev_monster_track);
	
	formatex(szFormat, 32, "track%d_wall", iTrack)
	
	if(equali(szFormat, szClass))
	{
		
		new Float:Velocity[3]
		formatex(szFormat, 32, "track%d",iTrack+1)
		
		new iTarget = find_ent_by_tname(-1, szFormat)
		if(!is_valid_ent(iTarget))
			iTarget = find_ent_by_tname(-1, "end")
		
		entity_set_aim(monster, iTarget, Float:{0.0, 0.0, 0.0}, 0);	
		
		velocity_by_aim(monster, pev(monster, pev_monster_speed), Velocity)
		entity_set_vector(monster, EV_VEC_velocity, Velocity)
		
		set_pev(monster, pev_monster_track, iTrack+1);
	}
	else if(equali(szClass, "end_wall")) 
	{
		//jeśli doszło do końca
		
		giMonsterAlive--
		set_pev(monster, pev_monster_track, 1)
		
		new iTower
		if(gModelTurret)
		{
			iTower = find_ent_by_class(-1, "tower");
				
			if(!is_valid_ent(iTower)) {
				remove_entity(monster)
				return PLUGIN_CONTINUE
			}	
		}
		
		new Float:szMax = float( get_pcvar_num(gCvarInfo[CVAR_BASE_HEALTH]) )	
		new Float:fDamage;
		new Float:fValue 
			
		fDamage = float( get_pcvar_num(gCvarInfo[CVAR_MONSTER_DAMAGE]))
			
		if(e_RoundType:pev(monster, pev_monster_type) == ROUND_BOSS)
			fDamage = float( get_pcvar_num(gCvarInfo[CVAR_BOSS_DAMAGE]))				
			
		giBaseHealth -= floatround(fDamage)
		
		if(giBaseHealth <= 0) {
			giBaseHealth = 0;
			EndGame(PLAYERS_LOSE);
		}
		
		if(gModelTurret)
		{
			fValue = ( szMax / fDamage )
			gfTowerOrigin[2] -= ( 225.0 / fValue )
				
			Explode()
			
			set_pev(iTower, pev_origin, gfTowerOrigin)
		}
			
		if(giMonsterAlive <= 0 && (giSendsMonster >= is_special_wave(giWave)?gWaveInfo[giWave][WAVE_MONSTER_NUM]+1:gWaveInfo[giWave][WAVE_MONSTER_NUM])) {
			client_cmd(0, "spk sound/%s", gSounds[SOUND_CLEAR_WAVE]);
			set_task(3.0, "StartWave", 9123) // nowy wave
		}
				
		if(is_valid_ent(monster))
		{
			if(is_valid_ent(pev(monster, pev_monster_healthbar)))
				remove_entity(pev(monster, pev_monster_healthbar))
				
			set_pev(monster, pev_euser2, 0)
			set_pev(monster, pev_monster_type, 0)
			set_pev(monster, pev_monster_track, 0)
			set_pev(monster, pev_monster_maxhealth, 0)
			set_pev(monster, pev_monster_speed, 0)
			set_pev(monster, pev_monster_healthbar, 0)

			remove_entity(monster)
		}
	}
	return PLUGIN_CONTINUE
}

public HLTV()
	gCanWalk = false

public LogEventNewRound()
	gCanWalk = true
		
public ResetPlayerInformation(id)
{
	if(0 < id <= giMaxPlayers)
	{
		gfPlayerHudPosition[id] = Float:{0.1, 0.0}
		giPlayerHudColor[id] = {0, 255, 255}
		gfPlayerHealthbarScale[id] = 0.3
		
		for(new i ; i < _:e_Player ; i++)
			gPlayerInfo[id][e_Player:i] = 0
	}
}
public client_connect(id) {
	ResetPlayerInformation(id)
}

public client_disconnect(id) {
	ResetPlayerInformation(id)
}

public client_putinserver(id)
{
	if(!is_user_connected(id) || gGame == false)
		return PLUGIN_CONTINUE
	
	set_task(5.0, "PlayerRespawn", id+gTasks[TASK_PLAYER_SPAWN])
	return PLUGIN_CONTINUE
}
public PlayerRespawn(id)
{
	id-=gTasks[TASK_PLAYER_SPAWN]
	if(!is_user_connected(id) || is_user_alive(id))
		return PLUGIN_CONTINUE	

	if(get_user_team(id) == 1 || get_user_team(id) == 2)
	{
		ExecuteHamB(Ham_CS_RoundRespawn, id)
		remove_task(id+gTasks[TASK_PLAYER_SPAWN])
		return PLUGIN_CONTINUE
	}

	set_task(5.0, "PlayerRespawn", id+gTasks[TASK_PLAYER_SPAWN])
	return PLUGIN_CONTINUE
}

public cmdUseLighting(id)
{
	if(!is_user_alive(id) || gPlayerInfo[id][PLAYER_LEVEL] < 7)
		return PLUGIN_CONTINUE
		
	if(gfPlayerLightingTime[id]+30 > get_gametime())
	{
		client_print(id, print_center, "Musisz poczekac jeszcze %ds", floatround(gfPlayerLightingTime[id]+30-get_gametime()))
		return PLUGIN_CONTINUE
	}
	
	new Float:AimedOrigin[3]
	new Origin[3]
	
	get_user_origin(id, Origin, 3)
	IVecFVec(Origin, AimedOrigin)
	
	new entlist[1]
	find_sphere_class(0, "monster", 80.0, entlist, 1, AimedOrigin)
	
	if(!is_valid_ent(entlist[0]))
	{
		client_print(id, print_center, "Musisz wybrac cel!")
		return PLUGIN_CONTINUE
	}
	gfPlayerLightingTime[id] = get_gametime()
	
	emit_sound(id, CHAN_AUTO, gSounds[SOUND_PLAYER_USE_LIGHTING], 1.0, ATTN_NORM, 0, PITCH_NORM); 
	ExecuteHamB(Ham_TakeDamage, entlist[0], id, id, 1, DMG_BLAST)
	
	Create_Lighting(id, entlist[0], 0, 1, 10, 20, 20, 255, 255, 255, 255, 3)
	
	return PLUGIN_CONTINUE
}
public PlayerCmdKill(id) // jezeli ktos uzyl komendy "kill"
{
	if(!is_user_alive(id) && get_pcvar_num(gCvarInfo[CVAR_BLOCK_CMD_KILL])) // jezeli gracz nie zyje przerwij
		return FMRES_IGNORED
		
	client_print(id, print_console, "Chciales uzyc komendy ^"kill^" - jest ona nie dozwolona! - 2 pkt")
	client_print(id, 3, "Chciales uzyc komendy ^"kill^" - jest ona nie dozwolona! - 2 pkt")
	gPlayerInfo[id][PLAYER_GOLD]-=2 //punkty za to ze chcial sie zabic
	
	if(gPlayerInfo[id][PLAYER_GOLD] < 0) // jezeli gracz ma ponizej 0 pkt to chyba nie chcemy zeby pokazywalo -x :)
		gPlayerInfo[id][PLAYER_GOLD] = 0 // ustaw 0
	
	return FMRES_SUPERCEDE //przerwij
}
public TakeDamagePlayer(this, idinflictor, attacker, Float:damage, damagebits) // gracze nie moga zadac sobie obrazen
{	
	if(is_user_alive(attacker) && is_user_alive(this))
		return HAM_SUPERCEDE
		;
	return HAM_IGNORED;
}
public TakeDamage(ent, idinflictor, attacker, Float:damage, damagebits)
{
	if(!is_valid_ent(ent) || !is_user_alive(attacker))
		return HAM_IGNORED
		
	if(td_is_monster(ent))  //jezli to potwor
	{	
		if(damagebits & DMG_BLAST)
			damage+=1000
		if(gPlayerInfo[attacker][PLAYER_EXTRA_DAMAGE])
			damage += float(gPlayerInfo[attacker][PLAYER_EXTRA_DAMAGE])
		if(is_valid_ent(pev(ent, pev_monster_healthbar)))
			set_pev( pev(ent, pev_monster_healthbar) , pev_frame , 0.0 + ( (pev( ent , pev_health )-floatround(damage)) * 100.0 ) / pev( ent , pev_monster_maxhealth ) );
		
		if(is_user_connected(attacker) && !(damagebits & DMG_DROWN)) {
			set_hudmessage(0, 255, 0, 0.55, -1.0, 0, 6.0, 1.0, 0.0, 0.4)
			ShowSyncHudMsg(attacker, gSyncInfo[SYNC_DAMAGE], "%d", floatround(damage))
		}
		set_task(0.1, "TakeDamageEffects", ent+551)
	}
	SetHamParamFloat(4, damage)
	return HAM_IGNORED
}
public TakeDamageEffects(ent)
{
	ent-=551
	if(is_valid_ent(ent)) {
		switch(random_num(1, 8)) {
			case 2: emit_sound(ent, CHAN_ITEM, gSounds[SOUND_MONSTER_HIT_1], 1.0, ATTN_NORM, 0, PITCH_NORM);
			case 4: emit_sound(ent, CHAN_ITEM, gSounds[SOUND_MONSTER_HIT_2], 1.0, ATTN_NORM, 0, PITCH_NORM);
			case 6: emit_sound(ent, CHAN_ITEM, gSounds[SOUND_MONSTER_HIT_3], 1.0, ATTN_NORM, 0, PITCH_NORM);
			case 8: emit_sound(ent, CHAN_ITEM, gSounds[SOUND_MONSTER_HIT_4], 1.0, ATTN_NORM, 0, PITCH_NORM);
		}
		if(random_num(1, 2) == 1) {
			new Origin[3], Float:fOrigin[3]
			pev(ent, pev_origin, fOrigin)
			FVecIVec(fOrigin, Origin)
			Origin[0] += random_num(-10, 10)
			Origin[1] += random_num(-10, 10)
			Origin[2] += random_num(-10, 30)
			fx_blood(Origin, 15) // krew	
		}
	}
	remove_task(ent+551)
}
public MonsterKilled(iEnt, id) //zabicie potwora
{
	if(!is_user_alive(id) || !td_is_monster(iEnt))
		return HAM_IGNORED
	
	new iDeadSeq;
	
	switch(random_num(1, 3))
	{
		case 1:iDeadSeq = lookup_sequence(iEnt, "death1")
		case 2:iDeadSeq = lookup_sequence(iEnt, "death2")
		case 3:iDeadSeq = lookup_sequence(iEnt, "death3")
	}
	if(!iDeadSeq)
		iDeadSeq = lookup_sequence(iEnt, "death1");
	
	new iRet;
	ExecuteForward(gForward[FORWARD_MONSTER_KILLED], iRet, iEnt, id, e_RoundType:pev(iEnt,pev_monster_type))
	
	giMonsterAlive--
	if(is_valid_ent(pev(iEnt, pev_monster_healthbar)))
		remove_entity(pev(iEnt, pev_monster_healthbar))
		
	/*death_msg(id, iEnt);*/	
		
	new data[2];
	data[0] = id,
	data[1] = iEnt
	set_task(0.3, "postKillMonster", id+433, data, 1)
	
	set_hudmessage(255, 255, 255, 0.60, -1.0, 2, 6.0, 1.0, 0.0, 0.4)
	ShowSyncHudMsg(id, gSyncInfo[SYNC_DAMAGE], "KILL")
	
	if(giMonsterAlive <= 0 && (giSendsMonster >= (is_special_wave(giWave)?gWaveInfo[giWave][WAVE_MONSTER_NUM]+1:gWaveInfo[giWave][WAVE_MONSTER_NUM]))) {
		client_cmd(0, "spk sound/%s", gSounds[SOUND_CLEAR_WAVE]);
		set_task(3.0, "StartWave", 9123)
		return HAM_IGNORED
	}
		
	set_pev(iEnt, pev_euser2, 0)
	set_pev(iEnt, pev_monster_type, 0)
	set_pev(iEnt, pev_monster_track, 0)
	set_pev(iEnt, pev_monster_maxhealth, 0)
	set_pev(iEnt, pev_monster_speed, 0)
	set_pev(iEnt, pev_monster_healthbar, 0)
	
	entity_set_float(iEnt, EV_FL_nextthink, 0.0);
	entity_set_vector(iEnt, EV_VEC_velocity, Float:{0.0, 0.0, 0.0})
	entity_set_int(iEnt, EV_INT_solid, SOLID_NOT)
	
	entity_set_int(iEnt, EV_INT_sequence, iDeadSeq); 
	entity_set_float(iEnt, EV_FL_animtime, get_gametime()+0.1); 
	entity_set_float(iEnt, EV_FL_framerate,  1.0); 
	entity_set_float(iEnt, EV_FL_frame, 3.0); 
		
	new Float:fSeqTime = 5.0

	if(get_pcvar_num(gCvarInfo[CVAR_KILL_MONSTER_FX]))
	{
		new iOrigin[3]
		new Float:fOrigin[3]

		pev(iEnt, pev_origin, fOrigin);
		FVecIVec(fOrigin, iOrigin)
		iOrigin[2]-=35
		
		msg_implosion(0, iOrigin, 100, 50, 5);
	}
	set_task(fSeqTime, "DeleteMonsterPost", iEnt+gTasks[TASK_MONSTER_DEATH]);
	return HAM_SUPERCEDE
}	

public postKillMonster(szData[], id) {
	KillMonster(szData[0], e_RoundType:pev(szData[1], pev_monster_type));
	
	new iEnt = szData[1]
	if(!is_valid_ent(iEnt))
		return PLUGIN_CONTINUE
		
	if(!is_special_monster(iEnt)) {	
		switch(random_num(1, 4)) {
			case 1: emit_sound(iEnt, CHAN_ITEM, gSounds[SOUND_MONSTER_DIE_1], 1.0, ATTN_NORM, 0, PITCH_NORM);
			case 2: emit_sound(iEnt, CHAN_ITEM, gSounds[SOUND_MONSTER_DIE_2], 1.0, ATTN_NORM, 0, PITCH_NORM);
			case 3: emit_sound(iEnt, CHAN_ITEM, gSounds[SOUND_MONSTER_DIE_3], 1.0, ATTN_NORM, 0, PITCH_NORM);
			case 4: emit_sound(iEnt, CHAN_ITEM, gSounds[SOUND_MONSTER_DIE_4], 1.0, ATTN_NORM, 0, PITCH_NORM);
		}
	} else{

		switch(e_RoundType:pev(iEnt, pev_monster_type)) {
			case ROUND_BONUS: emit_sound(iEnt, CHAN_ITEM, gSounds[SOUND_BONUS_DIE], 1.0, ATTN_NORM, 0, PITCH_NORM);
			case ROUND_BOSS: emit_sound(iEnt, CHAN_ITEM, gSounds[SOUND_BOSS_DIE], 1.0, ATTN_NORM, 0, PITCH_NORM);
		}
	}
	remove_task(id)
	
	return PLUGIN_CONTINUE	
}
public DeleteMonsterPost(iEnt) {
	iEnt -= gTasks[TASK_MONSTER_DEATH]
	if(is_valid_ent(iEnt))
		remove_entity(iEnt);
	remove_task(iEnt+gTasks[TASK_MONSTER_DEATH])
}

public KillMonster(iPlayer, e_RoundType:iType) {
	if(!is_user_connected(iPlayer)) {
			return PLUGIN_CONTINUE;
	}
	/* Złoto */
	gPlayerInfo[iPlayer][PLAYER_GOLD] += get_pcvar_num(iType==ROUND_BOSS?gCvarInfo[CVAR_KILL_BOSS_GOLD]:iType==ROUND_BONUS?gCvarInfo[CVAR_KILL_BONUS_GOLD]:gCvarInfo[CVAR_KILL_GOLD]);
	if(gPlayerInfo[iPlayer][PLAYER_EXTRA_GOLD] > 0)
		gPlayerInfo[iPlayer][PLAYER_GOLD] += gPlayerInfo[iPlayer][PLAYER_EXTRA_GOLD]
	/* Fragi */
	
	set_user_frags(iPlayer, get_user_frags(iPlayer)+(iType==ROUND_BOSS?3:iType==ROUND_BONUS?2:1))
	gPlayerInfo[iPlayer][PLAYER_FRAGS] += iType==ROUND_BOSS?3:iType==ROUND_BONUS?2:1
	CheckPlayerLevel(iPlayer)
	
	/* Kasa */
	
	cs_set_user_money(iPlayer, cs_get_user_money(iPlayer)+gPlayerInfo[iPlayer][PLAYER_EXTRA_MONEY]+get_pcvar_num(gCvarInfo[CVAR_KILL_MONEY]), 1)

	if(cs_get_user_money(iPlayer) > 16000)
		cs_set_user_money(iPlayer, 16000, 0)

	client_cmd(iPlayer, "spk sound/%s", gSounds[SOUND_COIN]);
	/* Odswiezanie fragow */
	RefreshFrag(iPlayer)

	/* Amunicja */
	if(get_user_weapon(iPlayer) != 29)
		GivePlayerAmmo(iPlayer, get_pcvar_num(gCvarInfo[CVAR_KILL_BP_AMMO])) // prawy BP
	
	return PLUGIN_CONTINUE;
}

public CheckPlayerLevel(iPlayer)
{
	if(!is_user_connected(iPlayer))
		return PLUGIN_CONTINUE

	while(gPlayerInfo[iPlayer][PLAYER_FRAGS] >= giLevelFrags[gPlayerInfo[iPlayer][PLAYER_LEVEL]])
	{
		gPlayerInfo[iPlayer][PLAYER_LEVEL]++
		gPlayerInfo[iPlayer][PLAYER_FRAGS] = 0
		
		client_print(iPlayer, 3, "%s Awansowales do poziomu %d.", gszPrefix, gPlayerInfo[iPlayer][PLAYER_LEVEL])
		client_print(iPlayer, 3, "%s Masz nowa umiejetnosc, wpisz ^"/skill^", aby ja zobaczyc", gszPrefix)
		
		client_cmd(iPlayer, "spk sound/%s", gSounds[SOUND_PLAYER_LEVELUP])
		
		switch(gPlayerInfo[iPlayer][PLAYER_LEVEL]) {
			case 1: {
				gPlayerInfo[iPlayer][PLAYER_EXTRA_DAMAGE] += 2;
			}
			case 2: {
				gPlayerInfo[iPlayer][PLAYER_EXTRA_SPEED] += 25
			}
			case 3: {
				gPlayerInfo[iPlayer][PLAYER_EXTRA_GOLD] += 1
			}
			case 4: {
				gPlayerInfo[iPlayer][PLAYER_EXTRA_MONEY] += 150
			}
			case 5: {
				gPlayerInfo[iPlayer][PLAYER_EXTRA_SPEED] += 50
			}
			case 6: {
				gPlayerInfo[iPlayer][PLAYER_EXTRA_DAMAGE] += 8;
			}		
		}
	}
	return PLUGIN_CONTINUE
}

public client_PreThink(id) {
	if(!is_user_alive(id)|| !gPlayerInfo[id][PLAYER_EXTRA_SPEED]) {
		return FMRES_IGNORED
	}
	if(gCanWalk)
		set_user_maxspeed(id, (250.0+gPlayerInfo[id][PLAYER_EXTRA_SPEED]))
	
	return FMRES_IGNORED
}
public fwAddToFullPack(es_handle, e, ENT, HOST, hostflags, player, set)
{
	if(player || !is_user_connected(HOST) || !is_valid_ent(ENT) || !pev(ENT, pev_health)) 
		return FMRES_IGNORED;
	static Float:fOrigin[ 3 ]
	if(is_valid_ent(pev(ENT, pev_monster_healthbar)))
	{	
		
		pev(ENT , pev_origin , fOrigin );
				
		fOrigin[ 2 ] += 45.0;
				
		set_pev(pev(ENT, pev_monster_healthbar), pev_origin, fOrigin)
			
		entity_set_model(pev(ENT, pev_monster_healthbar), gszEntityBar[giPlayerHealthbar[HOST]]);
		set_pev(pev(ENT, pev_monster_healthbar), pev_scale, gfPlayerHealthbarScale[HOST])
		return FMRES_IGNORED
	}
	return FMRES_IGNORED;
}
new bool:gimenuOption[33];

public cmdmenuPlayer(id) {
	if(!is_user_connected(id)) {
		return PLUGIN_CONTINUE
	}
	
	new szConfig[33];
	new szSkills[33];
	new szTurrets[33];
	
	formatex(szTurrets, 32, "Wiezyczki");
	formatex(szSkills, 32, "Umiejetnosci");
	formatex(szConfig, 32, "Ustawienia");
	
	new iMenu = menu_create("Wybierz opcje: ", "cmdmenuPlayerH");
	new iCb = menu_makecallback("cmdmenuPlayerCb");
	
	menu_additem(iMenu, szTurrets, _, _, iCb);
	menu_additem(iMenu, szSkills);
	menu_additem(iMenu, szConfig);
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wyjscie");
	menu_display(id, iMenu);
	return PLUGIN_CONTINUE;
}
public cmdmenuPlayerCb(id, menu, item) {
	if(item == 0 && !gTurretsAvailable)
		return ITEM_DISABLED;
	return ITEM_ENABLED
}

public cmdmenuPlayerH(id, menu, item) {
	if(item == MENU_EXIT) {
		menu_destroy(menu)
		return PLUGIN_CONTINUE
	}
	
	switch(item) {
		case 0: {
			client_cmd(id, "say /turrets");
		}
		case 1: {
			cmdmenuPlayerSkill(id)
		}
		case 2: {
			menuPlayerOptions(id);
		}
	}
	
	return PLUGIN_CONTINUE
}

public cmdmenuPlayerSkill(id) {	
	new szSkill[96]
	new iMenu = menu_create("Twoje umiejetnosci: ", "cmdmenuPlayerSkillH")
	new iCb = menu_makecallback("cmdmenuPlayerSkillCb");
	
	for(new i ; i < MAX_LEVEL-1 ; i++) {
		formatex(szSkill, 95, "%s \y[POZIOM %d]", gszSkills[i], i+1) 
		menu_additem(iMenu, szSkill, _, _, iCb);
	}
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
}

public cmdmenuPlayerSkillCb(id, menu, item) {
	for(new i ; i < MAX_LEVEL-1 ; i++ ) {
		if(item == i && gPlayerInfo[id][PLAYER_LEVEL] < i+1) {
			return ITEM_DISABLED;
		}
	}
	
	return ITEM_ENABLED;
}

public cmdmenuPlayerSkillH(id, menu, item) {
	if(item == MENU_EXIT) {
		cmdmenuPlayer(id)
		return PLUGIN_CONTINUE
	}
	
	cmdmenuPlayerSkill(id)
	return PLUGIN_CONTINUE;
}
public menuPlayerOptions(id) {	
	new szHud[33], szHealthbar[33];
	
	formatex(szHud, 32, "HUD");
	formatex(szHealthbar, 32, "Healthbary");
	
	new iMenu = menu_create("Ustawienia: ", "menuPlayerOptionsH");
	menu_additem(iMenu, szHud);
	menu_additem(iMenu, szHealthbar);
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
}

public menuPlayerOptionsH(id, menu, item) {
	if(item == MENU_EXIT) {
		cmdmenuPlayer(id)
		return PLUGIN_CONTINUE
	}
	
	switch(item) {
		case 0: {
			menuPlayerOptionsHud(id);
		}
		case 1: {
			menuPlayerOptionsBar(id)
		}
	}
	
	return PLUGIN_CONTINUE
}
public menuPlayerOptionsBar(id) {
	new szStyle[33], szScale[33];
	
	formatex(szStyle, 32, "Zmien styl")
	formatex(szScale, 32, "Zmien wielkosc")
	new iMenu = menu_create("Healthbary", "menuPlayerOptionsBarH")
	
	menu_additem(iMenu, szStyle)
	menu_additem(iMenu, szScale)
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
}
public menuPlayerOptionsBarH(id, menu, item)
{
	if(item == MENU_EXIT)
	{
		menuPlayerOptions(id)
		return PLUGIN_CONTINUE
	}
	switch(item)
	{
		case 0: {
			menuPlayerOpStyleBar(id)
		}
		case 1: {
			menuPlayerOpScaleBar(id)
		}
	}
	return PLUGIN_CONTINUE
}
public menuPlayerOpScaleBar(id) {
	if(!is_user_connected(id)) {
		return PLUGIN_CONTINUE
	}
	
	new szScale[33], szTitle[33], szChangeOption[33]
	
	formatex(szScale, 32, "Wielkosc: \r%0.2f", gfPlayerHealthbarScale[id]);
	formatex(szTitle, 32, "%s\w co 0.05", gimenuOption[id]?"\yDodawaj":"\yOdejmuj")
	formatex(szChangeOption, 32, "%s", gimenuOption[id]?"\yOdejmuj":"\yDodawaj")
	
	new iMenu = menu_create(szTitle, "menuPlayerOpScaleBarH");
	
	menu_additem(iMenu, szScale);
	menu_additem(iMenu, szChangeOption)
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
	return PLUGIN_CONTINUE;
}
public menuPlayerOpScaleBarH(id, menu, item)
{
	if(item == MENU_EXIT) {
		menuPlayerOptionsBar(id)
		return PLUGIN_CONTINUE
	}
	
	switch(item) {
		case 0: {
			if(gimenuOption[id]) {
				gfPlayerHealthbarScale[id] += 0.05
			} else {
				gfPlayerHealthbarScale[id] -= 0.05
			}
			
			if(gfPlayerHealthbarScale[id] < 0.1) {
				gfPlayerHealthbarScale[id] = 0.1
			} else if(gfPlayerHealthbarScale[id] > 1.0) {
				gfPlayerHealthbarScale[id] = 1.0
			}
		}
		case 1: {
			gimenuOption[id] = !gimenuOption[id]
		}
	}
	
	menuPlayerOpScaleBar(id)
	return PLUGIN_CONTINUE
}
public menuPlayerOpStyleBar(id) {
	new szHealthbar[33];
	
	new iMenu = menu_create("Style: ", "menuPlayerOpStyleBarH")
	new iCb = menu_makecallback("menuPlayerOpStyleBarCb");
	for(new i; i < 3 ; i++) {
		formatex(szHealthbar, 32, "Healthbar %d", i+1)
		menu_additem(iMenu, szHealthbar, _, _, iCb)
	}
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
}

public menuPlayerOpStyleBarCb(id, menu, item)
{
	if(item == giPlayerHealthbar[id])
		return ITEM_DISABLED
	return ITEM_ENABLED
}

public menuPlayerOpStyleBarH(id, menu, item)
{
	if(item == MENU_EXIT) {
		menuPlayerOptions(id)
		return PLUGIN_CONTINUE
	}
	
	client_print(id, 3, "%s Healthbar zostal zmieniony!", gszPrefix);
	
	giPlayerHealthbar[id] = item;
	menuPlayerOpStyleBar(id)
	return PLUGIN_CONTINUE
}

public menuPlayerOptionsHud(id) {
	if(!is_user_connected(id)) {
		return PLUGIN_CONTINUE
	}
	
	new szHudPosition[33], szHudColor[33];
	
	formatex(szHudPosition, 32, "Pozycja: \rX: %0.2f \yY: %0.2f", gfPlayerHudPosition[id][0], gfPlayerHudPosition[id][1]);
	formatex(szHudColor, 32, "Kolor: R: %d G: %d B: %d", giPlayerHudColor[id][0], giPlayerHudColor[id][1], giPlayerHudColor[id][2]);
	
	new iMenu = menu_create("HUD: ", "menuPlayerOptionsHudH");
	menu_additem(iMenu, szHudPosition);
	menu_additem(iMenu, szHudColor);
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
	return PLUGIN_CONTINUE;
}

public menuPlayerOptionsHudH(id, menu, item) {
	if(item == MENU_EXIT) {
		menuPlayerOptions(id)
		return PLUGIN_CONTINUE
	}
	
	switch(item) {
		case 0: {
			menuPlayerOpHudPos(id)
		}
		case 1: {
			menuPlayerOpHudColor(id)
		}
	}
	
	return PLUGIN_CONTINUE
}

public menuPlayerOpHudPos(id) {
	new szX[33], szY[33], szTitle[33];
	new szChangeOption[33];
	
	formatex(szX, 32, "X: %0.2f", gfPlayerHudPosition[id][0]);
	formatex(szY, 32, "Y: %0.2f", gfPlayerHudPosition[id][1]);
	formatex(szTitle, 32, "%s\w co 0.04 :", gimenuOption[id]?"\yDodawaj":"\rOdejmuj");
	formatex(szChangeOption, 32, "%s", gimenuOption[id]?"\yOdejmuj":"\yDodawaj");
	
	new iMenu = menu_create(szTitle, "menuPlayerOpHudPosH")
	
	menu_additem(iMenu, szX);
	menu_additem(iMenu, szY);
	menu_additem(iMenu, szChangeOption);
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
}

public menuPlayerOpHudPosH(id, menu, item)
{
	if(item == MENU_EXIT) {
		menuPlayerOptionsHud(id)
		return PLUGIN_CONTINUE
	}
	
	switch(item) {
		case 0: {
			if(gimenuOption[id]) {
				gfPlayerHudPosition[id][0] += 0.04
			} else {
				gfPlayerHudPosition[id][0] -= 0.04
			}
			
			if(gfPlayerHudPosition[id][0] < 0.0) {
				gfPlayerHudPosition[id][0] = 0.00
			} else if(gfPlayerHudPosition[id][0] > 1.0) {
				gfPlayerHudPosition[id][0] = 1.00
			}
		}
		case 1: {
			
			if(gimenuOption[id]) {
				gfPlayerHudPosition[id][1] += 0.04
			} else {
				gfPlayerHudPosition[id][1] -= 0.04
			}
			
			if(gfPlayerHudPosition[id][1] < 0.0) {
				gfPlayerHudPosition[id][1] = 0.00
			} else if(gfPlayerHudPosition[id][1] > 1.0) {
				gfPlayerHudPosition[id][1] = 1.00
			}
			
		}
		case 2: {
			gimenuOption[id] = !gimenuOption[id]
		}
	}
	
	menuPlayerOpHudPos(id)
	return PLUGIN_CONTINUE
}

public menuPlayerOpHudColor(id) {
	new szRed[33], szGreen[33], szBlue[33], szTitle[33];
	new szChangeOption[33];
	
	formatex(szRed, 32, "Red: %d", giPlayerHudColor[id][0]);
	formatex(szGreen, 32, "Green: %d", giPlayerHudColor[id][1]);
	formatex(szBlue, 32, "Blue: %d", giPlayerHudColor[id][2]);
	formatex(szTitle, 32, "%s\w co 10: ", gimenuOption[id]?"\yDodawaj":"\rOdejmuj");
	formatex(szChangeOption, 32, "%s", gimenuOption[id]?"\yOdejmuj":"\yDodawaj");
	
	new iMenu = menu_create(szTitle, "menuPlayerOpHudColorH")
	
	menu_additem(iMenu, szRed);
	menu_additem(iMenu, szGreen);
	menu_additem(iMenu, szBlue);
	menu_additem(iMenu, szChangeOption);
	
	menu_setprop(iMenu, MPROP_EXITNAME, "Wroc");
	menu_display(id, iMenu);
}

public menuPlayerOpHudColorH(id, menu, item)
{
	if(item == MENU_EXIT) {
		menuPlayerOptionsHud(id)
		return PLUGIN_CONTINUE
	}
	
	switch(item) {
		case 0: {
			if(gimenuOption[id]) {
				giPlayerHudColor[id][0] += 10
			} else {
				giPlayerHudColor[id][0] -= 10
			}
			
			if(giPlayerHudColor[id][0] == 260)
				giPlayerHudColor[id][0] = 255
			else if(giPlayerHudColor[id][0] == 245)
				giPlayerHudColor[id][0] = 250
				
			if(giPlayerHudColor[id][0] < 0) {
				giPlayerHudColor[id][0] = 0
			} else if(giPlayerHudColor[id][0] > 255) {
				giPlayerHudColor[id][0] = 255
			}
		}
		case 1: {
			
			if(gimenuOption[id]) {
				giPlayerHudColor[id][1] += 10
			} else {
				giPlayerHudColor[id][1] -= 10
			}
			
			if(giPlayerHudColor[id][1] == 260)
				giPlayerHudColor[id][1] = 255
			else if(giPlayerHudColor[id][1] == 245)
				giPlayerHudColor[id][1] = 250
				
			if(giPlayerHudColor[id][1] < 0) {
				giPlayerHudColor[id][1] = 0
			} else if(giPlayerHudColor[id][1] > 255) {
				giPlayerHudColor[id][1] = 255
			}
		}
		case 2: {
			
			if(gimenuOption[id]) {
				giPlayerHudColor[id][2] += 10
			} else {
				giPlayerHudColor[id][2] -= 10
			}
			
			if(giPlayerHudColor[id][2] == 260)
				giPlayerHudColor[id][2] = 255
			else if(giPlayerHudColor[id][2] == 245)
				giPlayerHudColor[id][2] = 250
				
			if(giPlayerHudColor[id][2] < 0) {
				giPlayerHudColor[id][2] = 0
			} else if(giPlayerHudColor[id][2] > 255) {
				giPlayerHudColor[id][2] = 255
			}
		}
		case 3: {
			gimenuOption[id] = !gimenuOption[id]
		}
	}
	
	menuPlayerOpHudColor(id)
	return PLUGIN_CONTINUE
}

public PlayerSpawn(id){
	if(!is_user_connected(id) || !is_user_alive(id) || !gGame || id == 0)
		return PLUGIN_CONTINUE
		
	if(get_playersnum() == 1 && !gOnePlayerMode && get_pcvar_num(gCvarInfo[CVAR_ONE_PLAYER_MODE])) {
		client_print(id, 3, "%s Znajdujesz sie sam na serwerze!", gszPrefix)
		client_print(id, 3, "%s Aby roczpocac rozgrywke wpisz ^"/start^"!", gszPrefix)
		client_print(id, 3, "%s Przewidywany poziom trudnosci: ULTRA HIGH!", gszPrefix)
	}
	if(get_playersnum() >= 2 && !gOnePlayerMode && !gWaveIsStarted && !gGameIsStarted)
	{
		client_cmd(0, "spk sound/%s", gSounds[SOUND_CLEAR_WAVE]);
		set_task(5.0, "StartWave", 9123)
	}

	if(get_playersnum() > 1 && gOnePlayerMode && gGameIsStarted) {
		client_print(0, 3, "%s Do gry dolaczyl kolega!", gszPrefix)
		gOnePlayerMode = false;
	}
	client_print(id, 3, "%s Aby uzyskac dostep do menu gry, wpisz ^"/menu^".", gszPrefix);
	
	set_task(2.0, "PlayerHud", id+gTasks[TASK_HUD_INFO]);
	
	return PLUGIN_CONTINUE
}

public PlayerHud(id) {
	id-=gTasks[TASK_HUD_INFO]
	
	if(!is_user_alive(id))
		return PLUGIN_CONTINUE
		
	set_dhudmessage(giPlayerHudColor[id][0], giPlayerHudColor[id][1], giPlayerHudColor[id][2], gfPlayerHudPosition[id][0], gfPlayerHudPosition[id][1], 0, 6.0, 2.02, 0.0, 0.1, true)
	show_dhudmessage(id, "[WAVE: %d / %d | %s] [ZLOTO: %d]^n[POTWORY: %d (%d) / %d] [WIEZA: %d / %d]^n[POZIOM: %d] [FRAGI: %d / %d]", giWave, giWaveNum, gszRoundName[gWaveInfo[giWave][WAVE_ROUND_TYPE]], gPlayerInfo[id][PLAYER_GOLD], giMonsterAlive, giSendsMonster, (is_special_wave(giWave)?gWaveInfo[giWave][WAVE_MONSTER_NUM]+1:gWaveInfo[giWave][WAVE_MONSTER_NUM]), giBaseHealth, get_pcvar_num(gCvarInfo[CVAR_BASE_HEALTH]),
	gPlayerInfo[id][PLAYER_LEVEL], gPlayerInfo[id][PLAYER_FRAGS], 
	gPlayerInfo[id][PLAYER_LEVEL]==(MAX_LEVEL-1)?gPlayerInfo[id][PLAYER_FRAGS]:giLevelFrags[gPlayerInfo[id][PLAYER_LEVEL]])
	
	set_task(2.0, "PlayerHud", id+gTasks[TASK_HUD_INFO])
	
	return PLUGIN_CONTINUE
}

public cmdOnePlayerMode(id) {
	if(!is_user_alive(id)) {
		client_print(id, 3, "%s Nie mozesz rozpoczac rozgrywki niezyjac!", gszPrefix)
		return PLUGIN_CONTINUE
	} else if(get_playersnum() > 1 || !gGame) {
		client_print(id, 3, "%s Niedozwolone uzycie komendy!", gszPrefix)
		return PLUGIN_CONTINUE
	} else if(gOnePlayerMode) {
		client_print(id, 3, "%s Ta opcja zostala juz aktywowana!", gszPrefix)
		return PLUGIN_CONTINUE
	} else if(!get_pcvar_num(gCvarInfo[CVAR_ONE_PLAYER_MODE])) {
		client_print(id, 3, "%s Ten tryb gry jest wylaczony!", gszPrefix);
		return PLUGIN_CONTINUE;
	}
	
	client_cmd(id, "spk sound/%s", gSounds[SOUND_ACTIVATED])
	client_print(id, 3, "%s Gra zostala rozpoczeta! Powodzenia.", gszPrefix)
	
	gOnePlayerMode = true;
	
	client_cmd(0, "spk sound/%s", gSounds[SOUND_CLEAR_WAVE]);
	set_task(3.0, "StartWave", 9123)
	
	return PLUGIN_CONTINUE
}

new gszData[6]
public StartWave() {
	if(!gGame) {
		return PLUGIN_CONTINUE
	}

	remove_task(9123)
	RemoveMonsters()

	if(giWave >= giWaveNum) {
		giSendsMonster = 0;
		giMonsterAlive = 0;
		EndGame(PLAYERS_WIN);
		return PLUGIN_CONTINUE
	}

	new szText[128];

	gGameIsStarted = true
	giMonsterAlive = 0;
	giSendsMonster = 0;
	gWaveIsStarted = false
	giWave++;

	gszData[0] = gWaveInfo[giWave][WAVE_ROUND_TYPE]
	gszData[1] = is_special_wave(giWave)?gWaveInfo[giWave][WAVE_MONSTER_NUM]+1:gWaveInfo[giWave][WAVE_MONSTER_NUM]
	gszData[2] = gWaveInfo[giWave][WAVE_MONSTER_HEALTH]
	gszData[3] = gWaveInfo[giWave][WAVE_MONSTER_SPEED]
	gszData[4] = gWaveInfo[giWave][WAVE_SPECIAL_HEALTH]
	gszData[5] = gWaveInfo[giWave][WAVE_SPECIAL_SPEED]

	if(giWave != 1)
	{

		new iRet;
		ExecuteForward(gForward[FORWARD_ENDWAVE], iRet, giWave-1)

	}

	formatex(szText, 32, "Wave %d rozpocznie sie za: ", giWave);
	
	set_countdown(0, szText, {255, 255, 0}, 0.15, 0.75, 1, get_pcvar_num(gCvarInfo[CVAR_TIME_TO_WAVE]), 1, 3, _,_,_);
	set_task(float(get_pcvar_num(gCvarInfo[CVAR_TIME_TO_WAVE])), "PreSendMonsters", 1251, gszData, 6)

	/* informacje o rundzie */
	new szTemp[64];
	new iMonsterNum = gszData[1];
		
	formatex(szText, 127, "WAVE: %d | %s [ %d %s ]", giWave, gszRoundName[e_RoundType:gszData[0]],iMonsterNum, (iMonsterNum>=5?"Potworow":iMonsterNum>1?"Potwory":iMonsterNum==1?"Potwor":iMonsterNum==0?"Potwor":""));
	if((!is_special_wave(giWave) && iMonsterNum) || (is_special_wave(giWave) && (iMonsterNum-1) > 0)) {	
		formatex(szTemp, 63, "^nHP: %d^nSPEED: %d", gszData[2], gszData[3])
		add(szText, 127, szTemp);
	}
	
	if(e_RoundType:gszData[0] == ROUND_BOSS) {
		formatex(szTemp, 63, "^n^nBOSS :^nHP: %d^nSPEED: %d", gszData[4], gszData[5])
		add(szText, 127, szTemp)
	}
	else if(e_RoundType:gszData[0] == ROUND_BONUS) {
		formatex(szTemp, 63, "^n^nBONUS:^nHP: %d^nSPEED: %d", gszData[4], gszData[5])
		add(szText, 127, szTemp)
	}
	set_hudmessage(255, 255, 255, 0.50, 0.65, 2, 9.0, get_pcvar_num(gCvarInfo[CVAR_TIME_TO_WAVE])-1.0, 0.05, 3.0, -1)
	ShowSyncHudMsg(0, gSyncInfo[SYNC_WAVE_INFO], szText)
	return PLUGIN_CONTINUE
}
public PreSendMonsters(szData[])
{
	new iRet;
	ExecuteForward(gForward[FORWARD_STARTWAVE], iRet, giWave, e_RoundType:szData[0], szData[1])
	
	gWaveIsStarted = true
	
	switch(szData[0])
	{
		case ROUND_NORMAL:	SendMonsters(ROUND_NORMAL, szData[1], szData[2])
		case ROUND_FAST:	SendMonsters(ROUND_FAST, szData[1], szData[2])
		case ROUND_STRENGHT:	SendMonsters(ROUND_STRENGHT, szData[1], szData[2])
		case ROUND_BONUS:
		{
			if(szData[1]-1)
				SendMonsters(ROUND_NORMAL, szData[1], szData[2])
			
			else if(szData[1]-1 <= 0)
				SendMonsters(ROUND_BONUS, -1, szData[4])
		}
		case ROUND_BOSS:
		{
			if(szData[1]-1)
				SendMonsters(ROUND_NORMAL, szData[1], szData[2])
			
			else if(szData[1]-1 <= 0)
				SendMonsters(ROUND_BOSS,  -1, szData[4])
		}
	}
}
new tempType, tempNum, tempHealth
public SendMonsters(e_RoundType:Type, num, health) // wysylanie potworow
{
	if(gGame == true)
	{
		num-=1
		
		if(num < 1 && num >= (-2)) {
			
			if(Type != ROUND_BONUS && e_RoundType:gszData[0] == ROUND_BONUS)
			{
				SendMonsters(ROUND_BONUS, -1, gszData[4])
				
				return PLUGIN_CONTINUE
			}
			if(Type != ROUND_BOSS && e_RoundType:gszData[0] == ROUND_BOSS)
			{
				SendMonsters(ROUND_BOSS, -1, gszData[4])
				
				return PLUGIN_CONTINUE
			}
		}
		
		new iEnt = create_entity("info_target");
		
		entity_set_string(iEnt, EV_SZ_classname, "monster");
		static szModel[64];
					
		switch(Type) //model zalezny od typu
		{
			case ROUND_NORMAL:	formatex(szModel, 63, "models/TD/%s.mdl", gModels[random(4)][MODEL_NORMAL])
			case ROUND_FAST:	formatex(szModel, 63, "models/TD/%s.mdl", gModels[random(4)][MODEL_FAST])
			case ROUND_STRENGHT:	formatex(szModel, 63, "models/TD/%s.mdl", gModels[random(4)][MODEL_STRENGHT])
			case ROUND_BONUS:	formatex(szModel, 63, "models/TD/%s.mdl", gModels[random(4)][MODEL_BONUS])
			case ROUND_BOSS:	formatex(szModel, 63, "models/TD/%s.mdl", gModels[random(4)][MODEL_BOSS])
		}
		dllfunc(DLLFunc_Spawn, iEnt)
		entity_set_model(iEnt, szModel);	
		entity_set_float(iEnt, EV_FL_health, float(health));
		entity_set_float(iEnt, EV_FL_takedamage, DAMAGE_YES);
		entity_set_size(iEnt, Float:{-16.0, -16.0, -30.0}, Float:{16.0, 16.0, 56.0}); // org -20(-20..)			
		entity_set_origin(iEnt, gfStartOrigin);
		entity_set_vector(iEnt, EV_VEC_angles, Float:{0.0, 0.0, 0.0});
		
		entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX);
		entity_set_int(iEnt, EV_INT_movetype, MOVETYPE_FLY) 
		
		entity_set_int(iEnt, EV_INT_sequence, 4) // oodpowiada za animacje
		entity_set_float(iEnt, EV_FL_animtime, 2.0)
		
		/* Szybkosc animacji wzgledem speeda */
		
		static Float:szSpeed;
		
		if(Type != ROUND_BOSS && Type != ROUND_BONUS)
			szSpeed = float(gszData[3])
		else if(Type == ROUND_BOSS || Type == ROUND_BONUS)
		{
			szSpeed =float(gszData[5])
			set_glow(iEnt, 255, Type==ROUND_BONUS?255:0, 0, 17)
		}
		set_pev(iEnt, pev_monster_speed, floatround(szSpeed))
		
		szSpeed /= 250.0
		
		set_pev(iEnt, pev_framerate, szSpeed);
		
		/* Healthbar */
		
		new iHealtbar = create_entity("env_sprite")
	
		entity_set_string(iHealtbar, EV_SZ_classname, "monster_healthbar");
		entity_set_vector(iHealtbar, EV_VEC_origin, gfStartOrigin)
		entity_set_model(iHealtbar, gszEntityBar[0]);
		entity_set_int(iHealtbar, EV_INT_solid, SOLID_NOT);
		entity_set_int(iHealtbar, EV_INT_movetype, MOVETYPE_FLY) 
		set_pev(iEnt, pev_euser2, 1)
		
		set_pev(iEnt, pev_monster_healthbar, iHealtbar)
		set_pev(iEnt, pev_monster_maxhealth, health)
		set_pev(iHealtbar, pev_scale, 0.30);
		set_pev(iHealtbar , pev_frame , 99.0 );
		
		/* --------- */
		
		giMonsterAlive++;
		giSendsMonster++;
		
		/* --------- */
		
		set_pev(iEnt, pev_monster_track, 1)
		set_pev(iEnt, e_RoundType:pev_monster_type, Type);
		
		
		new Float:Velocity[3]
		new iTarget = find_ent_by_tname(-1, "track1")
		if(!is_valid_ent(iTarget))
		{
			iTarget = find_ent_by_tname(-1, "end")
		}
		entity_set_aim(iEnt, iTarget, Float:{0.0, 0.0, 0.0}, 0);	
			
		velocity_by_aim(iEnt, pev(iEnt, pev_monster_speed), Velocity)
		entity_set_vector(iEnt, EV_VEC_velocity, Velocity)
		
		if(Type == ROUND_BOSS || Type == ROUND_BONUS)
			entity_set_float(iEnt, EV_FL_nextthink, get_gametime()+0.01)
		
		remove_task(TASK_SEND_MONSTER)
		if(num >= 1 && Type != ROUND_BONUS && Type != ROUND_BOSS)
		{
			tempType = Type
			tempNum = num
			tempHealth = health
			set_task(1.0, "SendMonstersPost", TASK_SEND_MONSTER) // 1.0 - czas wyslania nastepnego potwora
		}
	}
	return PLUGIN_CONTINUE
}
public SendMonstersPost() {// sendmonsters 2
	if(gGame) {
		SendMonsters(e_RoundType:tempType, tempNum, tempHealth)
	}
}



public thinkMonsterThink(iEnt) {
	if(!is_valid_ent(iEnt))
		return PLUGIN_CONTINUE		
	
	if(giMonsterAlive == 1 || giSendsMonster == 1)
		goto rep
		
	/* Przechodzeni przez potwory */
	static entlist[3], szTrack[16]
	new num = find_sphere_class(iEnt, "monster", 50.0, entlist, 2)
	
	if(num <= 1)
		goto rep;
	new ciEnt = (entlist[1] == iEnt && entlist[0] != iEnt)  ?  entlist[0]  :  entlist[1]
	if(ciEnt == iEnt)
		goto rep
	/* ========================= */
	
	/* BugFix #1*/
	if(pev(iEnt, pev_solid) == SOLID_NOT)
	{
		formatex(szTrack, 15, "track%d_wall", pev(iEnt, pev_monster_track))
		new giEnt = find_ent_by_tname(-1, szTrack)
		if(!is_valid_ent(giEnt))
			giEnt = find_ent_by_tname(-1, "end_wall")

		static Float:fOrigin[2][3]
		pev(iEnt, pev_origin, fOrigin[0])
		fm_get_brush_entity_origin(giEnt, fOrigin[1])
		if(get_distance_f(fOrigin[0], fOrigin[1]) <= 80.0)
			touchMonsterTrack(iEnt, giEnt)
	}
	/* ======== */
	if(ciEnt != iEnt && ciEnt > 0)
	{
		entity_set_int(iEnt, EV_INT_solid, SOLID_NOT)
		entity_set_float(iEnt, EV_FL_nextthink, get_gametime()+0.005);
		return PLUGIN_CONTINUE
	}
	rep:
	entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX)
	entity_set_float(iEnt, EV_FL_nextthink, get_gametime()+0.005);
	
	return PLUGIN_CONTINUE
}


public RemoveMonsters() {
	new iEnt = find_ent_by_class(-1, "monster");
	
	while(is_valid_ent(iEnt) && pev(iEnt, pev_monster_type)) {

		set_pev(iEnt, pev_euser2, 0)
		set_pev(iEnt, pev_monster_type, 0)
		set_pev(iEnt, pev_monster_track, 0)
		set_pev(iEnt, pev_monster_maxhealth, 0)
		set_pev(iEnt, pev_monster_speed, 0)
		set_pev(iEnt, pev_monster_healthbar, 0)
	
		remove_entity(iEnt)

		iEnt = find_ent_by_class(-1, "monster");

	}

	iEnt = find_ent_by_class(-1, "monster_healthbar")

	while(is_valid_ent(iEnt)) {
		remove_entity(iEnt)
		iEnt = find_ent_by_class(-1, "monster_healthbar")
	}
}

public EndGame(e_EndType: iType) {
	
	giMonsterAlive = 0;
	giSendsMonster = 0;
	gWaveIsStarted = false;
	gGame = false;
	
	RemoveMonsters();
	
	new iFrag, iPlayer, szNick[33];
	new szMapName[33], szText[64];

	for(new i = 1; i <= giMaxPlayers; i++) {
		if(is_user_connected(i) && ( 1<= i <= 32 )) {
			if(iFrag < get_user_frags(i)) {
				iFrag = get_user_frags(i)
				iPlayer = i;
			}
		}
	}
	if(iPlayer == 0 && iFrag == 0)
	{
		iPlayer = 1
		iFrag == get_user_frags(1) ? get_user_frags(1) : 0
	}

	get_cvar_string("amx_nextmap", szMapName, 32);
	get_user_name(iPlayer, szNick, 32);
	
	formatex(szText, 64, "Zmiana mapy na '%s' nastapi za: ", szMapName)
	
	if(iType == PLAYERS_LOSE) 
	{
		if(gModelTurret)
		{
			set_task(0.1, "Explode")
			set_task(0.5, "Explode")
			set_task(1.0, "Explode")
			set_task(2.0, "Explode")
			set_task(2.5, "Explode")
			set_task(3.0, "Explode")
			set_task(4.0, "Explode")
			set_task(4.4, "Explode")
			set_task(4.8, "Explode")
			set_task(5.0, "Explode")
			set_task(6.6, "Explode")
			set_task(6.7, "RemoveTower")
		}
		
		set_hudmessage(255, 255, 0, 0.25, 0.65, 0, 6.0, 10.0, 0.0, 0.4, -1)
		ShowSyncHudMsg(0, gSyncInfo[SYNC_END_GAME], "Obroncy zamku PRZEGRALI wojne z potworami!^nNajlepszym graczem jest '%s' z %d zabiciami", szNick, iFrag)
	} else if(iType == PLAYERS_WIN) {
		set_hudmessage(255, 255, 0, 0.25, 0.65, 0, 6.0, 10.0, 0.0, 0.4, -1)
		ShowSyncHudMsg(0, gSyncInfo[SYNC_END_GAME], "Obroncy zamku WYGRALI wojne z potworami!^nNajlepszym graczem jest '%s' z %d zabiciami", szNick, iFrag)
	}
	
	set_countdown(0, szText, {255, 0, 255}, 0.25, 0.90, _, 15, _, _,_,_,_);
	set_task(15.0, "ChangeMap", _, szMapName, 32)
}
public RemoveTower()
{
	new iTower = find_ent_by_class(-1, "tower")
	if(is_valid_ent(iTower))
		remove_entity(iTower)
}
public CheckGamePossibility(){
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Sprawdzanie statusu gry...")
#endif
	
	if(gGame == false)
	{
		new szNextMap[33], szText[64];
		get_cvar_string("amx_nextmap", szNextMap, 32);
		
		set_dhudmessage(170, 255, 255, 0.28, 0.61, 0, 6.0, 12.0)
		show_dhudmessage(0, "Gra nie jest mozliwa z powodu bledow mapy lub zlej konfigiguracji", szNextMap)
		
		formatex(szText, 63, "Mapa zostanie zmieniona na '%s' za: ", szNextMap);
		
		set_countdown(0, szText, {255, 255, 0}, 0.28, 0.40, _, 45, 1, 3, "ChangeMap", szNextMap, 32);	
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Gra nie jest mozliwa z powodu bledow mapy lub zlej konfigiguracji...")
#endif
	}
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Zakonczono sprawdzanie statusu gry...")
	
	log_to_file(gszLogFile, "DEBUG: Sprawdzanie plikow konfiguracyjnych zostalo zakonczone...")
#endif
}

public ChangeMap(szMapName[]) {
	server_cmd("changelevel %s", szMapName)
}

public RefreshFrag(id) //odswiez fragi
{
	new ideaths = cs_get_user_deaths(id);
	new ifrags = pev(id, pev_frags);
	new kteam = _:cs_get_user_team(id);
	
	message_begin( MSG_ALL, get_user_msgid("ScoreInfo"), {0,0,0}, 0 );
	write_byte( id );
	write_short( ifrags );
	write_short( ideaths);
	write_short( 0 );
	write_short( kteam );
	message_end();
}

public CheckMap() {
#if defined DEBUG
		log_to_file(gszLogFile, "DEBUG: Zakonczono sprawdzanie pliku konfiguracyjnego wave'y")
		log_to_file(gszLogFile, "DEBUG: Sprawdzam mape...")
#endif
	/* start */
	new iEnt = find_ent_by_tname(-1, "start")
	
	if(is_valid_ent(iEnt) && iEnt != 0) {
		pev(iEnt, pev_origin, gfStartOrigin)
		
		new iSprite = create_entity("env_sprite")
		
		entity_set_string(iSprite, EV_SZ_classname, "start_sprite")
		entity_set_model(iSprite, giSpriteSpawn)
			
		entity_set_origin(iSprite, gfStartOrigin)
		entity_set_int(iSprite, EV_INT_solid, SOLID_NOT);
		entity_set_int(iSprite, EV_INT_movetype, MOVETYPE_FLY) 
		
		set_pev(iSprite, pev_framerate, 1.0)
		set_pev(iSprite, pev_scale, 2.5)
	} else {
#if defined DEBUG
		log_to_file(gszLogFile, "DEBUG: Nie znaleziono bytu startowego 'start'...")
#endif
		gGame = false;
		return PLUGIN_CONTINUE
	}
	/* end */
	iEnt = find_ent_by_tname(-1, "end")
	if(is_valid_ent(iEnt) && iEnt != 0) {
		
		pev(iEnt, pev_origin, gfEndOrigin)
		
		if(gModelTurret)
		{
			new iTower = create_entity("info_target")
			new szModel[64], Float:tempOrigin[3];
		
			formatex(szModel, 63, "models/TD/%s.mdl", gModels[random(3)][MODEL_TOWER])
			
			entity_set_string(iTower, EV_SZ_classname, "tower")
			entity_set_model(iTower, szModel);
			entity_set_origin(iTower, gfEndOrigin);
			entity_set_int(iTower, EV_INT_solid, SOLID_NOT);
			entity_set_int(iTower, EV_INT_movetype, MOVETYPE_FLY) 
			drop_to_floor(iTower)
			
			pev(iTower, pev_origin, tempOrigin)
			
			gfTowerOrigin = tempOrigin
			set_pev(iTower, pev_origin, gfTowerOrigin)	
		}
		
	} else {
#if defined DEBUG
		log_to_file(gszLogFile, "DEBUG: Nie znaleziono bytu koncowego 'end'...")
#endif	
		gGame = false;
		return PLUGIN_CONTINUE
	}
	/* track */
	iEnt = find_ent_by_tname(-1, "track1")
	
	if(!is_valid_ent(iEnt)) {
#if defined DEBUG
		log_to_file(gszLogFile, "DEBUG: Nie znaleziono bytu kierujacego potworem 'track1'. Moga wystapic bledy...")
#endif
	}
	else {
		new szTrack[16], i;
		while(iEnt > 0)
		{
			formatex(szTrack, 15, "track%d_wall", ++i)
			iEnt = find_ent_by_tname(-1, szTrack)
			if(is_valid_ent(iEnt))
				fm_set_rendering(iEnt, kRenderFxNone, 0, 0, 0, kRenderTransAdd, 0)
			else {
				formatex(szTrack, 15, "track%d", i)
				if(is_valid_ent( find_ent_by_tname(-1, szTrack) ))
				{
#if defined DEBUG
					log_to_file(gszLogFile, "DEBUG: Nie znaleziono bytu %s_wall...", szTrack)
#endif					
					gGame = false;
				}
				
				iEnt = find_ent_by_tname(-1, "end_wall")
				
				if(!is_valid_ent( iEnt )) {
#if defined DEBUG
					log_to_file(gszLogFile, "DEBUG: Nie znaleziono bytu %s_wall...", szTrack)
#endif					
					gGame = false;
				}
				fm_set_rendering(iEnt, kRenderFxNone, 0, 0, 0, kRenderTransAdd, 0)
				break;
			}
		}
	}

#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Zakonczono sprawdzanie mapy...")
#endif

	return PLUGIN_CONTINUE
}


public LoadSound() {
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Rozpoczynam wczytywanie dzwiekeow...")
#endif

	new szText[128], len;
	new szTemp[3][128];
	
	if(!file_exists(gszSoundConfigFile))
	{
		log_to_file(gszLogFile, "Brak pliku konfiguracyjnego dzwiekow...")
		gGame = false
		return PLUGIN_CONTINUE
	}
	
	for(new i ; read_file(gszSoundConfigFile, i, szText, 127, len) ; i++)
	{
		if(equali(szText, ";") || equali(szText, ""))
			continue;
			
		parse(szText, szTemp[0], 127, szTemp[1], 16, szTemp[2], 127)
		remove_quotes(szTemp[2]);
		
		if(equali(szTemp[0], "START_WAVE")) 
			copy(gSounds[SOUND_START_WAVE], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_DIE_1")) 
			copy(gSounds[SOUND_MONSTER_DIE_1], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_DIE_2")) 
			copy(gSounds[SOUND_MONSTER_DIE_2], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_DIE_3")) 
			copy(gSounds[SOUND_MONSTER_DIE_3], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_DIE_4")) 
			copy(gSounds[SOUND_MONSTER_DIE_4], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_HIT_1")) 
			copy(gSounds[SOUND_MONSTER_HIT_1], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_HIT_2")) 
			copy(gSounds[SOUND_MONSTER_HIT_2], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_HIT_3")) 
			copy(gSounds[SOUND_MONSTER_HIT_3], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_HIT_4")) 
			copy(gSounds[SOUND_MONSTER_HIT_4], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_SOUND_1")) 
			copy(gSounds[SOUND_MONSTER_1], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_SOUND_2")) 
			copy(gSounds[SOUND_MONSTER_2], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_SOUND_3")) 
			copy(gSounds[SOUND_MONSTER_3], 127, szTemp[2])
		else if(equali(szTemp[0], "MONSTER_SOUND_4")) 
			copy(gSounds[SOUND_MONSTER_4], 127, szTemp[2])
		else if(equali(szTemp[0], "BOSS_DIE")) 
			copy(gSounds[SOUND_BOSS_DIE], 127, szTemp[2])
		else if(equali(szTemp[0], "BONUS_DIE")) 
			copy(gSounds[SOUND_BONUS_DIE], 127, szTemp[2])
		else if(equali(szTemp[0], "COIN")) 
			copy(gSounds[SOUND_COIN], 127, szTemp[2])
		else if(equali(szTemp[0], "ACTIVATED")) 
			copy(gSounds[SOUND_ACTIVATED], 127, szTemp[2])
		else if(equali(szTemp[0], "COUNTDOWN")) 
			copy(gSounds[SOUND_COUNTDOWN], 127, szTemp[2])
		else if(equali(szTemp[0], "PLAYER_LEVELUP")) 
			copy(gSounds[SOUND_PLAYER_LEVELUP], 127, szTemp[2])
		else if(equali(szTemp[0], "PLAYER_USE_LIGHTING")) 
			copy(gSounds[SOUND_PLAYER_USE_LIGHTING], 127, szTemp[2])
		else if(equali(szTemp[0], "CLEAR_WAVE")) 
			copy(gSounds[SOUND_CLEAR_WAVE], 127, szTemp[2])
		
	}
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Zakonczono wczytywanie dzwiekow...")
#endif
	return PLUGIN_CONTINUE
}
public LoadWave(szMapName[]) {
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Wczytywanie wavow z pliku ^"%s.ini^"...", szMapName)
#endif
	
	new szFileDir[64];
	new iLoadStandardWave;
	static LoadStandardConf
	formatex(szFileDir, 63, "%s/%s.ini", gszWaveConfigDir, szMapName)
	
	if(!file_exists(szFileDir)) {
		log_to_file(gszLogFile, "Plik konfiguracyjny ^"%s^" nie zostal znaleziony.", szFileDir)
		log_to_file(gszLogFile, "Wczytywanie standardowych wavow")
		
		iLoadStandardWave = 1;
	}
	
	if(iLoadStandardWave) {
		formatex(szFileDir, 63, "%s/standard_wave.ini", gszWaveConfigDir)
		
		if(!file_exists(szFileDir)) {
			log_to_file(gszLogFile, "Plik konfiguracyjny ^"%s^" nie zostal znaleziony. Zmiana mapy", szFileDir)
			gGame = false
			
			return PLUGIN_CONTINUE
		} else {
			LoadWave("standard_wave");
			iLoadStandardWave = 0;
			
			return PLUGIN_CONTINUE
		}
	}
	
	new szText[128], len;
	new szData[10][64]
	
	new iWasConf = 7;
	
	for(new i; read_file(szFileDir, i, szText, 127, len) ; i++) {
		if(szText[0] == ';' || (equali(szText, "")))
			continue;
		
		remove_quotes(szText)
			
		replace_all(szText, 127, "=", "")
		replace_all(szText, 127, "(", "")
		replace_all(szText, 127, ")", "")
		replace_all(szText, 127, ",", "")
		
		parse(szText, szData[0], 63, szData[1], 63, szData[2], 63, 
		szData[3], 63, szData[4], 63, szData[5], 63, szData[6], 63,
		szData[7], 63, szData[8], 63, szData[9], 63)
	
		/* Wczytywanie Konfiguracji */
		
		if(iWasConf > 0 && !LoadStandardConf) {
			iWasConf --;
			
			if(equali(szData[0], "BASE_HEALTH")) {
				set_pcvar_num(gCvarInfo[CVAR_BASE_HEALTH], str_to_num(szData[1]));
				giBaseHealth = str_to_num(szData[1])
			}
			else if(equali(szData[0], "TIME_TO_WAVE")) {
				set_pcvar_num(gCvarInfo[CVAR_TIME_TO_WAVE], str_to_num(szData[1]));
			}
			else if(equali(szData[0], "MONSTER_DAMAGE")) {
				set_pcvar_num(gCvarInfo[CVAR_MONSTER_DAMAGE], str_to_num(szData[1]));
			}
			else if(equali(szData[0], "BOSS_DAMAGE")) {
				set_pcvar_num(gCvarInfo[CVAR_BOSS_DAMAGE], str_to_num(szData[1]));
			}
			else if(equali(szData[0], "TURRETS")){
				gTurretsAvailable = str_to_num(szData[1])?true:false
			}
			else if(equali(szData[0], "TOWER_MODEL")){
				gModelTurret = str_to_num(szData[1])?true:false
			}
			else if(equali(szData[0], "[LOAD_STANDARD_WAVE]")){
				LoadStandardConf = 1
				formatex(szFileDir, 63, "%s/standard_wave.ini", gszWaveConfigDir)
				LoadWave(szFileDir)
			}
			else if(equali(szData[0], "MAX_MAP_TURRETS"))
				MAX_MAP_TURRETS = clamp(str_to_num(szData[1]), 1, 100)
			continue;
		}
		else
			iWasConf = 0
#if defined DEBUG
		if(iWasConf > 0) {
			gTurretsAvailable = false;
			log_to_file(gszLogFile, "DEBUG: Plik zawiera nieprawidlowa ilosc wymaganych danych.")
			log_to_file(gszLogFile, "DEBUG: Brakujace informacje zostaly zastapione standardowymi.")
			
			iWasConf = 0;
		}
#endif	
		/* Wczytywanie Wavow */
		
		static iWave, iOldWave, iNum;
		iWave = str_to_num(szData[0]);
		
		if(iWave > 0) {
			if(iWave != iOldWave && iWave-1 == iOldWave) {
				iOldWave = iWave
				if(equali(szData[1], "NORMAL")) {
					gWaveInfo[iWave][WAVE_ROUND_TYPE] = ROUND_NORMAL;
				} else if(equali(szData[1], "FAST")) {
					gWaveInfo[iWave][WAVE_ROUND_TYPE] = ROUND_FAST;
				} else if(equali(szData[1], "STRENGHT")) {
					gWaveInfo[iWave][WAVE_ROUND_TYPE] = ROUND_STRENGHT;
				} else if(equali(szData[1], "BOSS")) {
					gWaveInfo[iWave][WAVE_ROUND_TYPE] = ROUND_BOSS;
				} else if(equali(szData[1], "BONUS")) {
					gWaveInfo[iWave][WAVE_ROUND_TYPE] = ROUND_BONUS;
				} else {
					log_to_file(gszLogFile, "Nieprawidlowy typ rundy! ^"%s^" | linia: %d", szData[1], i)
					gGame = false
					return PLUGIN_CONTINUE
				}
				
				/* ================================= */
				
				
				iNum = str_to_num(szData[2]);
				
				if(iNum < 0 || (!is_special_wave(iWave) && iNum == 0) || iNum > MAX_MONSTERS) {
					log_to_file(gszLogFile, "Nieprawidlowa ilosc potworow! ^"%d^" | linia: %d", iNum, i)
					gGame = false
					return PLUGIN_CONTINUE
				}
				
				gWaveInfo[iWave][WAVE_MONSTER_NUM] = iNum;
				
				/* ================================= */
				
				iNum = str_to_num(szData[3]);
				if(iNum <= 0 && !is_special_wave(iWave)) {
					log_to_file(gszLogFile, "Nieprawidlowa ilosc HP! ^"%d^" | linia: %d", iNum, i)
					gGame = false
					return PLUGIN_CONTINUE
				}
				gWaveInfo[iWave][WAVE_MONSTER_HEALTH] = iNum
				
				/* ================================= */
				
				iNum = str_to_num(szData[4]);
				if(iNum <= 0 && !is_special_wave(iWave)) {
					log_to_file(gszLogFile, "Nieprawidlowa predkosc! ^"%d^" | linia: %d", iNum, i)
					gGame = false
					return PLUGIN_CONTINUE
				}
				gWaveInfo[iWave][WAVE_MONSTER_SPEED] = iNum
				
				/* ================================= */
				
				if(is_special_wave(iWave)) {	
					iNum = str_to_num(szData[5]);
					
					if(iNum <= 0) {
						log_to_file(gszLogFile, "Nieprawidlowa wartosc HP [specjalne]! ^"%d^" | linia: %d", iNum, i)
						gGame = false
						return PLUGIN_CONTINUE
					}
					gWaveInfo[iWave][WAVE_SPECIAL_HEALTH] = iNum
					
					/* ================================= */
					
					iNum = str_to_num(szData[6]);
					if(iNum <= 0) {
						log_to_file(gszLogFile, "Nieprawidlowa predkosc [specjalne]! ^"%d^" | linia: %d", iNum, i)
						gGame = false
						return PLUGIN_CONTINUE
					}
					
					gWaveInfo[iWave][WAVE_SPECIAL_SPEED] = iNum
					
					/* ================================= */
				}
				
				giWaveNum++;
				
				
			} else {
				log_to_file(gszLogFile, "Nieprawidlowy numer wave! Byl ^"%d^", jest ^"%d^". | linia: %d", iOldWave, iWave, i)
				gGame = false
				return PLUGIN_CONTINUE
			}
		} 
		
	}
	

	return PLUGIN_CONTINUE
}

public LoadCvar() {
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Wczytywanie pliku konfiguracyjnego: cvary...")	
#endif
	if(file_exists(gszCvarConfigFile))
		server_cmd("exec %s",gszCvarConfigFile)
#if defined DEBUG
	else {

	log_to_file(gszLogFile, "DEBUG: Brak pliku konfiguracyjnego cvarow, uzywam domyslne...")
	}
	log_to_file(gszLogFile, "DEBUG: Zakonczono wczytywanie pliku konfiguracyjnego cvarow...")
#endif	
}

public LoadModels()//wczytuje modele
{
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Rozpoczynam wczytywanie modeli...")
#endif

	new szText[128], len;
	new szTemp[4][128];
	new iNumber;
	
	if(!file_exists(gszModelsConfigFile))
	{
		log_to_file(gszLogFile, "Brak pliku konfiguracyjnego modeli...")
		gGame = false
		return PLUGIN_CONTINUE
	}
	for(new i ; read_file(gszModelsConfigFile, i, szText, 127, len) ; i++)
	{
		if(equali(szText, ";"))
			continue;
			
		parse(szText, szTemp[0], 127, szTemp[1], 16, szTemp[2], 16, szTemp[3], 127)
		iNumber = str_to_num(szTemp[1]);
		
		if(equali(szTemp[0], "NORMAL_MDL")) 
			copy(gModels[iNumber-1][MODEL_NORMAL], 33, szTemp[3])
		else if(equali(szTemp[0], "FAST_MDL"))
			copy(gModels[iNumber-1][MODEL_FAST], 33, szTemp[3])
		else if(equali(szTemp[0], "STRENGHT_MDL"))		
			copy(gModels[iNumber-1][MODEL_STRENGHT], 33, szTemp[3])
		else if(equali(szTemp[0], "BONUS_MDL"))
			copy(gModels[iNumber-1][MODEL_BONUS], 33, szTemp[3])
		else if(equali(szTemp[0], "BOSS_MDL"))
			copy(gModels[iNumber-1][MODEL_BOSS], 33, szTemp[3])
		else if(equali(szTemp[0], "TOWER_MDL"))
			copy(gModels[iNumber-1][MODEL_TOWER], 33, szTemp[3])
		
	}
#if defined DEBUG
	log_to_file(gszLogFile, "DEBUG: Zakonczono wczytywanie modeli...")
#endif
	return PLUGIN_CONTINUE
}

new ciTime;
new ciColor[3]
new Float:cfPosition[2];
new ciEffect;
new ciMode;
new ciChannel;
new cszText[64];
new ciNum
new giSec
stock set_countdown(id, szText[], iColor[3], Float:posX, Float:posY, iEffect = 0, tTime, iMode = 1, channel = 4, const szFunction[] = "", ifParam[] = "", ifLen = 0)
{
	/*
	iMode = 0 || Czas odlicza od 0 do tTime
	iMode == 1 || Czas odlicza od tTime do 0
	*/
	
	ciNum = formatex(cszText, strlen(szText), szText);
	ciTime = tTime;
	ciColor = iColor;
	cfPosition[0] = posX
	cfPosition[1] = posY
	ciEffect = iEffect
	ciMode = iMode;
	ciChannel = channel;
	
	display_countdown(id+gTasks[TASK_COUNTDOWN])
	
	if(strlen(szFunction) > 0)
		set_task(float(tTime), szFunction, gTasks[TASK_COUNTDOWN], ifParam, ifLen);
	// ciTime - giSec = ile zostalo do wykonania taska
}

public display_countdown(id) 
{	
	static gszSec[6];
	id-=gTasks[TASK_COUNTDOWN]

	if(giSec >= ciTime) {
		remove_task(gTasks[TASK_COUNTDOWN]);
		remove_task(id+gTasks[TASK_COUNTDOWN]);
		
		giSec = 0;
		ciTime = 0
		ciColor = {0, 0, 0}
		cfPosition[0] = 0.0
		cfPosition[1] = 0.0
		ciEffect = 0
		ciMode = 0
		ciChannel = 0
	
		return PLUGIN_CONTINUE
	}
	
	if(ciMode == 1){
		formatex(gszSec, 5, "%d", ciTime-giSec);
		add(cszText, 64,  gszSec);
	} else if(ciMode == 0) {
		formatex(gszSec, 5, "%d", giSec);
		add(cszText, 64,  gszSec);
	}
	
	set_hudmessage(ciColor[0], ciColor[1], ciColor[2], cfPosition[0], cfPosition[1], ciEffect, 6.0, 1.1, _, _, ciChannel)
	show_hudmessage(id, cszText)
	
	formatex(cszText[ciNum], ciNum, "")
	formatex(cszText[ciNum+1], ciNum, "")
	formatex(cszText[ciNum+2], ciNum, "")
	formatex(cszText[ciNum+3], ciNum, "")
	
	if(!gWaveIsStarted && gGame) {
		new iCount = 3;
		if((ciTime-giSec) <= 5 && (ciTime-giSec) > 1) {
			client_cmd(0, "spk sound/%s", gSounds[SOUND_COUNTDOWN]);
		} else if((ciTime-giSec) > 5 && (giSec%iCount) == 0) {
			client_cmd(0, "spk sound/%s", gSounds[SOUND_COUNTDOWN]);
		}
	}
	giSec++;
	set_task(1.0, "display_countdown", id+gTasks[TASK_COUNTDOWN]);
	return PLUGIN_CONTINUE
}
stock GivePlayerAmmo(id, liczba){ //ustawia amunicje
	if(is_user_alive(id) && is_user_connected(id) && !is_user_hltv(id)){
		new weapon = get_user_weapon(id)
		if(weapon != 29) cs_set_user_bpammo(id, weapon, cs_get_user_bpammo(id, weapon)+liczba);
		if(cs_get_user_bpammo(id, weapon) > giMaxAmmo[weapon])
			cs_set_user_bpammo(id, weapon, giMaxAmmo[weapon])
	}
}
/*
public PauseGame()
{	if(!gGame)
		return PLUGIN_CONTINUE
	gGameIsPaused = true
	
	if(task_exists(gTasks[TASK_COUNTDOWN]))
		set_task(0.1, "repeatpause")
	client_print(0, 3, "%d", ciTime-giSec)
	new iEnt = find_ent_by_class(-1, "monster")
	while(is_valid_ent(iEnt) && (pev(iEnt, pev_euser2) == 1))
	{
		entity_set_vector(iEnt, EV_VEC_velocity, Float:{0.0,0.0,0.0})
		entity_set_int(iEnt, EV_INT_solid, SOLID_NOT)
		entity_set_float(iEnt, EV_FL_nextthink, 0.0)
		set_pev(iEnt, pev_euser2, 0)
		set_pev(iEnt, pev_framerate, 0.0)
		iEnt = find_ent_by_class(iEnt, "monster")
	}
	return PLUGIN_CONTINUE
}
public repeatpause(id)
{
	change_task(gTasks[TASK_COUNTDOWN], 999.9)
	change_task(ciId+gTasks[TASK_COUNTDOWN], 999.0)
	change_task(gTasks[TASK_SEND_MONSTER], 999.9)
	change_task(1251, 
	
}
public UnPauseGame()
{
	if(!gGame)
		return PLUGIN_CONTINUE
		
	gGameIsPaused = false
	
	change_task(gTasks[TASK_COUNTDOWN], float(ciTime-giSec))
	change_task(ciId+gTasks[TASK_COUNTDOWN], 0.5)
	change_task(gTasks[TASK_SEND_MONSTER], 0.75)
	remove_task(1363)
	
	new iEnt = find_ent_by_class(-1, "monster")
	while(is_valid_ent(iEnt) && (pev(iEnt, pev_euser2) == 0))
	{
		entity_set_int(iEnt, EV_INT_solid, SOLID_BBOX)
		entity_set_float(iEnt, EV_FL_nextthink, get_gametime()+0.01)
		set_pev(iEnt, pev_euser2, 1)
		
		new szSpeed = pev(iEnt, pev_monster_speed)
		szSpeed /= 250.0
		set_pev(iEnt, pev_framerate, szSpeed);
		
		iEnt = find_ent_by_class(iEnt, "monster")
	}
	return PLUGIN_CONTINUE
}*/
public ResetGame() {
	
	if(gGame && giWave > 0)
	{
		new iRet;
		ExecuteForward(gForward[FORWARD_RESET_GAME], iRet)
		
		giWave = 0
		giBaseHealth = get_pcvar_num(gCvarInfo[CVAR_BASE_HEALTH])
		giMonsterAlive = 0
		giSendsMonster = 0
		gWaveIsStarted = false
		gGameIsStarted = false
		
		
		RemoveMonsters()
		
		remove_task(1251)
		remove_task(gTasks[TASK_SEND_MONSTER])
		remove_task(gTasks[TASK_COUNTDOWN]);
	
		for(new i=1; i <= giMaxPlayers;i++)
		{
			
			ResetPlayerInformation(i)
		}

		set_task(3.0, "StartWave", 9123)
	}	
}

/*stock death_msg(id, ent) {  //usatwia efekt zabicia w prawym gornym rogu
	if(get_playersnum() <= 1 || !is_valid_ent(ent))
		return PLUGIN_CONTINUE
	static szName[33], szNick[33];
	
	static iFind
	for(new i = 1; i < 33 ; i++) {
		if(is_user_connected(i) && !is_user_hltv(i) && i != id && get_user_team(i) != get_user_team(id))
			if(iFind != i) {
				iFind = i;
				break;
			}
	}
	
	if(!iFind) {
		return PLUGIN_CONTINUE;
	}
	
	get_user_name(iFind, szName, 32);
	
	formatex(szNick, 32, "%s %s", gszMonsterPrefix, gszRoundName[e_RoundType:pev(ent, pev_monster_type)]);

	set_user_info(iFind, "name", szNick)
	new Params[34]
	copy(Params, 32, szName)
	Params[33] = id
	set_task(0.1, "ResetDeath", iFind, Params, 34)
	
	return PLUGIN_CONTINUE
	
}
public ResetDeath(Params[], id) //usatwia efekt zabicia w prawym gornym rogu 2
{
	new id2 = Params[33]
	new szNick[33];
	copy(szNick, 32, Params);
	
	set_msg_block(get_user_msgid("DeathMsg"),BLOCK_ONCE)
	message_begin(MSG_ALL, get_user_msgid("DeathMsg")) 
	write_byte(id2)
	write_byte(id)
	write_byte(0)
	message_end()
	
	set_user_info(id, "name", szNick);
	remove_task(id)
}*/
public SayText(msgid, msgdest, msgentity) //bokuje wyswietlanie informacji o zmianie nicku
{
	new Marg[32]
	get_msg_arg_string(2, Marg, 31)
	if( equal(Marg, "#Cstrike_Name_Change"))
	{
		return PLUGIN_HANDLED
	}
	return PLUGIN_CONTINUE
}
stock entity_set_aim(ent1, ent2, Float:offset2[3], region)
{
	if(!is_valid_ent(ent1) || !is_valid_ent(ent2) || ent1 == ent2)
		return 0;
	
	static Float:offset[3]
	offset[0]=offset2[0], offset[1]=offset2[1], offset[2]=offset2[2]
	static Float:ent1origin[3]
	static Float:ent2origin[3]
	static Float:view_angles[3]
	
	entity_get_vector(ent2,EV_VEC_origin,ent2origin)
	
	pev(ent1, pev_origin, ent1origin)
		
	switch(region)
	{
		case 1:
		{
			offset[2] += 30.173410
		}
		case 2:
		{
			offset[2] += 17.271676
		}
		case 3:
		{
			offset[0] += 12.000000
			offset[2] += 11.028901
		}
		case 4:
		{
			offset[0] += -12.000000
			offset[2] += 11.028901
		}
		case 5:
		{
			offset[0] += 8.000000
			offset[2] += -19.768786
		}
		case 6:
		{
			offset[0] += -8.000000
			offset[2] += -19.768786
			
		}
	}
	
	static Float:ent2_angles[3]
	entity_get_vector(ent2,EV_VEC_v_angle,ent2_angles)
	ent2origin[0] += offset[0] * (((floatabs(ent2_angles[1]) - 90) / 90) * -1)
	ent2origin[1] += offset[1] * (1 - (floatabs(90 - floatabs(ent2_angles[1])) / 90))
	ent2origin[2] += offset[2]
	
	ent2origin[0] -= ent1origin[0]
	ent2origin[1] -= ent1origin[1]
	ent2origin[2] -= ent1origin[2]
	
	static Float:hyp
	hyp = floatsqroot( (ent2origin[0] * ent2origin[0]) + (ent2origin[1] * ent2origin[1]))
	
	static x, y, z
	x=0, y=0, z=0
	
	if(ent2origin[0]>=0.0) 
		x=1
	if(ent2origin[1]>=0.0) 
		y=1
	if(ent2origin[2]>=0.0) 
		z=1
	
	if(ent2origin[0]==0.0) 
		ent2origin[0] = 0.000001
	if(ent2origin[1]==0.0) 
		ent2origin[1] = 0.000001
	if(ent2origin[2]==0.0) 
		ent2origin[2] = 0.000001
	
	ent2origin[0]=floatabs(ent2origin[0])
	ent2origin[1]=floatabs(ent2origin[1])
	ent2origin[2]=floatabs(ent2origin[2])
	
	view_angles[1] = floatatan2(ent2origin[1],ent2origin[0],degrees)
	
	//1=positive 0=negative
	if(x && !y) 
		view_angles[1] = -1 * ( 180 - view_angles[1] )
	if(!x && !y) 
		view_angles[1] = ( 180 - view_angles[1] )
	if(!x && y) 
		view_angles[1] = view_angles[1] = 180 + floatabs(180 - view_angles[1])
	if(x && !y) 
		view_angles[1] = view_angles[1] = 0 - floatabs(-180 - view_angles[1])
	if(!x && !y) 
		view_angles[1] *= -1
	
	while(view_angles[1]>180.0) 
		view_angles[1] -= 180
	while(view_angles[1]<-180.0) 
		view_angles[1] += 180
	if(view_angles[1]==180.0 || view_angles[1]==-180.0) 
		view_angles[1]=-179.999999
	
	view_angles[0] = floatasin(ent2origin[2] / hyp,degrees)
	
	if(z) 
		view_angles[0] *= -1

	entity_set_int(ent1,EV_INT_fixangle,1)
	entity_set_vector(ent1,EV_VEC_v_angle,view_angles)
	entity_set_vector(ent1,EV_VEC_angles,view_angles)
	entity_set_int(ent1,EV_INT_fixangle,1)
	
	return 1;
}

public getClossestMonster(ent)
{
	if(!td_is_monster(ent) )
		return 0;
		
	new entlist[3]
	new num = find_sphere_class(ent, "monster", 30.0, entlist, 2)
	
	if(!num)
		return 0
	
	if(!is_valid_ent(entlist[1]) || pev(entlist[1], pev_monster_type) == 0)
		return 0;
		
	return entlist[1];

}

stock fx_blood(origin[3], size){ //efekt krwi
	message_begin(MSG_BROADCAST,SVC_TEMPENTITY)
	write_byte(TE_BLOODSPRITE)
	write_coord(origin[0]+random_num(-20,20))
	write_coord(origin[1]+random_num(-20,20))
	write_coord(origin[2]+random_num(-20,20))
	write_short(giSpriteBloodSpray)
	write_short(giSpriteBloodDrop)
	write_byte(229) // color index
	write_byte(size) // size
	message_end()
}
stock set_glow(id, r,g,b, width)
	set_rendering(id, kRenderFxGlowShell, r, g, b, kRenderNormal, width)
	
public Explode() //wybuch nad wieza
{
	new Origin[3]
	FVecIVec(gfTowerOrigin, Origin)
	Origin[2]+= 275 // wysokoc wybuchu nad wieza
	message_begin(MSG_BROADCAST ,SVC_TEMPENTITY)
	write_byte(TE_EXPLOSION)
	write_coord(Origin[0])	// start position
	write_coord(Origin[1])
	write_coord(Origin[2])
	write_short(giSpriteExplode)	// sprite index
	write_byte(50)	// scale in 0.1's
	write_byte(10)	// framerate
	write_byte(0)	// flags
	message_end()
}
stock Create_Lighting(startEntity, endEntity, startFrame, frameRate, life, width, noise, red, green, blue, alpha, speed)
{
	
	message_begin( MSG_BROADCAST, SVC_TEMPENTITY )
	write_byte( TE_BEAMENTS )
	write_short( startEntity )              // start entity
	write_short( endEntity )                // end entity
	write_short( giSpriteLighting )                  // model
	write_byte( startFrame )                // starting frame
	write_byte( frameRate )                 // frame rate
	write_byte( life )                              // life
	write_byte( width )                             // line width
	write_byte( noise )                             // noise amplitude
	write_byte( red )                               // red
	write_byte( green )                             // green
	write_byte( blue )                              // blue
	write_byte( alpha )                             // brightness
	write_byte( speed )                             // scroll speed
	message_end()
}
stock msg_implosion(id, Origin[3],  radius, numbers, time_) { // efekt 
	message_begin(MSG_BROADCAST ,SVC_TEMPENTITY, Origin, id) //message begin
	write_byte(TE_IMPLOSION)
	write_coord(Origin[0]) // start position
	write_coord(Origin[1])
	write_coord(Origin[2])
	write_byte(radius) // radius
	write_byte(numbers) // count
	write_byte(time_*10) // life in 1's
	message_end()
	
}

/* =========================================== */
/*                   NATYWY 		       */
/* =========================================== */

public td_is_monster(ent)
{
	if(!is_valid_ent(ent))
		return 0
		
	new szClassname[24];
	entity_get_string(ent, EV_SZ_classname, szClassname, 23);
	if(equal(szClassname, "monster"))
		return 1;
	return 0
}
public td_is_healthbar(ent) {
	if(!is_valid_ent(ent))
		return 0;
	
	new szClassname[24];
	entity_get_string(ent, EV_SZ_classname, szClassname, 23);
	if(equal(szClassname, "monster_healtbar"))
		return 1;
	return 0
}
public is_special_monster(ent)
{
	if(!is_valid_ent(ent))
		return 0
	
	if(pev(ent, pev_monster_type) == _:ROUND_BOSS || pev(ent, pev_monster_type) == _:ROUND_BONUS)
		return 1
	
	return 0;
}
public is_special_wave(iWave) {
	if(MAX_WAVE > iWave > 0) {
		
		if(gWaveInfo[iWave][WAVE_ROUND_TYPE] == ROUND_BOSS){
			return 1;
		}
		else if(gWaveInfo[iWave][WAVE_ROUND_TYPE] == ROUND_BONUS) {
			return 2;
		}
	}
	
	return 0;
}


public eGame:_td_get_game_status()
	return gGame?GAME_AVAILABLE:GAME_NOT_AVAILABLE

public _td_set_game_status(eGame:iStatus)
{
	if(iStatus == GAME_NOT_AVAILABLE)
		gGame = false
	else if(iStatus == GAME_AVAILABLE)
		gGame = true
	CheckGamePossibility()
}


public _td_get_wave()
	return giWave
public _td_set_wave(wave)
	giWave = wave
public _td_get_wavenum()
	return giWaveNum
	

public _td_get_wave_info(iWave, e_WaveInfo:iInfo)
{
	if(iWave > giWaveNum || iWave <= 0)
		return 0
	if(iInfo == WAVE_MONSTER_NUM)
		return is_special_wave(iWave)?gWaveInfo[iWave][WAVE_MONSTER_NUM]+1:gWaveInfo[iWave][WAVE_MONSTER_NUM]

	return gWaveInfo[iWave][iInfo]
}
public _td_set_wave_info(iWave, e_WaveInfo:iInfo, _:iValue)
{
	if(iWave > giWaveNum || iWave <= 0)
		return;
	
	gWaveInfo[iWave][iInfo] = iValue;
	
}

public _td_get_user_info(id, e_Player:iInfo) {
	if(is_user_connected(id)) 
		return gPlayerInfo[id][iInfo]
	return 0
}

public _td_set_user_info(id, e_Player:iInfo, iValue) {
	if(is_user_connected(id)) 
	{
		gPlayerInfo[id][iInfo] = iValue
		if(iInfo == PLAYER_FRAGS)
			CheckPlayerLevel(id)
	}
}

public _td_get_max_wave()
	return MAX_WAVE

public _td_get_max_level()
	return MAX_LEVEL-1

public _td_get_max_monsters()
	return MAX_MONSTERS

public _td_get_monster_type(iEnt) {
	if(is_valid_ent(iEnt))
		return e_RoundType:pev(iEnt, pev_monster_type)
	return ROUND_NONE
}

public _td_get_monster_health(iEnt) {
	if(is_valid_ent(iEnt))
		return pev(iEnt, pev_health)
	return 0
}

public _td_get_monster_healthbar(iEnt) {
	if(is_valid_ent(iEnt) && is_valid_ent(pev(iEnt, pev_monster_healthbar)))
		return pev(iEnt, pev_monster_healthbar)
	return 0
}

public _td_get_start_origin(Float:out[3]) {
	set_array_f(1, gfStartOrigin, 3)
}

public _td_get_end_origin(Float:out[3]) {
	set_array_f(1, gfEndOrigin, 3)
}

public _td_remove_monsters() {
	RemoveMonsters()
}

public _td_remove_tower() {
	if(gModelTurret)
		RemoveTower() 
	else
		return 0;
	return 1;
}
public _td_get_round_name(e_RoundType:iRoundType, szOutpout[], len)
{
	param_convert(2)
	copy(szOutpout, len, gszRoundName[iRoundType])
}

public _td_get_max_map_turrets()
	return MAX_MAP_TURRETS
