new const NINTENDOMOD_BOWSER_PLUGIN[] = "Nintendo Mod - Bowser"
new const NINTENDOMOD_BOWSER_VERSION[] = "1.1"
new const NINTENDOMOD_BOWSER_AUTHOR[] = "Soloist"

/*
	Passive: Speed
		* Starts off Slow but speed increases to normal speed.
	Skill 1: Impale
		* Each hit has a chance of shaking the enemy's screen.
	Skill 2: Big Body
		* Gets more armor as skill level increases.
	Skill 3: Spiked Back
		* Has spikes on his back so if enemy touches a player with bowser the enemy is damage.
	PowerUp: Fireball
		* Blow flame damaging the enemy within distance that the player is looking at.

	Future Plans
		Add CVARS for values

	Written By Soloist
	Version 1.1
	Last Updated On 08/26/06

	*************************************************************************************

	Changelog
		Version 1.1
			* Fixed speed bug
		Version 1.0
			* Release of the plugin
*/

#include <amxmodx>
#include <fakemeta>
#include <nintendomod>

new charName[] = "Bowser";
new passiveName[] = "Speed";
new skill1Name[] = "Impale";
new skill2Name[] = "Big Body";
new skill3Name[] = "Spiked Back";
new powerupName[] = "Fireball";
new initName[] = "Bowser_Init";
new keyDownName[] = "Bowser_Fireball";

new passiveHelp[] = "Starts off Slow but speed increases to normal speed.";
new skill1Help[] = "Each hit has a chance of shaking the enemy^'s screen.";
new skill2Help[] = "Gets more armor as skill level increases.";
new skill3Help[] = "Has spikes on his back so if enemy touches a player with bowser the enemy is damage.";
new powerupHelp[] = "Blow flame damaging the enemy within distance that the player is looking at.";

new const Float:BOWSER_SPEEDNUM[11] = {190.0, 192.0, 194.0, 196.0, 198.0, 200.0, 202.0, 204.0, 206.0, 210.0, 215.0};
new const Float:BOWSER_IMPALEPROB[3] = {0.15, 0.25, 0.35};
new const Float:BOWSER_BIGBODYNUM[3] = {150.0, 175.0, 200.0};
new const Float:BOWSER_SPIKEDPROB[3] = {0.01, 0.05, 0.1};
new const BOWSER_SPIKEDDMG[3] = {50, 75, 99};

new PlayerLevel[33];
new PlayerSkill1[33];
new PlayerSkill2[33];
new PlayerSkill3[33];
new PlayerPowerUp[33];

new bool:BetweenRounds;

new fireball, sprBoom, sprSmoke, sprShock, sprFire;

public plugin_init()
{
	if(is_plugin_loaded("Nintendo Mod") == -1)
	{
		server_print("**********************************");
		server_print("*** Nintendo Mod is not loaded ***");
		server_print("**********************************");
		pause("ae");
		return;
	}
	
	register_plugin(NINTENDOMOD_BOWSER_PLUGIN, NINTENDOMOD_BOWSER_VERSION, NINTENDOMOD_BOWSER_AUTHOR);
	register_cvar("NintendoMod_Bowser_Version", NINTENDOMOD_BOWSER_VERSION, FCVAR_SERVER|FCVAR_SPONLY);
	set_cvar_string("NintendoMod_Bowser_Version", NINTENDOMOD_BOWSER_VERSION);

	register_event("ResetHUD", "ResetHUD", "b");
	register_logevent("RoundStart", 2, "1=Round_Start");
	register_logevent("RoundEnd", 2, "1=Round_End");

	register_event("CurWeapon", "Bowser_Speed", "be");
	register_event("Damage", "Bowser_Impale", "b", "2!0");
	register_forward(FM_Touch, "Bowser_SpikedBack");

	Nintendo_RegisterChar(charName, passiveName, skill1Name, skill2Name, skill3Name, powerupName, initName);
	Nintendo_RegisterHelp(charName, passiveHelp, skill1Help, skill2Help, skill3Help, powerupHelp);
	Nintendo_RegisterKeyDown(charName, keyDownName);

	register_srvcmd(initName, initName);
	register_srvcmd(keyDownName, keyDownName);
}

