
//
public SpawnChippy()
{
	// reference trigger box @ 0 degrees rot
	new Float:Chippy_MinBounds1[3] = {88.0, 18.0, 74.0};
	new Float:Chippy_MaxBounds1[3] = {56.0, -18.0, 78.0};
	
	// calc rotated trigger
	new Float:Chippy_MinBounds2[3];
	new Float:Chippy_MaxBounds2[3];
	
	Chippy_MinBounds2[0] = Cosine(DegToRad(g_ChippyAngles[1])) * Chippy_MinBounds1[0] - Sine(DegToRad(g_ChippyAngles[1])) * Chippy_MinBounds1[1];
	Chippy_MinBounds2[1] = Sine(DegToRad(g_ChippyAngles[1])) * Chippy_MinBounds1[0] + Cosine(DegToRad(g_ChippyAngles[1])) * Chippy_MinBounds1[1];
	Chippy_MinBounds2[2] = Chippy_MinBounds1[2];
	
	Chippy_MaxBounds2[0] = Cosine(DegToRad(g_ChippyAngles[1])) * Chippy_MaxBounds1[0] - Sine(DegToRad(g_ChippyAngles[1])) * Chippy_MaxBounds1[1];
	Chippy_MaxBounds2[1] = Sine(DegToRad(g_ChippyAngles[1])) * Chippy_MaxBounds1[0] + Cosine(DegToRad(g_ChippyAngles[1])) * Chippy_MaxBounds1[1];
	Chippy_MaxBounds2[2] = Chippy_MaxBounds1[2];
	
	// inside out triggers suck
	if (Chippy_MinBounds2[0] < Chippy_MaxBounds2[0])
	{
		g_ChippyTriggerMin[0] = Chippy_MinBounds2[0];
		g_ChippyTriggerMax[0] = Chippy_MaxBounds2[0];
	}
	else
	{
		g_ChippyTriggerMin[0] = Chippy_MaxBounds2[0];
		g_ChippyTriggerMax[0] = Chippy_MinBounds2[0];
	}
	
	if (Chippy_MinBounds2[1] < Chippy_MaxBounds2[1])
	{
		g_ChippyTriggerMin[1] = Chippy_MinBounds2[1];
		g_ChippyTriggerMax[1] = Chippy_MaxBounds2[1];
	}
	else
	{
		g_ChippyTriggerMin[1] = Chippy_MaxBounds2[1];
		g_ChippyTriggerMax[1] = Chippy_MinBounds2[1];
	}
	
	if (Chippy_MinBounds2[2] < Chippy_MaxBounds2[2])
	{
		g_ChippyTriggerMin[2] = Chippy_MinBounds2[2];
		g_ChippyTriggerMax[2] = Chippy_MaxBounds2[2];
	}
	else
	{
		g_ChippyTriggerMin[2] = Chippy_MaxBounds2[2];
		g_ChippyTriggerMax[2] = Chippy_MinBounds2[2];
	}
	
	g_ChippyTrigPos[0] = g_ChippyOrigin[0] + (g_ChippyTriggerMin[0] + g_ChippyTriggerMax[0])/2;
	g_ChippyTrigPos[1] = g_ChippyOrigin[1] + (g_ChippyTriggerMin[1] + g_ChippyTriggerMax[1])/2;
	g_ChippyTrigPos[2] = g_ChippyOrigin[2] + (g_ChippyTriggerMin[2] + g_ChippyTriggerMax[2])/2;


	// chippy model
	g_ChippyEnt = CreateEntityByName("prop_physics_override");
	SetEntityModel(g_ChippyEnt,"models/decapination/dc_chippy.mdl");
	SetEntityMoveType(g_ChippyEnt, MOVETYPE_VPHYSICS); //TODO: MOVETYPE_NONE?
	SetEntProp(g_ChippyEnt, Prop_Data, "m_CollisionGroup", 0);//TODO: CHECKME
	SetEntProp(g_ChippyEnt, Prop_Data, "m_usSolidFlags", 256);
	
	DispatchKeyValue(g_ChippyEnt, "spawnflags", "8"); 
	DispatchSpawn(g_ChippyEnt);

	if(IsValidEntity(g_ChippyEnt))
	{
		TeleportEntity(g_ChippyEnt, g_ChippyOrigin, g_ChippyAngles, NULL_VECTOR);
		AttachExhaustParticle(g_ChippyEnt);
	}
	
	// chippy windows
	g_ChippyWindowsEnt = CreateEntityByName("prop_physics_override");
	SetEntityModel(g_ChippyWindowsEnt,"models/props/de_train/utility_truck_windows.mdl");
	SetEntityMoveType(g_ChippyWindowsEnt, MOVETYPE_VPHYSICS); //TODO: MOVETYPE_NONE?
	SetEntProp(g_ChippyWindowsEnt, Prop_Data, "m_CollisionGroup", 0);//TODO: CHECKME
	SetEntProp(g_ChippyWindowsEnt, Prop_Data, "m_usSolidFlags", 256);
	
	DispatchKeyValue(g_ChippyWindowsEnt, "spawnflags", "8"); 
	DispatchSpawn(g_ChippyWindowsEnt);

	if(IsValidEntity(g_ChippyWindowsEnt))
	{
		TeleportEntity(g_ChippyWindowsEnt, g_ChippyOrigin, g_ChippyAngles, NULL_VECTOR);
	}
	
	// chippy trigger
	g_ChippyTriggerEnt = CreateEntityByName("trigger_multiple");
	DispatchSpawn(g_ChippyTriggerEnt);
	ActivateEntity(g_ChippyTriggerEnt);
	TeleportEntity(g_ChippyTriggerEnt, g_ChippyOrigin, NULL_VECTOR, NULL_VECTOR);
	SetEntityModel(g_ChippyTriggerEnt, "models/decapination/dc_chippy.mdl");
	SetEntPropVector(g_ChippyTriggerEnt, Prop_Send, "m_vecMins", g_ChippyTriggerMin);
	SetEntPropVector(g_ChippyTriggerEnt, Prop_Send, "m_vecMaxs", g_ChippyTriggerMax);      
	SetEntProp(g_ChippyTriggerEnt, Prop_Send, "m_nSolidType", 2);
	new enteffects = GetEntProp(g_ChippyTriggerEnt, Prop_Send, "m_fEffects");
	enteffects = 1; // was |= 32 for ef_nodraw
	SetEntProp(g_ChippyTriggerEnt, Prop_Send, "m_fEffects", enteffects);
	DispatchKeyValue(g_ChippyTriggerEnt, "spawnflags", "320"); 
	
	// BUG: doesn't play for players who miss round start!
	EmitAmbientSound(g_ChippyIdleSound, g_ChippyOrigin, SOUND_FROM_WORLD, SNDLEVEL_NORMAL, SND_NOFLAGS, 0.7, SNDPITCH_NORMAL, 0.0);
	
	HookEntityOutput("trigger_multiple","OnStartTouch",OnStartTouch);
}

