openclonk/planet/Objects.ocd/Environment.ocd/Stalactite.ocd/Script.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$";