2013-02-25 20:47:55 +00:00
|
|
|
/*
|
|
|
|
BigVolcano
|
|
|
|
Author: Sven2
|
|
|
|
|
|
|
|
DESC
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const BigVolcanoBehaviour_Fill = 0,
|
|
|
|
BigVolcanoBehaviour_Advance = 1,
|
|
|
|
BigVolcanoBehaviour_AdvanceLava = 2,
|
2015-01-01 16:38:30 +00:00
|
|
|
BigVolcanoBehaviour_Stop = 3,
|
2015-12-06 02:21:30 +00:00
|
|
|
BigVolcanoBehaviour_Underground = DMQ_Sub;
|
2013-02-25 20:47:55 +00:00
|
|
|
|
|
|
|
static const BigVolcano_XRes = 25; // step size of segments of lava_y array
|
|
|
|
|
|
|
|
local lava_y; // array for current vertical lava positions
|
|
|
|
local lava_y_endpoint; // volcano is done when lava reaches this point
|
|
|
|
local n_lava_y; // size of lava_y array
|
|
|
|
local n_branches;
|
|
|
|
local mat_behaviours; // array of BigVolcanoBehaviour_*, indexed by GetMaterial(x,y)+1: How to behave in materials
|
|
|
|
local mat_advancespeeds; // array of ints from 0 to 100, indexed by GetMaterial(x,y)+1: How to behave in materials
|
2013-09-21 17:54:42 +00:00
|
|
|
local speed_multiplier = 1; // number of pixels by which the volcano advances when it does advance
|
2013-02-25 20:47:55 +00:00
|
|
|
|
|
|
|
func Activate(int start_y, int end_y)
|
|
|
|
{
|
|
|
|
if (lava_y) return; // already active
|
|
|
|
if (!start_y) start_y = LandscapeHeight();
|
|
|
|
if (!end_y) end_y = 0;
|
|
|
|
lava_y_endpoint = end_y;
|
|
|
|
ScheduleCall(this, this.Execute, 10, 99999);
|
|
|
|
n_branches = 0;
|
|
|
|
mat_behaviours = CreateArray(20);
|
|
|
|
mat_advancespeeds = CreateArray(20);
|
|
|
|
mat_behaviours[0] = BigVolcanoBehaviour_Fill;
|
|
|
|
mat_advancespeeds[0] = 80;
|
|
|
|
for (var mat_idx=0, mat_name; mat_name=MaterialName(mat_idx); ++mat_idx)
|
|
|
|
{
|
|
|
|
var behaviour, density = GetMaterialVal("Density", "Material", mat_idx), speed;
|
|
|
|
if (WildcardMatch(mat_name, "*Lava")) // pass through lava
|
|
|
|
{
|
|
|
|
behaviour = BigVolcanoBehaviour_AdvanceLava;
|
|
|
|
speed = 100;
|
|
|
|
}
|
|
|
|
else if (WildcardMatch(mat_name, "*Water")) // fill into water to remove it
|
|
|
|
{
|
|
|
|
behaviour = BigVolcanoBehaviour_Fill;
|
|
|
|
speed = 10;
|
|
|
|
}
|
|
|
|
else if (density <= 0) // fill tunnels
|
|
|
|
{
|
|
|
|
behaviour = BigVolcanoBehaviour_Fill;
|
|
|
|
speed = 80;
|
|
|
|
}
|
|
|
|
else if (density <= 25) // pass through any other liquids
|
|
|
|
{
|
|
|
|
behaviour = BigVolcanoBehaviour_Advance;
|
|
|
|
speed = 60;
|
|
|
|
}
|
|
|
|
else if (GetMaterialVal("DigFree", "Material", mat_idx)) // pass through diggable materials
|
|
|
|
{
|
|
|
|
behaviour = BigVolcanoBehaviour_Advance;
|
|
|
|
speed = 50;
|
|
|
|
}
|
|
|
|
else // stop at rocks + minerals
|
|
|
|
{
|
|
|
|
behaviour = BigVolcanoBehaviour_Stop;
|
|
|
|
speed = 10;
|
|
|
|
}
|
|
|
|
mat_behaviours[mat_idx+1] = behaviour;
|
|
|
|
mat_advancespeeds[mat_idx+1] = speed;
|
|
|
|
}
|
|
|
|
n_lava_y = (LandscapeWidth()-1)/BigVolcano_XRes+2;
|
|
|
|
lava_y = CreateArray(n_lava_y);
|
|
|
|
for (var i=0; i<n_lava_y; ++i) lava_y[i] = start_y;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
func Execute()
|
|
|
|
{
|
|
|
|
//Log("tic");
|
|
|
|
// Create branch
|
|
|
|
var ls_w=LandscapeWidth();
|
|
|
|
if (n_branches<20 && !Random(1))
|
|
|
|
{
|
|
|
|
var x = Random(ls_w);
|
|
|
|
LaunchBranch(x, GetLavaY(x), Random(5)-2, -15-Random(5));
|
|
|
|
}
|
|
|
|
// Rise lava
|
|
|
|
if (true)
|
|
|
|
{
|
2014-09-19 19:35:21 +00:00
|
|
|
var lavamat = Material("DuroLava");
|
2013-02-25 20:47:55 +00:00
|
|
|
var any_nonlava, last_move, this_move;
|
|
|
|
for (var i=0; i<n_lava_y; ++i)
|
|
|
|
{
|
|
|
|
if (lava_y[i] > lava_y_endpoint)
|
|
|
|
{
|
|
|
|
any_nonlava = true;
|
|
|
|
var x = BoundBy(i*BigVolcano_XRes-BigVolcano_XRes/2, 0, ls_w-BigVolcano_XRes) + Random(BigVolcano_XRes);
|
|
|
|
var y = GetLavaY(x);
|
|
|
|
var speed = mat_advancespeeds[GetMaterial(x,y-5)+1];
|
|
|
|
if (i) if (lava_y[i] > lava_y[i-1]+BigVolcano_XRes*2) speed+=50;
|
|
|
|
if (i<n_lava_y-1) if (lava_y[i] > lava_y[i+1]+BigVolcano_XRes*2) speed+=50;
|
|
|
|
this_move = (Random(100) < speed);
|
|
|
|
if (this_move)
|
2013-09-21 17:54:42 +00:00
|
|
|
lava_y[i] -= speed_multiplier;
|
2013-02-25 20:47:55 +00:00
|
|
|
else if (!Random(3))
|
|
|
|
{
|
|
|
|
if (speed<=10)
|
|
|
|
{
|
|
|
|
// Blast away solid
|
2013-02-26 23:21:30 +00:00
|
|
|
var blast_size = 5+Random(5);
|
|
|
|
BlastFree(x,y-3,blast_size,GetController());
|
|
|
|
// gfx
|
2013-11-26 21:47:44 +00:00
|
|
|
var particle_speed = blast_size * 3;
|
2013-12-17 20:40:40 +00:00
|
|
|
CreateParticle("FireDense", PV_Random(x - 1, x + 1), PV_Random(y - 4, y - 2), PV_Random(-particle_speed, particle_speed), PV_Random(-particle_speed, particle_speed), PV_Random(30, 40), Particles_Fire(), 5);
|
2015-12-13 21:14:55 +00:00
|
|
|
if (!Random(5)) SoundAt("Hits::Materials::Rock::RockHit*", x,y-3, 100);
|
2013-02-25 20:47:55 +00:00
|
|
|
}
|
|
|
|
else if (speed <=50)
|
|
|
|
{
|
|
|
|
// Crumble away diggable
|
|
|
|
ShakeFree(x,y-Random(20),5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (last_move || (this_move && i))
|
|
|
|
{
|
2014-09-19 19:35:21 +00:00
|
|
|
var x1=(i-1)*BigVolcano_XRes, x2 = i*BigVolcano_XRes;
|
|
|
|
var y1=lava_y[i-1]+speed_multiplier+1, y2 = lava_y[i]+speed_multiplier+1;
|
|
|
|
var limit=50;
|
|
|
|
while (GetMaterial(x1,y1+1) != lavamat && --limit) ++y1;
|
|
|
|
limit=50;
|
|
|
|
while (GetMaterial(x1,y2+1) != lavamat && --limit) ++y2;
|
2015-01-01 16:38:30 +00:00
|
|
|
DrawMaterialQuad("DuroLava-lava_red", x1,lava_y[i-1], x2,lava_y[i], x2,y2, x1,y1, BigVolcanoBehaviour_Underground);
|
2013-02-25 20:47:55 +00:00
|
|
|
}
|
|
|
|
last_move = this_move;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
// Lava risen to the max?
|
|
|
|
if (!any_nonlava)
|
|
|
|
{
|
|
|
|
ClearScheduleCall(this, this.Execute);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetLavaY(int x)
|
|
|
|
{
|
|
|
|
var i = BoundBy(x/BigVolcano_XRes, 0, n_lava_y-2), ix = x%BigVolcano_XRes;
|
|
|
|
return (lava_y[i]*(BigVolcano_XRes-ix) + lava_y[i+1]*ix) / BigVolcano_XRes;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Branch effects */
|
|
|
|
// draws a lava branch that walks ahead of the rising main lava lake
|
|
|
|
// branch effect variables:
|
|
|
|
// x,y: Branch tip position
|
|
|
|
// tip_progress: Progress from trace_x/y[end] towards dir_x/dir_y. From 0 to 100.
|
|
|
|
// dir_x,dir_y: Advance direction per segment
|
|
|
|
// len: Length of branch
|
|
|
|
// trace_x,trace_y: Array of previous positions. Index from oldest to newest. Currenct tip x/y not included.
|
|
|
|
// trace_len: length of trace_x,trace_y arrays
|
|
|
|
|
|
|
|
local dbg_counter;
|
|
|
|
|
|
|
|
func LaunchBranch(int x, int y, int dir_x, int dir_y, int parent_level)
|
|
|
|
{
|
|
|
|
var fx = AddEffect("VolcanoBranch", this, 1, 3, this);
|
|
|
|
fx.x=x; fx.y=y; fx.dir_x=dir_x; fx.dir_y=dir_y;
|
|
|
|
fx.tip_progress=0;
|
|
|
|
fx.trace_x=[x]; fx.trace_y=[y]; fx.trace_len=fx.len=1;
|
|
|
|
fx.counter = ++dbg_counter;
|
|
|
|
fx.level = parent_level + 1;
|
|
|
|
//Log("LaunchBranch %d from %d/%d towards %d/%d", fx.counter,x,y,dir_x,dir_y);
|
|
|
|
++n_branches;
|
|
|
|
return fx;
|
|
|
|
}
|
|
|
|
|
|
|
|
func FxVolcanoBranchTimer(object q, fx, int time)
|
|
|
|
{
|
|
|
|
// Progress tip
|
|
|
|
var next_tip_progress = fx.tip_progress + 10;
|
|
|
|
var last_segment = fx.trace_len-1;
|
|
|
|
var sx=fx.trace_x[last_segment], sy=fx.trace_y[last_segment];
|
|
|
|
var nx=sx+next_tip_progress*(fx.dir_x)/100, ny=sy+next_tip_progress*(fx.dir_y)/100;
|
|
|
|
//Log("Go %d from %d/%d towards %d/%d", fx.counter,sx,sy,nx-sx,ny-sy);
|
|
|
|
if (nx==sx && ny==sy) { fx.tip_progress=next_tip_progress; return FX_OK; }
|
|
|
|
if (ny<0 || fx.len>20) return FX_Execute_Kill; // End here?
|
|
|
|
var behaviour = mat_behaviours[GetMaterial(nx,ny)+1];
|
|
|
|
var i,dx,dy;
|
|
|
|
if (behaviour == BigVolcanoBehaviour_Fill)
|
|
|
|
{
|
|
|
|
CastPXS("DuroLava", 4+Cos(fx.fill_time*40,2), 30+Cos(fx.fill_time*40,25), nx,ny-1, 0,50);
|
2015-12-13 16:30:50 +00:00
|
|
|
if (!(fx.fill_time%20) && !GBackSemiSolid(nx,ny-6)) SoundAt("BigVolcano::BigVolcanoBubble*", nx,ny, 10);
|
2013-02-25 20:47:55 +00:00
|
|
|
if (fx.fill_time++ > 31) return FX_Execute_Kill; // Done?
|
|
|
|
}
|
|
|
|
else if (behaviour != BigVolcanoBehaviour_Stop)
|
|
|
|
{
|
|
|
|
fx.fill_time = 0;
|
|
|
|
//if (behaviour == BigVolcanoBehaviour_AdvanceLava && !Random(5)) return FX_Execute_Kill; // prevent too many overlapping branches
|
|
|
|
DrawVerticalBranch(fx.x,fx.y,nx,ny,1);
|
|
|
|
fx.x=nx; fx.y=ny;
|
|
|
|
// Extend width of old segments
|
|
|
|
for (i=fx.tip_progress*last_segment/100; i<next_tip_progress*last_segment/100; ++i)
|
|
|
|
{
|
|
|
|
var old_half_wdt = (last_segment-i+1)/3+1;
|
|
|
|
var new_half_wdt = (last_segment-i+2)/3+1;
|
|
|
|
if (new_half_wdt != old_half_wdt)
|
|
|
|
ExtendVerticalBranch(fx.trace_x[i],fx.trace_y[i], fx.trace_x[i+1],fx.trace_y[i+1], old_half_wdt, new_half_wdt);
|
|
|
|
}
|
|
|
|
fx.tip_progress = next_tip_progress;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Do not bounce too much
|
|
|
|
if (++fx.bounces>6) return FX_Execute_Kill;
|
|
|
|
// Try to find a new spot to advance to
|
|
|
|
if (fx.tip_progress)
|
|
|
|
{
|
|
|
|
// Start searching from last pos we went to
|
|
|
|
sx+=fx.tip_progress*(fx.dir_x)/100;
|
|
|
|
sy+=fx.tip_progress*(fx.dir_y)/100;
|
|
|
|
}
|
|
|
|
dx = Sign(fx.dir_x);
|
|
|
|
if (!dx) dx = Random(2)*2-1;
|
|
|
|
dx *= 5;
|
|
|
|
var n_valid_branches=0;
|
|
|
|
for (i=0; i<2; ++i)
|
|
|
|
{
|
|
|
|
for (dy=-10; dy<10; dy+=2)
|
|
|
|
{
|
|
|
|
var b = mat_behaviours[GetMaterial(sx+dx,sy+dy)+1];
|
|
|
|
if (b != BigVolcanoBehaviour_Stop && b != BigVolcanoBehaviour_AdvanceLava)
|
|
|
|
{
|
|
|
|
if (!n_valid_branches++)
|
|
|
|
{
|
|
|
|
// First valid branch: Take over this one
|
|
|
|
nx = sx+dx;
|
|
|
|
ny = sy+dy;
|
|
|
|
// Do not branch too deeply
|
|
|
|
if (fx.level>1) ++i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Second possible position: Branch off this one
|
|
|
|
LaunchBranch(sx,sy,dx,dy,fx.level++);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dx*=-1;
|
|
|
|
}
|
|
|
|
// Caught in a corner?
|
|
|
|
if (!n_valid_branches) return FX_Execute_Kill;
|
|
|
|
// Spot found. Add segment if we already progressed in the last segment
|
|
|
|
/*if (fx.tip_progress)
|
|
|
|
{
|
|
|
|
fx.trace_x[fx.trace_len] = sx; fx.trace_y[fx.trace_len] = sy;
|
|
|
|
++fx.trace_len; ++fx.len;
|
|
|
|
fx.tip_progress = 0;
|
|
|
|
}*/
|
|
|
|
// Move to new spot
|
|
|
|
fx.dir_x = nx-fx.trace_x[last_segment];
|
|
|
|
fx.dir_y = ny-fx.trace_y[last_segment];
|
|
|
|
}
|
|
|
|
// End pos reached?
|
|
|
|
if (fx.tip_progress==100)
|
|
|
|
{
|
|
|
|
// Add new tip
|
|
|
|
fx.trace_x[fx.trace_len] = nx; fx.trace_y[fx.trace_len] = ny;
|
|
|
|
++fx.trace_len; ++fx.len;
|
|
|
|
// Launch next branch
|
|
|
|
fx.tip_progress = 0;
|
|
|
|
fx.dir_x = BoundBy(fx.dir_x+Random(5)-2,-8,8);
|
|
|
|
fx.dir_y = BoundBy(fx.dir_y+Random(5)-2,-15,-20);
|
|
|
|
//Log("%v %v",fx.trace_y, fx.trace_len);
|
|
|
|
}
|
|
|
|
// Remove segments that fell below the main lake (max one at a time)
|
|
|
|
if (fx.trace_y[1] >= GetLavaY(fx.trace_x[1]))
|
|
|
|
{
|
|
|
|
fx.trace_x = fx.trace_x[1:fx.trace_len];
|
|
|
|
fx.trace_y = fx.trace_y[1:fx.trace_len];
|
|
|
|
--fx.trace_len;
|
|
|
|
}
|
|
|
|
return FX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
func FxVolcanoBranchStop(object q, fx, int reason, bool temp)
|
|
|
|
{
|
|
|
|
if (!temp)
|
|
|
|
{
|
|
|
|
--n_branches;
|
|
|
|
//Log("DieBranch %d", fx.counter);
|
|
|
|
}
|
|
|
|
return FX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
func DrawVerticalBranch(int x1, int y1, int x2, int y2, int half_wdt)
|
|
|
|
{
|
|
|
|
// Draw branch from x1/y1 to x2/y2 with width half_wdt*2
|
|
|
|
//Log("BRANCH %d,%d,%d,%d, %d",x1,y1,x2,y2,half_wdt);
|
|
|
|
if (Abs(x2-x1)>Abs(y2-y1))
|
2015-01-01 16:38:30 +00:00
|
|
|
return DrawMaterialQuad("DuroLava-lava_red",x1,y1-half_wdt, x1,y1+half_wdt, x2,y2+half_wdt, x2,y2-half_wdt, BigVolcanoBehaviour_Underground);
|
2013-02-25 20:47:55 +00:00
|
|
|
else
|
2015-01-01 16:38:30 +00:00
|
|
|
return DrawMaterialQuad("DuroLava-lava_red",x1-half_wdt,y1, x1+half_wdt,y1, x2+half_wdt,y2, x2-half_wdt,y2, BigVolcanoBehaviour_Underground);
|
2013-02-25 20:47:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func ExtendVerticalBranch(int x1, int y1, int x2, int y2, int from_half_wdt, int to_half_wdt)
|
|
|
|
{
|
|
|
|
//Log("EXTBRANCH %d,%d,%d,%d, %d->%d",x1,y1,x2,y2,from_half_wdt,to_half_wdt);
|
|
|
|
// Extend width of drawn branch from x1/y1 to x2/y2 from width from_half_wdt*2 to to_half_wdt*2
|
|
|
|
// Effectively draws extra branch left and right, unless the branch had been pretty thin before
|
|
|
|
if (from_half_wdt <= 2) return DrawVerticalBranch(x1,y1,x2,y2,to_half_wdt);
|
|
|
|
if (Abs(x2-x1)>Abs(y2-y1))
|
|
|
|
{
|
2015-01-01 16:38:30 +00:00
|
|
|
DrawMaterialQuad("DuroLava-lava_red",x1,y1-to_half_wdt, x1,y1-from_half_wdt, x2,y2-from_half_wdt, x2,y2-to_half_wdt, BigVolcanoBehaviour_Underground);
|
|
|
|
DrawMaterialQuad("DuroLava-lava_red",x1,y1+to_half_wdt, x1,y1+from_half_wdt, x2,y2+from_half_wdt, x2,y2+to_half_wdt, BigVolcanoBehaviour_Underground);
|
2013-02-25 20:47:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-01-01 16:38:30 +00:00
|
|
|
DrawMaterialQuad("DuroLava-lava_red",x1-to_half_wdt,y1, x1-from_half_wdt,y1, x2-from_half_wdt,y2, x2-to_half_wdt,y2, BigVolcanoBehaviour_Underground);
|
|
|
|
DrawMaterialQuad("DuroLava-lava_red",x1+to_half_wdt,y1, x1+from_half_wdt,y1, x2+from_half_wdt,y2, x2+to_half_wdt,y2, BigVolcanoBehaviour_Underground);
|
2013-02-25 20:47:55 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-09-21 17:54:42 +00:00
|
|
|
// Get highest point of lava surface
|
|
|
|
func GetLavaPeak()
|
|
|
|
{
|
|
|
|
var y; for (var ly in lava_y) y += ly;
|
|
|
|
return y / n_lava_y;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update speed of rising lava
|
|
|
|
func SetSpeedMultiplier(int new_multiplier)
|
|
|
|
{
|
|
|
|
speed_multiplier = new_multiplier;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-02-25 20:47:55 +00:00
|
|
|
local Name = "BigVolcano";
|
|
|
|
local Description = "Volcano helper object";
|