forked from Mirrors/openclonk
181 lines
4.5 KiB
C
181 lines
4.5 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);
|
|
}
|
|
}
|
|
|
|
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.
|
|
if (!settings)
|
|
settings = {};
|
|
var loc_area = nil;
|
|
if (rectangle)
|
|
loc_area = Loc_InRect(rectangle);
|
|
var loc_background;
|
|
if (settings.underground == nil)
|
|
loc_background = Loc_Or(Loc_Sky(), Loc_Tunnel());
|
|
else if (settings.underground)
|
|
loc_background = Loc_Tunnel();
|
|
else
|
|
loc_background = Loc_Sky();
|
|
|
|
var stalactites = [];
|
|
for (var i = 0; i < amount; i++)
|
|
{
|
|
var loc = FindLocation(loc_background, 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 / 120, 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)
|
|
{
|
|
stalactite->SetR(180);
|
|
stalactite.MeshTransformation = Trans_Mul(Trans_Translate(0, 10 * stalactite->GetDefHeight() * stalactite->GetCon(), 0), stalactite.MeshTransformation);
|
|
}
|
|
else if (mat != "Ice")
|
|
{
|
|
// Add rain drop effect for stalactites only.
|
|
stalactite->AddRainDropEffect(nil, RandomX(80, 120), "Water", RandomX(1, 5), 0, 4);
|
|
}
|
|
|
|
return stalactite;
|
|
}
|
|
|
|
public func OnRainDropCreated(effect fx_drop)
|
|
{
|
|
if (Random(9))
|
|
return;
|
|
Sound("Liquids::Waterdrop*");
|
|
}
|
|
|
|
local Name = "$Name$";
|
|
local Description = "$Description$";
|