public OnStartTouch(const String:output[], caller, activator, Float:delay)
{
	if (caller == g_ChippyTriggerEnt)
	{
		new String:edictname[128];
		GetEdictClassname(activator, edictname, 128);

		if (activator == g_ChippyEnt)
			return;
		if (activator == g_ChippyWindowsEnt)
			return;
	
		if (strncmp("prop_", edictname, 5, false)==0)
		{
			new i,j; // i=victim, j=holder
			new String:thrower_name[64];
			new String:victim_name[64];
			
			for (j=1; j<=MaxClients; j++)
			{
				if (g_HeldEnt[j]==activator)
				{
					//if(IsPlayer(j) == false) PrintToServer("[SM][DC] OnStartTouch(held ent):FALSE");
					
					// is a held ent
					Command_UnGrab(j, 0);
					for (i=1; i<=MaxClients; i++)
					{
						if (g_HeadEnt[i]==activator)
						{
							if(IsPlayer(i) == false) PrintToServer("[SM][DC] OnStartTouch(held head ent):FALSE");
							// is a held head ent
							g_HeadEnt[i] = -1;
							CreateTimer(0.2, KillEntity, activator);	
							
							GetClientName(g_HeadLastHolder[i], thrower_name, sizeof(thrower_name));
							GetClientName(i, victim_name, sizeof(victim_name));
							
							if (IsPlayerAlive(i))
							{
								PrintToChatAll("%s slam dunked %s!", thrower_name, victim_name);
								//PrintToChat(g_HeadLastHolder[i], "You slam dunked %s!", victim_name);
								//PrintToChat(i, "%s slam dunked your head!", thrower_name);
								SetEntProp(g_HeadLastHolder[i], Prop_Data, "m_iFrags", GetClientFrags(g_HeadLastHolder[i]) + 1);
							}
							else
							{
								PrintToChatAll("%s slam dunked the dead brain of %s!", thrower_name, victim_name);
								//PrintToChat(g_HeadLastHolder[i], "You slam dunked the dead brain of %s!", victim_name);
								//PrintToChat(i, "%s slam dunked your dead head!", thrower_name);
							}
							
							DealDamage(i ,100, g_HeadLastHolder[i], DMG_GENERIC, "weapon_knife");
							
							HopperSpurt();
							CreateTimer(0.1, ChippyFleshSounds);
							CreateTimer(0.2, SpoutSpurt);
							return;
						}
					}
					// is a held prop
					ChippyRejectSounds();
					BounceEntity(activator);
					return;
				}
			}
			
			for (i=1; i<=MaxClients; i++)
			{
				if (g_HeadEnt[i]==activator)
				{
					//if(IsPlayer(i) == false) PrintToServer("[SM][DC] OnStartTouch(non-held head ent):FALSE");
					// is a non-held head ent
					g_HeadEnt[i] = -1;
					CreateTimer(0.2, KillEntity, activator);	
					
					if (g_HeadLastHolder[i] > 0)
					{
						// how far
						new Float:vecThrowPos[3];
						new Float:distance;
						new distance_points;
						
						vecThrowPos[0] = g_ThrowPosX[g_HeadLastHolder[i]];
						vecThrowPos[1] = g_ThrowPosY[g_HeadLastHolder[i]];
						vecThrowPos[2] = g_ThrowPosZ[g_HeadLastHolder[i]];
						
						distance = GetVectorDistance(g_ChippyTrigPos,vecThrowPos);
						
						
						GetClientName(g_HeadLastHolder[i], thrower_name, sizeof(thrower_name));
						GetClientName(i, victim_name, sizeof(victim_name));
						
						if (IsPlayerAlive(i))
						{
							distance_points = RoundFloat(distance)/100;
							PrintToChatAll("%s minced %s alive with a %d point throw!", thrower_name, victim_name, distance_points);
							//PrintToChat(g_HeadLastHolder[i], "You minced %s alive with a %d point throw!", victim_name, distance_points);
							//PrintToChat(i, "%s minced your head with a %d point throw!", thrower_name, distance_points);
						}
						else
						{
							distance_points = RoundFloat(distance)/200;
							PrintToChatAll("%s minced the dead brain of %s with a %d point throw!", thrower_name, victim_name, distance_points);
							//PrintToChat(g_HeadLastHolder[i], "You minced the dead brain of %s for %d points!", victim_name, distance_points);
							//PrintToChat(i, "%s minced your dead head with a %d point throw!", thrower_name, distance_points);
						}
						
						if (distance_points > 0)
						{
							EmitSoundToAll(g_AchievementSound, g_HeadLastHolder[i]);
						}
						
						SetEntProp(g_HeadLastHolder[i], Prop_Data, "m_iFrags", GetClientFrags(g_HeadLastHolder[i]) + distance_points);
						DealDamage(i ,100, g_HeadLastHolder[i], DMG_GENERIC, "weapon_knife");
					}
					else
						DealDamage(i ,100, i, DMG_GENERIC, "weapon_knife");
						
					HopperSpurt();
					CreateTimer(0.1, ChippyFleshSounds);
					CreateTimer(0.2, SpoutSpurt);
					return;
				}
			}

			ChippyRejectSounds();
			BounceEntity(activator);
			return;
		}
		
		if (strncmp("player", edictname, 6, false)==0)
		{
			//if(IsPlayer(activator) == false) PrintToServer("[SM][DC] OnStartTouch(player):FALSE");
			ForcePlayerSuicide(activator);
			CreateTimer(0.2, RemoveRagdoll, activator);
			
			HopperSpurt();
			CreateTimer(0.1, ChippyFleshSounds);
			CreateTimer(0.2, SpoutSpurt);
			CreateTimer(0.4, ChippyFleshSounds);
			CreateTimer(0.8, SpoutSpurt);
			CreateTimer(1.5, SpoutSpurt, INVALID_HANDLE);
		}
	}
}