public plugin_precache()
{
	engfunc(EngFunc_PrecacheSound, "nintendomod/bowser_pierce.wav");
	engfunc(EngFunc_PrecacheSound, "nintendomod/bowser_laugh.wav");
	engfunc(EngFunc_PrecacheSound, "nintendomod/bowser_fireball.wav");
	fireball = engfunc(EngFunc_PrecacheModel, "sprites/xfireball3.spr");
	sprBoom  = engfunc(EngFunc_PrecacheModel, "sprites/zerogxplode.spr");
	sprSmoke = engfunc(EngFunc_PrecacheModel, "sprites/steam1.spr");
	sprShock = engfunc(EngFunc_PrecacheModel, "sprites/shockwave.spr");
	sprFire  = engfunc(EngFunc_PrecacheModel, "sprites/explode1.spr");
}

public client_connect(id)
{
	if(!Nintendo_Active() || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	InitPlayer(id);

	return PLUGIN_CONTINUE;
}

public client_disconnect(id)
{
	if(!Nintendo_Active() || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	InitPlayer(id);
	remove_task(id);

	return PLUGIN_CONTINUE;
}

public InitPlayer(id)
{
	if(!Nintendo_Active() || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	PlayerLevel[id] = 0;
	PlayerSkill1[id] = 0;
	PlayerSkill2[id] = 0;
	PlayerSkill3[id] = 0;
	PlayerPowerUp[id] = 0;

	return PLUGIN_CONTINUE;
}

public Bowser_Init()
{
	new temp[33];
	read_argv(1, temp, 32);
	new id = str_to_num(temp);

	if(!Nintendo_Active() || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	read_argv(2, temp, 32);
	new index  = str_to_num(temp);

	if(index == 0)
	{
		read_argv(3, temp, 32);
		new level = str_to_num(temp);
		read_argv(4, temp, 32);
		new skill1 = str_to_num(temp);
		read_argv(5, temp, 32);
		new skill2 = str_to_num(temp);
		read_argv(6, temp, 32);
		new skill3 = str_to_num(temp);
		read_argv(7, temp, 32);
		new powerup = str_to_num(temp);

		PlayerLevel[id] = level;
		PlayerSkill1[id] = skill1;
		PlayerSkill2[id] = skill2;
		PlayerSkill3[id] = skill3;
		PlayerPowerUp[id] = powerup;
	}
	else
	{
		read_argv(3, temp, 32);
		new value = str_to_num(temp);

		switch(index)
		{
			case 1: PlayerLevel[id] = value;
			case 2: PlayerSkill1[id] = value;
			case 3: PlayerSkill2[id] = value;
			case 4: PlayerSkill3[id] = value;
			case 5: PlayerPowerUp[id] = value;
		}
	}

	ResetHUD(id);

	return PLUGIN_CONTINUE;
}

public RoundStart()
{
	if(!Nintendo_Active())
		return PLUGIN_HANDLED;

	BetweenRounds = false;

	return PLUGIN_CONTINUE;
}

public RoundEnd()
{
	if(!Nintendo_Active())
		return PLUGIN_HANDLED;

	BetweenRounds = true;

	return PLUGIN_CONTINUE;
}

public ResetHUD(id)
{
	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName) || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	set_task(get_cvar_float("mp_freezetime"), "Bowser_Speed", id);
	Bowser_BigBody(id);

	return PLUGIN_CONTINUE;
}

public Bowser_Speed(id) // Passive
{
	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName) || !Nintendo_IsValidPlayer(id) || BetweenRounds)
		return PLUGIN_HANDLED;

	Nintendo_SetSpeed(id, BOWSER_SPEEDNUM[PlayerLevel[id]]);

	return PLUGIN_CONTINUE;
}

public Bowser_Impale(id) // Skill 1
{
	if(!Nintendo_Active() || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	new weapon, bodypart, attacker = get_user_attacker(id, weapon, bodypart);

	if(!Nintendo_HasChar(attacker, charName) || !Nintendo_IsValidPlayer(attacker))
		return PLUGIN_HANDLED;

	if(PlayerSkill1[attacker] > 0 && id != attacker)
	{
		if(Nintendo_TeamKill(id, attacker))
		{
			new Float:randomnumber = random_float(0.0,1.0);
			if(randomnumber <= BOWSER_IMPALEPROB[PlayerSkill1[attacker] - 1])
			{
				emit_sound(id, CHAN_AUTO, "nintendomod/bowser_laugh.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
				message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("ScreenShake"), _, id);
				write_short(3<<14);
				write_short(3<<15);
				write_short(3<<14);
				message_end();

				Nintendo_ExtraDamage(attacker, id, 5, "Impale", 0);
			}
		}
	}

	return PLUGIN_CONTINUE;
}

public Bowser_BigBody(id) // Skill 2
{
	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName) || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	if(PlayerSkill2[id] > 0)
		Nintendo_SetArmor(id, BOWSER_BIGBODYNUM[PlayerSkill2[id] - 1]);

	return PLUGIN_CONTINUE;
}

public Bowser_SpikedBack(victim, attacker) // Skill 3
{
	if(!Nintendo_Active() || !Nintendo_HasChar(attacker, charName) || !Nintendo_IsValidPlayer(victim) || !Nintendo_IsValidPlayer(attacker))
		return PLUGIN_HANDLED;

	if(PlayerSkill3[attacker] > 0)
	{
		if(Nintendo_TeamKill(victim, attacker))
		{
			new Float:randomnumber = random_float(0.0, 1.0);
			if(randomnumber <= BOWSER_SPIKEDPROB[PlayerSkill3[attacker] - 1])
			{
				Nintendo_ExtraDamage(attacker, victim, BOWSER_SPIKEDDMG[PlayerSkill3[attacker] - 1], "Spiked Back", 0);
				emit_sound(victim, CHAN_AUTO, "nintendomod/bowser_pierce.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
			}
		}
	}

	return PLUGIN_CONTINUE;
}
public Bowser_Fireball()
{
	new temp[6]
	read_argv(1, temp, 5)
	new id = str_to_num(temp)

	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName) || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	if(PlayerPowerUp[id] == 1)
	{
		new victim, body;
		get_user_aiming(id, victim, body);
		if(Nintendo_IsValidPlayer(victim))
		{
			Nintendo_PowerUpUsed(id, 1, 30);

			new idOrigin[3], vicOrigin[3], vecStep[3], parm[8];
			get_user_origin(id, idOrigin);
			get_user_origin(victim, vicOrigin);

			new distance = get_distance(vicOrigin, idOrigin);
			new steps = distance / 70;

			vecStep[0] = (vicOrigin[0] - idOrigin[0]) / steps;
			vecStep[1] = (vicOrigin[1] - idOrigin[1]) / steps;
			vecStep[2] = (vicOrigin[2] - idOrigin[2]) / steps;

			parm[0] = id;
			parm[1] = victim;
			parm[2] = idOrigin[0];
			parm[3] = idOrigin[1];
			parm[4] = idOrigin[2];
			parm[5] = vecStep[0];
			parm[6] = vecStep[1];
			parm[7] = vecStep[2];
			emit_sound(id, CHAN_AUTO, "nintendomod/bowser_fireball.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
			set_task(0.1, "Bowser_FireballFly", 0, parm, 7);
		}
		else
			Nintendo_PowerUpDeny(id, "Not a valid player.");
	}

	return PLUGIN_CONTINUE;
}

public Bowser_FireballFly(parm[])
{
	new id = parm[0];
	new victim = parm[1];

	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName))
		return PLUGIN_HANDLED;

	new vecStep[3], vicOrigin[3], fireBallOrigin[3], tempOrigin[3];

	fireBallOrigin[0] = parm[2];
	fireBallOrigin[1] = parm[3];
	fireBallOrigin[2] = parm[4];

	vecStep[0] = parm[5];
	vecStep[1] = parm[6];
	vecStep[2] = parm[7];

	new players[32], num, player;
	get_players(players, num);
	for(new i = 0; i <= num; i++)
	{
		player = players[i];
		if(Nintendo_IsValidPlayer(player) && player != id)
		{
			get_user_origin(player, tempOrigin);
			if(get_distance(tempOrigin, fireBallOrigin) < 200)
			{
				Bowser_FireballExplode(id, fireBallOrigin);
				return PLUGIN_CONTINUE;
			}
		}
	}

	if(BetweenRounds || !Nintendo_IsValidPlayer(id) || !Nintendo_IsValidPlayer(victim))
	{
		Bowser_FireballExplode(id, fireBallOrigin);
		return PLUGIN_CONTINUE;
	}

	fireBallOrigin[0] += vecStep[0];
	fireBallOrigin[1] += vecStep[1];
	fireBallOrigin[2] += vecStep[2];

	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, fireBallOrigin);
	write_byte(TE_SPRITE);
	write_coord(fireBallOrigin[0]);
	write_coord(fireBallOrigin[1]);
	write_coord(fireBallOrigin[2]);
	write_short(fireball);
	write_byte(10);
	write_byte(200);
	message_end();

	get_user_origin(victim, vicOrigin);

	new distance = get_distance(vicOrigin, fireBallOrigin);
	new steps = distance / 70;

	vecStep[0] = (vicOrigin[0] - fireBallOrigin[0]) / steps;
	vecStep[1] = (vicOrigin[1] - fireBallOrigin[1]) / steps;
	vecStep[2] = (vicOrigin[2] - fireBallOrigin[2]) / steps;

	parm[0] = id;
	parm[1] = victim;
	parm[2] = fireBallOrigin[0];
	parm[3] = fireBallOrigin[1];
	parm[4] = fireBallOrigin[2];
	parm[5] = vecStep[0];
	parm[6] = vecStep[1];
	parm[7] = vecStep[2];

	set_task(0.4, "Bowser_FireballFly", 0, parm, 8);

	return PLUGIN_CONTINUE;
}

