openclonk/planet/Objects.ocd/Environment.ocd/Stalactite.ocd/Script.c

188 lines
4.4 KiB
C

/**
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);
}
AddTimer("DoWaterdrop", RandomX(36 * 10, 36 * 40));
}
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;
}
}
private func DoWaterdrop()
{
if (Random(9)) return;
Sound("Liquids::Waterdrop*");
}
local Name = "$Name$";
local Description = "$Description$";