new const NINTENDOMOD_YOSHI_PLUGIN[] = "Nintendo Mod - Yoshi"
new const NINTENDOMOD_YOSHI_VERSION[] = "1.0"
new const NINTENDOMOD_YOSHI_AUTHOR[] = "Soloist"

/*
	Passive: Green Dino
		* Increased armor at the expense of looking green.
	Skill 1: Jump
		* Lower Gravity.
	Skill 2: Speed
		* Increased  Speed.
	Skill 3: Mole
		* Change of spawning in enemy spawn looking like your enemy.
	PowerUp: Egg Mine
		* Lays an egg that acts as a proximity mine.

	Future Plans
		Add CVARS for values

	Written By Soloist
	Version 1.0
	Last Updated On 08/26/06

	*************************************************************************************

	Changelog
		Version 1.0
			* Release of the plugin
*/

#include <amxmodx>
#include <fun>
#include <cstrike>
#include <fakemeta>
#include <nintendomod>

new const Float:YOSHI_ARMORNUM[11] = {100.0, 110.0, 120.0, 130.0, 140.0, 150.0, 160.0, 170.0, 180.0, 190.0, 200.0};
new const YOSHI_GREENNUM[11] = {255, 240, 230, 220, 210, 200, 190, 180, 170, 160, 150};
new const Float:YOSHI_JUMPGRAV[3] = {700.0, 500.0, 400.0};
new const Float:YOSHI_SPEEDNUM[3] = {300.0, 325.0, 350.0};
new const Float:YOSHI_MOLEPROB[3] = {0.01, 0.111, 0.155};

new charName[] = "Yoshi";
new passiveName[] = "Green Dino";
new skill1Name[] = "Jump";
new skill2Name[] = "Speed";
new skill3Name[] = "Mole";
new powerupName[] = "Egg Mine";
new initName[] = "Yoshi_Init";
new keyDownName[] = "Yoshi_Egg";

new passiveHelp[] = "Increased armor at the expense of looking green.";
new skill1Help[] = "Lower Gravity.";
new skill2Help[] = "Increased  Speed.";
new skill3Help[] = "Change of spawning in enemy spawn looking like your enemy.";
new powerupHelp[] = "Lays an egg that acts as a proximity mine.";

new PlayerLevel[33];
new PlayerSkill1[33];
new PlayerSkill2[33];
new PlayerSkill3[33];
new PlayerPowerUp[33];

new bool:BetweenRounds;

new bool:mole[32];
new CTSkins[5][] = {"sas", "gsg9", "urban", "gign", "spetsnaz"}
new TSkins[5][] = {"arctic", "leet", "guerilla", "terror", "militia"}
new spawnEntString[2][] = {"info_player_start", "info_player_deathmatch"}
new bool:spawnPointsused[33] = false

new bool:laidEggs[33], eggMine[33], mineOrigin[33][3], 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_YOSHI_PLUGIN, NINTENDOMOD_YOSHI_VERSION, NINTENDOMOD_YOSHI_AUTHOR);

	register_cvar("NintendoMod_Yoshi_Version", NINTENDOMOD_YOSHI_VERSION, FCVAR_SERVER|FCVAR_SPONLY);

	register_event("ResetHUD", "ResetHUD", "b");
	register_logevent("RoundStart", 2, "1=Round_Start")
	register_logevent("RoundEnd", 2, "1=Round_End")

	register_event("CurWeapon", "Yoshi_Speed", "be");

	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_PrecacheModel, "models/nintendomod/yoshi_egg.mdl");
	engfunc(EngFunc_PrecacheSound, "nintendomod/yoshi_eggping.wav");

	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 Yoshi_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;

	if(mole[id])
	{
		cs_reset_user_model(id);
		mole[id] = false;
	}

	set_task(0.1, "Yoshi_Mole", id+100);

	if(pev_valid(eggMine[id]))
		engfunc(EngFunc_RemoveEntity, eggMine[id]);

	remove_task(id);
	laidEggs[id] = false;

	Yoshi_Passive(id);
	Yoshi_Jump(id);
	set_task(get_cvar_float("mp_freezetime"), "Yoshi_Speed", id);

	return PLUGIN_CONTINUE;
}

public Yoshi_Passive(id) // Passive
{
	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName) || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	Nintendo_SetArmor(id, YOSHI_ARMORNUM[PlayerLevel[id]]);
	set_user_rendering(id, kRenderFxGlowShell, 0, YOSHI_GREENNUM[PlayerLevel[id]], 0, kRenderNormal, 25);

	return PLUGIN_CONTINUE;
}

