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

224 lines
5.1 KiB
C

/**
Volcano
Destructive eruptions of lava originating from the centre of the earth.
@author Maikel
*/
/*-- Disaster Control --*/
public func SetChance(num chance)
{
if (this != Volcano)
return;
var effect = GetEffect("IntVolcanoControl");
if (!effect)
effect = AddEffect("IntVolcanoControl", nil, 100, 20, nil, Volcano);
effect.chance = chance;
return;
}
public func GetChance()
{
if (this != Volcano)
return;
var effect = GetEffect("IntVolcanoControl");
if (effect)
return effect.chance;
return;
}
public func SetMaterial(string material)
{
if (this != Volcano)
return;
var effect = GetEffect("IntVolcanoControl");
if (effect)
effect.material = material;
return;
}
protected func FxIntVolcanoControlStart(object target, proplist effect, int temp)
{
// Default to lava as material.
if (!temp)
effect.material = "Lava";
return FX_OK;
}
protected func FxIntVolcanoControlTimer(object target, proplist effect, int time)
{
if (Random(100) < effect.chance && !Random(10))
LaunchVolcano(Random(LandscapeWidth()), LandscapeHeight(), Random(40) + 35, effect.material, RandomX(-10, 10));
return FX_OK;
}
global func LaunchVolcano(int x, int y, int strength, string material, float angle)
{
var volcano = CreateObject(Volcano);
return volcano->Launch(x, y, strength, material, angle);
}
/*-- Volcano --*/
local str; // Volcano strength, max 100.
local mat; // Volcano material, string.
local angle; // Direction of the volcano.
local oldx, oldy; // Old coordinates.
// returns true on a succesful volcano launch, false otherwise.
public func Launch(int x, int y, int strength, string material, float angle)
{
// Initial coordinates of the volcano.
SetPosition(x, y);
// Strength of the volcano.
str = BoundBy(strength, 1, 100);
// Volcano material.
mat = Material(material);
// Direction of the volcano.
angle = angle;
// Safety check.
if (!InGround())
{
RemoveObject();
return false;
}
// Launch volcano.
SetAction("Advance");
return true;
}
// Advance action call: Used for underground advancing.
private func Advance()
{
// Branch volcano.
if (!Random((120 - str) / 12))
Branch();
// Store old coordinates.
oldx = GetX();
oldy = GetY();
// Advance volcano.
angle += RandomX(-12, 12); // Slight angle distortion.
var adv = 12 + Random(6) + Random(str / 16);
var advx, advy;
var above_ground = false;
for (var x = 1; x <= adv; x++)
{
advx = Sin(angle, x);
advy = -Cos(angle, x);
SetPosition(oldx + advx, oldy + advy);
if (!InGround())
{
above_ground = true;
break;
}
}
// Draw volcano.
var strx = Abs(Cos(angle, str));
var stry = Abs(Sin(angle, str));
DrawMaterialQuad(MaterialName(mat),
GetX() - strx / 4, GetY() - stry / 4,
GetX() + strx / 4, GetY() + stry / 4,
oldx + strx / 4, oldy + stry / 4,
oldx - strx / 4, oldy - stry / 4, true);
// Drag Objects along.
for (var pObj in FindObjects(Find_OCF(OCF_Collectible), Find_InRect()))
{
pObj->SetXDir(advx);
pObj->SetYDir(advy);
}
// Shake free possible top layer.
if (above_ground)
ShakeFree(GetX(), GetY(), str / 4);
// Reduce strength
str -= Random(2);
if (str <= 0)
return RemoveObject();
// Above ground -> start Erupting.
if (above_ground)
SetAction("Erupt");
// Finished.
return;
}
// Erupt action call: Used for surface eruptions.
private func Erupt()
{
// Build up banks at the sides.
//CastPXS("Coal", str/4, str/4);
//CastPXS("Coal", str/4, str/4);
// Cast volcano material.
CastPXS(MaterialName(mat), 2 * str, 3 * str);
// Cast other particles (lava chunks, ashes, ashclouds).
if (!Random(6))
if (WildcardMatch(MaterialName(mat), "*Lava*"))
CastObjects(LavaChunk, 1, 60, 0, 0, 0, 40);
// Reduce strength.
if(!Random(3))
str--;
if (str <= 0)
return RemoveObject();
// If in ground -> start advancing.
if (InGround())
SetAction("Advance");
return;
}
// The volcano mainline branches into mainline + sideline.
private func Branch()
{
// Branch volcano.
var side = 2 * Random(2) - 1; // At which side the volcano branches.
var new_str = Max(Random(str / 2), 4); // Strength of the branch.
var x = side * Cos(angle, str / 4 - new_str / 4);
var y = side * Sin(angle, str / 4 - new_str / 4);
var new_mat = MaterialName(mat);
var new_angle = angle + side * RandomX(5, 15);
var volcano = CreateObject(Volcano, x, y, NO_OWNER);
volcano->Launch(GetX() + x, GetY() + y, new_str, new_mat, new_angle);
// Reset volcano.
str -= new_str;
x = side * Cos(new_angle, new_str / 4);
y = side * Sin(new_angle, new_str / 4);
SetPosition(GetX() + x, GetY() + y);
return;
}
// returns whether the volcano is in ground.
private func InGround()
{
if (GBackSolid(0, -2))
return true;
if (GetMaterial(0, -2) == mat)
return true;
return false;
}
/*-- Proplist --*/
local Name = "$Name$";
local ActMap = {
Advance = {
Prototype = Action,
Name = "Advance",
Procedure = DFA_NONE,
Delay = 2,
NextAction = "Advance",
StartCall = "Advance",
// Sound = "VolcanoAdvance",
},
Erupt = {
Prototype = Action,
Name = "Erupt",
Procedure = DFA_NONE,
Delay = 2,
NextAction = "Erupt",
StartCall = "Erupt",
// Sound = "VolcanoErupt",
},
};