public Action:KillEntity(Handle:Timer, any:ent)
{
	if(IsValidEntity(ent))
		AcceptEntityInput(ent, "Kill");	
}

public BounceEntity(any:ent)
{
	new Float:Entity_Origin[3];
	new Float:vecVelocity[3];

	GetEntPropVector(ent, Prop_Send, "m_vecOrigin", Entity_Origin);

	vecVelocity[0] = GetRandomFloat(-130.0,130.0);
	vecVelocity[1] = GetRandomFloat(-130.0,130.0);
	vecVelocity[2] = GetRandomFloat(400.0,800.0);

	TeleportEntity(ent, Entity_Origin, NULL_VECTOR, vecVelocity);
}

public Action:ChippyFleshSounds(Handle:timer)
{
	new Roll;
	
	EmitSoundToAll(g_ChippyFleshySound, g_ChippyEnt);
	
	Roll = GetRandomInt(1, 3);
	if(Roll == 1) EmitSoundToAll(g_ChippyGrind1Sound, g_ChippyEnt, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, SNDVOL_NORMAL, SNDPITCH_LOW);
	if(Roll == 2) EmitSoundToAll(g_ChippyGrind2Sound, g_ChippyEnt, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, SNDVOL_NORMAL, SNDPITCH_LOW);
	if(Roll == 3) EmitSoundToAll(g_ChippyGrind3Sound, g_ChippyEnt, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, SNDVOL_NORMAL, SNDPITCH_LOW);
}