public Yoshi_Jump(id) // Skill 1
{
	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName)  || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	if(PlayerSkill1[id] > 0)
		Nintendo_SetGravity(id, YOSHI_JUMPGRAV[PlayerSkill1[id] - 1]);

	return PLUGIN_CONTINUE;
}

public Yoshi_Speed(id) // Skill 2
{
	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName) || !Nintendo_IsValidPlayer(id) || BetweenRounds)
		return PLUGIN_HANDLED;

	if(PlayerSkill2[id] > 0)
		Nintendo_SetSpeed(id, YOSHI_SPEEDNUM[PlayerSkill2[id] - 1]);

	return PLUGIN_CONTINUE;
}

public Yoshi_Mole(id) // Skill 3
{
	id-=100;
	if(!Nintendo_Active() || !Nintendo_HasChar(id, charName) || !Nintendo_IsValidPlayer(id))
		return PLUGIN_HANDLED;

	if(PlayerSkill3[id] > 0)
	{
		new Float:randomnumber = random_float(0.0, 1.0);
		if(randomnumber <= YOSHI_MOLEPROB[PlayerSkill3[id] - 1])
		{
			new entSpawn;
			new Float:spawnAngle[3] ;
			new Float:spawnOrigin[3];
			if(get_user_team(id) == 2)
				 entSpawn = Yoshi_MoleFindSpawn(id, 1, spawnOrigin, spawnAngle);
			else
				 entSpawn = Yoshi_MoleFindSpawn(id, 2, spawnOrigin, spawnAngle);

			if (!entSpawn)
				return PLUGIN_CONTINUE;

			new origin[3];

			origin[0] = floatround(spawnOrigin[0]);
			origin[1] = floatround(spawnOrigin[1]);
			origin[2] = floatround(spawnOrigin[2]);

			new num = 0, newSkin[32]
			num = random_num(0,3)

			if(get_user_team(id) == 1)
				add(newSkin, 31, CTSkins[num]);
			else
				add(newSkin, 31, TSkins[num]);

			cs_set_user_model(id,newSkin);
			mole[id] = true;

			set_pev(id, pev_angles, spawnAngle);
			set_user_origin(id, origin);

			return PLUGIN_HANDLED;
		}

	}

	return PLUGIN_CONTINUE;
}

stock Yoshi_MoleFindSpawn(id, iTeamNumber, Float:spawnOrigin[], Float:spawnAngle[])
{
	new iSpawn
	if(iTeamNumber == 2)
		iSpawn=0
	else
		iSpawn=1

	const maxSpawns = 128
	new spawnPoints[maxSpawns]
	new ent = -1, spawnsFound = 0

	do
	{
		ent = engfunc(EngFunc_FindEntityByString, ent, "classname", spawnEntString[iSpawn]);

		if(ent != 0)
		{
			spawnPoints[spawnsFound] = ent
			spawnsFound++
		}
	} while(ent && spawnsFound < maxSpawns)

	new bool:foundFreeSpawn, playersInVicinity, entList[1], Float:vicinity = 96.0, i;

	for(i = 0; i < spawnsFound && !foundFreeSpawn; i++)
	{
		if(spawnPoints[i] != 0 && !spawnPointsused[i])
		{
			pev(spawnPoints[i], pev_origin, spawnOrigin);

			playersInVicinity = engfunc(EngFunc_FindEntityInSphere, 0, "player", vicinity, entList, 1, spawnOrigin);

			if(playersInVicinity == 0)
			{
				foundFreeSpawn = true;
				spawnPointsused[i] = true;
			}
			else
				foundFreeSpawn = false;
		}

		id--;
	}

	if(foundFreeSpawn && spawnPoints[i])
	{
		pev(spawnPoints[i], pev_angles, spawnAngle);
		return spawnPoints[i];
	}

	return -1;
}