public Bowser_FireballExplode(id, fireBallOrigin[3])
{
	new players[32], num, player, vicOrigin[3];
	get_players(players, num);
	for(new i = 0; i <= num; i++)
	{
		player = players[i];
		if(Nintendo_IsValidPlayer(player))
		{
			if(Nintendo_TeamKill(id, player))
			{
				get_user_origin(player, vicOrigin);

				if(get_distance(vicOrigin, fireBallOrigin) < 500.0)
					Nintendo_ExtraDamage(id, player, 100, "Fireball", 0);
			}
		}
	}

	// Start Explosion Effects..
	// Shockwave Effect
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, fireBallOrigin);
	write_byte(TE_BEAMCYLINDER);
	write_coord(fireBallOrigin[0]);
	write_coord(fireBallOrigin[1]);
	write_coord(fireBallOrigin[2] + 16);
	write_coord(fireBallOrigin[0]);
	write_coord(fireBallOrigin[1]);
	write_coord(fireBallOrigin[2] + 1936);
	write_short(sprShock);
	write_byte(0);
	write_byte(0);
	write_byte(2);
	write_byte(20);
	write_byte(0);
	write_byte(188);
	write_byte(220);
	write_byte(255);
	write_byte(255);
	write_byte(0);
	message_end();

	// Explosion Type 1 Effect
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, fireBallOrigin);
	write_byte(TE_EXPLOSION);
	write_coord(fireBallOrigin[0]);
	write_coord(fireBallOrigin[1]);
	write_coord(fireBallOrigin[2]);
	write_short(sprFire);
	write_byte(60);
	write_byte(10);
	write_byte(TE_EXPLFLAG_NONE);
	message_end();

	// Explosion Type 2 Effect
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, fireBallOrigin);
	write_byte(TE_EXPLOSION2);
	write_coord(fireBallOrigin[0]);
	write_coord(fireBallOrigin[1]);
	write_coord(fireBallOrigin[2]);
	write_byte(188);
	write_byte(10);
	message_end();

	// Outer Explosion Flame
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, fireBallOrigin);
	write_byte(TE_EXPLOSION);
	write_coord(fireBallOrigin[0]);
	write_coord(fireBallOrigin[1]);
	write_coord(fireBallOrigin[2]);
	write_short(sprBoom);
	write_byte(50);
	write_byte(15);
	write_byte(TE_EXPLFLAG_NONE);
	message_end();

	// Smoke Effect
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, fireBallOrigin);
	write_byte(TE_SMOKE);
	write_coord(fireBallOrigin[0]);
	write_coord(fireBallOrigin[1]);
	write_coord(fireBallOrigin[2]);
	write_short(sprSmoke);
	write_byte(60);
	write_byte(10);
	message_end();
}
