/**
	Stalactite
	Hangs from the ceiling

	@author Armin, Win, Zapper
*/

public func Construction()
{
	this.MeshTransformation = Trans_Rotate(Random(360), 0, 1, 0);
	
	var sibling = nil;
	for (var bone in ["bone1", "bone2", "bone3"])
	{
		var transformation;
		var rand = Random(2);
		if (rand == 0) 
			transformation = Trans_Rotate(RandomX(-20, 20), 1, 0, 0);
		else if(rand == 1)
			transformation = Trans_Rotate(RandomX(-20, 20), 0, 0, 1);
		sibling = TransformBone(bone, transformation, 1, Anim_Const(1000), sibling);
	}
	
	AddRainDropEffect(nil, RandomX(80, 120), "Water", RandomX(1, 5));
}

private func Hit()
{
	var colour = GetClrModulation();
	var particles = 
	{
		Size = PV_KeyFrames(0, 0, 0, 100, PV_Random(3, 5), 1000, 3),
		R = (colour >> 16) & 0xff,
		G = (colour >>  8) & 0xff,
		B = (colour >>  0) & 0xff,
		Alpha = PV_Linear(255, 0),
		ForceY = PV_Gravity(100),
		CollisionVertex = 0
	};
	
	var width = GetCon() * 7 / 100;
	var height = GetCon() * 60 / 100;
	if (GetR() != 0) height *= -1;
	
	CreateParticle("SmokeDirty", PV_Random(-width, width), PV_Random(0, height), PV_Random(-5, 5), PV_Random(-5, 15), PV_Random(10, 60), particles, 200);
	Sound("Hits::Materials::Rock::Rockfall*");

	for (var i = 0; i < 4; i++)
	{
		var fragment = CreateObject(Rock, 0, height / 2, NO_OWNER);
		fragment.Collectible = false;
		fragment->SetController(GetController());
		fragment->SetCon(50);
		fragment->SetSpeed(RandomX(-15, 15), RandomX(-25, 10));
		fragment->SetRDir(RandomX(-10, 10));
		fragment->FadeOut(390, true);
		fragment->SetClrModulation(this->GetClrModulation());
	}
	RemoveObject();
	return true;
}

public func Place(int amount, proplist rectangle, proplist settings)
{
	// Only allow definition call.
	if (GetType(this) != C4V_Def)
	{
		FatalError("Stalactite::Place must be called as a definition call!");
		return;
	}
	// Default parameters.
	var loc_area = nil;
	if (rectangle)
		loc_area = Loc_InRect(rectangle);

	var stalactites = [];
	for (var i = 0; i < amount; i++)
	{
		var loc = FindLocation(Loc_Tunnel(), Loc_Not(Loc_Liquid()), Loc_Wall(CNAT_Top), Loc_Space(40, CNAT_Bottom), loc_area);
		if (!loc)
			continue;
		var mat = MaterialName(GetMaterial(loc.x, loc.y - 1));
		var stalactite = CreateStalactite(loc.x, loc.y - 2, mat);
		
		// Find the ground below and scale down in narrow tunnels.
		var ground_y = nil;
		for (var y = 10; y < 200; y += 10)
		{
			if (!GBackSolid(loc.x, loc.y + y)) continue;
			
			// Search up and find actual surface.
			var up = 0;
			for (; up > -10; up -= 2)
				if (!GBackSolid(loc.x, loc.y + y + up)) break;
			
			ground_y = loc.y + y + up;
			break;
		}
		
		var con = 100;
		// Adjust size if there already is a stalactite very close.
		if (ObjectCount(Find_AtPoint(loc.x, loc.y), Find_ID(this)) > 1)
			con = RandomX(20, 50);
			
		var height;
		if (ground_y)
		{
			height = ground_y - loc.y;
			con = Min(con, BoundBy(100 * height / 60 / 2, 25, 100));
			
		}
		
		stalactite->SetCon(con, nil, true);
		
		// Create a stalagmite below?
		if (ground_y && height > 70 && Random(3))
		{
			// And place!
			if (MaterialName(GetMaterial(loc.x, ground_y + 2)) == mat)
			{
				var stalagmite = CreateStalactite(loc.x, ground_y + 2, mat, true);
				stalagmite->SetCon(con);
			}
		}
	}
	return stalactites;
}

private func CreateStalactite(int x, int y, string mat, bool stalagmite)
{
	var stalactite = CreateObject(this, x, y);

	// Ice stalactites are transparent and never use water sources.
	if (mat == "Ice")
	{
		stalactite->SetClrModulation(RGBa(157, 202, 243, 160));
	}
	else
	{
		// Keep colour tone of the material, but increase lightness.
		var colour = GetAverageTextureColor(mat);
		if (colour != nil)
		{
			colour = RGB2HSL(colour);
			var hue = (colour >> 16) & 0xff;
			colour = HSL(hue, 100, 200);
			stalactite->SetClrModulation(colour);
		}
		if (!stalagmite && Random(2))
			stalactite->DrawWaterSource();
	}

	if (stalagmite)
	{
		stalactite->SetR(180);
	}
	
	return stalactite;
}

private func DrawWaterSource()
{
	var xold = GetX();
	var yold = GetY() - 2;
	var xnew = xold;
	var ynew = xnew;
	for (var i = 0; i < RandomX(30, 140); i++)
	{
		ynew--;
		xnew = xold + RandomX(-1, 1);
		if (GBackSemiSolid(xnew-GetX(), ynew-GetY()))
			DrawMaterialQuad("Water", xold,yold, xold+1,yold, xold+1,yold+1, xold,yold+1);	
		else
			return;
		xold = xnew;
		yold = ynew;
	}
}

public func OnRainDropCreated()
{
	if (Random(9)) return;
	Sound("Liquids::Waterdrop*");
}

local Name = "$Name$";
local Description = "$Description$";