public Yoshi_Egg(id)
{
	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)
	{
		if(laidEggs[id])
		{
			Nintendo_PowerUpDeny(id, "You already laid an egg");
			return PLUGIN_HANDLED;
		}

		Nintendo_PowerUpUsed(id, 1, 30);
		new idOrigin[3];
		get_user_origin(id, idOrigin);
		Yoshi_EggPlantMine(id, idOrigin)
	}

	return PLUGIN_CONTINUE;
}
public Yoshi_EggPlantMine(id, idOrigin[3])
{
	new Float:origin[3];
	origin[0] = float(idOrigin[0]);
	origin[1] = float(idOrigin[1]);
	origin[2] = float(idOrigin[2]);

	new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"));
	set_pev(ent, pev_classname, "egg_mine");

	engfunc(EngFunc_SetModel, ent, "models/nintendomod/yoshi_egg.mdl");
	engfunc(EngFunc_SetOrigin, ent, origin);
	set_pev(ent, pev_effects, 32);
	set_pev(ent, pev_solid, SOLID_BBOX);
	set_pev(ent, pev_movetype, MOVETYPE_TOSS);
	set_pev(ent, pev_health, 200.0);
	set_pev(ent, pev_takedamage, 2.0);
	set_pev(ent, pev_owner, id);

	eggMine[id] = ent;
	laidEggs[id] = true;

	pev(eggMine[id], pev_origin, origin);
	mineOrigin[id][0] = floatround(origin[0]);
	mineOrigin[id][1] = floatround(origin[1]);
	mineOrigin[id][2] = floatround(origin[2]);

	Nintendo_StatusHUD(id, "You have laid an egg");
	set_task(5.0, "Yoshi_EggTimer", id);

	return PLUGIN_HANDLED
}

public Yoshi_EggTimer(id)
{
	if(!pev_valid(eggMine[id]))
		return PLUGIN_HANDLED;
	new idOrigin[3];
	new players[32], num;
	get_players(players, num);
	for(new i = 0; i < num; i++)
	{
		new player = players[i];
		if(!Nintendo_IsValidPlayer(player))
			continue;

		get_user_origin(player, idOrigin);
		if(get_distance(idOrigin, mineOrigin[id]) <= 400 || BetweenRounds)
		{
			Yoshi_EggExplode(id);
			return PLUGIN_CONTINUE;
		}
	}

	emit_sound(eggMine[id], CHAN_AUTO, "nintendomod/yoshi_eggping.wav", 0.3, ATTN_NORM, 0, PITCH_NORM);
	set_task(1.0, "Yoshi_EggTimer", id);

	return PLUGIN_CONTINUE;
}

public Yoshi_EggExplode(id)
{
	if(!pev_valid(eggMine[id]))
		return PLUGIN_HANDLED;

	new idOrigin[3];
	laidEggs[id] = false;

	engfunc(EngFunc_RemoveEntity, eggMine[id]);
	eggMine[id] = 0;

	new players[32], num;
	get_players(players, num);
	for(new i = 0; i < num; i++)
	{
		new player = players[i];
		if(!Nintendo_IsValidPlayer(player))
			continue;

		if(Nintendo_TeamKill(id, player))
		{
			get_user_origin(player, idOrigin);
			if(get_distance(idOrigin, mineOrigin[id]) <= 400)
			{
				message_begin(MSG_ONE, get_user_msgid("ScreenShake"), {0,0,0}, player);
				write_short(1<<14);
				write_short(1<<13);
				write_short(1<<14);
				message_end();

				Nintendo_ExtraDamage(id, player, 100, "Egg Mine", 0);
			}
		}
	}

	// Start Explosion Effects..
	// Shockwave Effect
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, mineOrigin[id]);
	write_byte(TE_BEAMCYLINDER);
	write_coord(mineOrigin[id][0]);
	write_coord(mineOrigin[id][1]);
	write_coord(mineOrigin[id][2] + 16);
	write_coord(mineOrigin[id][0]);
	write_coord(mineOrigin[id][1]);
	write_coord(mineOrigin[id][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, mineOrigin[id]);
	write_byte(TE_EXPLOSION);
	write_coord(mineOrigin[id][0]);
	write_coord(mineOrigin[id][1]);
	write_coord(mineOrigin[id][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, mineOrigin[id]);
	write_byte(TE_EXPLOSION2);
	write_coord(mineOrigin[id][0]);
	write_coord(mineOrigin[id][1]);
	write_coord(mineOrigin[id][2]);
	write_byte(188);
	write_byte(10);
	message_end();

	// Outer Explosion Flame
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY, mineOrigin[id]);
	write_byte(TE_EXPLOSION);
	write_coord(mineOrigin[id][0]);
	write_coord(mineOrigin[id][1]);
	write_coord(mineOrigin[id][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, mineOrigin[id]);
	write_byte(TE_SMOKE);
	write_coord(mineOrigin[id][0]);
	write_coord(mineOrigin[id][1]);
	write_coord(mineOrigin[id][2]);
	write_short(sprSmoke);
	write_byte(60);
	write_byte(10);
	message_end();

	return PLUGIN_CONTINUE;
}