public ChippyRejectSounds()
{
	new Roll;
	
	Roll = GetRandomInt(2, 5);
	if(Roll == 2) EmitSoundToAll(g_ChippyReject2Sound, g_ChippyEnt);
	if(Roll == 3) EmitSoundToAll(g_ChippyReject3Sound, g_ChippyEnt);
	if(Roll == 4) EmitSoundToAll(g_ChippyReject4Sound, g_ChippyEnt);
	if(Roll == 5) EmitSoundToAll(g_ChippyReject5Sound, g_ChippyEnt);
}

public AttachExhaustParticle(any:entity)
{
	new particle = CreateEntityByName("info_particle_system");
	
	new String:tName[128];
	
	if (IsValidEdict(particle))
	{
		decl Float:position[3];
		
		GetEntPropVector(entity, Prop_Send, "m_vecOrigin", position);

		TeleportEntity(particle, position, NULL_VECTOR, NULL_VECTOR);
		
		Format(tName, sizeof(tName), "Entity%d", entity);
		DispatchKeyValue(entity, "targetname", tName);
		GetEntPropString(entity, Prop_Data, "m_iName", tName, sizeof(tName));
		
		DispatchKeyValue(particle, "targetname", "CSSparticle");
		DispatchKeyValue(particle, "parentname", tName);
		DispatchKeyValue(particle, "effect_name", "smoke_gib_01");
		
		DispatchSpawn(particle);

		SetVariantString(tName);
		AcceptEntityInput(particle, "SetParent", particle, particle, 0);
		
		SetVariantString("exhaust");
		AcceptEntityInput(particle, "SetParentAttachment", particle, particle, 0);
		
		ActivateEntity(particle);
		AcceptEntityInput(particle, "start");
	}
}
