forked from Mirrors/openclonk
added Armin's particle fire
http://forum.openclonk.org/topic_show.pl?tid=3070 Only some optimizations have been added.stable-6.1
parent
2a112b1d00
commit
569e0d0cb3
Binary file not shown.
After Width: | Height: | Size: 74 KiB |
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=FireBorder
|
||||
Face=0,0,128,128,-64,-64
|
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=FireSharp
|
||||
Face=0,0,100,150,-40,-75
|
|
@ -67,7 +67,7 @@ global func Incinerate(
|
|||
return true;
|
||||
}
|
||||
else
|
||||
AddEffect("Fire", this, 100, 2, this, nil, caused_by, !!blasted, incinerating_object, strength);
|
||||
AddEffect("Fire", this, 100, 4, this, nil, caused_by, !!blasted, incinerating_object, strength);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -96,6 +96,7 @@ global func FxIntNonFlammableEffect(string new_name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
global func FxFireStart(object target, proplist effect, int temp, int caused_by, bool blasted, object incinerating_object, strength)
|
||||
{
|
||||
// safety
|
||||
|
@ -180,10 +181,89 @@ global func FxFireStart(object target, proplist effect, int temp, int caused_by,
|
|||
effect.blasted = blasted;
|
||||
effect.incinerating_obj = incinerating_object;
|
||||
effect.no_burn_decay = target.NoBurnDecay;
|
||||
|
||||
// store fire particles
|
||||
effect.smoke =
|
||||
{
|
||||
R = 255,
|
||||
G = 255,
|
||||
B = 255,
|
||||
CollisionVertex = 1000,
|
||||
OnCollision = PC_Stop(),
|
||||
ForceX = PV_Wind(50),
|
||||
DampingX = PV_Linear(900,999),
|
||||
ForceY = -7,
|
||||
DampingY = PV_Linear(1000,PV_Random(650,750)),
|
||||
Rotation = PV_Random(0, 359),
|
||||
Phase = PV_Random(0, 3)
|
||||
};
|
||||
effect.chaoticspark =
|
||||
{
|
||||
Size = PV_Linear(1, 0),
|
||||
ForceX = PV_KeyFrames(10, 0, PV_Random(-6, 6), 333, PV_Random(-6, -6), 666, PV_Random(6, 6), 1000, PV_Random(-6, 6)),
|
||||
ForceY = PV_KeyFrames(10, 0, PV_Random(-8, 5), 333, PV_Random(-8, 5), 666, PV_Random(-10, 10), 1000, PV_Random(-10, 15)),
|
||||
Stretch = PV_Speed(1000, 500),
|
||||
Rotation = PV_Direction(),
|
||||
CollisionVertex = 0,
|
||||
OnCollision = PC_Die(),
|
||||
R = 255,
|
||||
G = PV_Linear(255,200),
|
||||
B = PV_Random(0, 100),
|
||||
DampingX=950,
|
||||
DampingY=950,
|
||||
Alpha = PV_Random(40,140),
|
||||
BlitMode = GFX_BLIT_Additive
|
||||
};
|
||||
effect.redfiredense =
|
||||
{
|
||||
R = PV_Random(0, 255),
|
||||
G = 0,
|
||||
B = 0,
|
||||
Alpha = 120,
|
||||
Rotation = PV_Random(0, 359),
|
||||
Phase = PV_Random(0, 3),
|
||||
OnCollision = 0
|
||||
};
|
||||
effect.flameborder =
|
||||
{
|
||||
R = 255,
|
||||
G = PV_Linear(255,0),
|
||||
B = 0,
|
||||
Phase = PV_Random(0, 4),
|
||||
OnCollision = PC_Die(),
|
||||
OnCollision = 0,
|
||||
Alpha = PV_KeyFrames(0, 0, 0, 100, 80, 600, 80, 1000, 1)
|
||||
};
|
||||
effect.sharpflame =
|
||||
{
|
||||
R = 255,
|
||||
G = PV_KeyFrames(0, 0, 255, 666, 0, 627, 0),
|
||||
B = 0,
|
||||
Rotation = PV_Random(-5, 5),
|
||||
Phase = PV_Random(0, 5),
|
||||
OnCollision = 0,
|
||||
BlitMode = GFX_BLIT_Additive
|
||||
};
|
||||
|
||||
// Optimization: Only for living beings the flame actually follows the object. That means for all other objects, the flames can be rendered as one batch.
|
||||
if (target->GetOCF() & OCF_Alive)
|
||||
{
|
||||
effect.sharpflame.Attach = ATTACH_MoveRelative;
|
||||
effect.flameborder.Attach = ATTACH_MoveRelative;
|
||||
}
|
||||
|
||||
// Prepare some more values.
|
||||
EffectCall(target, effect, "UpdateEffectProperties");
|
||||
|
||||
// Reduce checks, smoke and a few other particles if there are other burning objects around.
|
||||
effect.FreqReduction = 1;
|
||||
for (var nearby in FindObjects (Find_Distance(effect.height)))
|
||||
if (nearby->OnFire())
|
||||
++effect.FreqReduction;
|
||||
effect.FreqReduction = effect.Interval * BoundBy(effect.FreqReduction / 3, 1, 6);
|
||||
|
||||
// Set values
|
||||
//target->FirePhase=Random(MaxFirePhase);
|
||||
if ((target->GetDefCoreVal("Width", "DefCore") * target->GetDefCoreVal("Height", "DefCore")) > 500)
|
||||
if ((4 * effect.width * effect.height) > 500)
|
||||
target->Sound("Inflame", false, 100);
|
||||
if (target->GetMass() >= 100)
|
||||
if (target->Sound("Fire", false, 100, nil, 1))
|
||||
|
@ -196,6 +276,37 @@ global func FxFireStart(object target, proplist effect, int temp, int caused_by,
|
|||
return FX_OK;
|
||||
}
|
||||
|
||||
|
||||
global func FxFireUpdateEffectProperties(object target, proplist effect)
|
||||
{
|
||||
effect.width = target->GetObjWidth() / 2;
|
||||
effect.height = target->GetObjHeight() / 2;
|
||||
|
||||
effect.fire_width = effect.width * effect.strength / 100 + 1;
|
||||
effect.fire_height = effect.height * effect.strength / 100 + 2;
|
||||
|
||||
effect.pspeed = -effect.fire_height/2;
|
||||
|
||||
effect.redfiredense.Size = PV_KeyFrames(0, 0, 1, 500, PV_Random(effect.fire_width/10, effect.fire_width/6), 1000, 1);
|
||||
|
||||
var smokesize = effect.fire_width * 2;
|
||||
if (smokesize > 60) smokesize = 50;
|
||||
effect.smoke.Size = PV_Linear(smokesize, smokesize * 5);
|
||||
effect.smoke.Alpha = PV_KeyFrames(0, 0, 1, 50, effect.strength, 1000, 0);
|
||||
|
||||
var stretch = 500 * effect.fire_height / effect.fire_width;
|
||||
effect.maxhgt = effect.fire_height - effect.fire_width * stretch / 1500;
|
||||
var sharpbottom = 0;
|
||||
if (GetCategory() & C4D_Structure || GetCategory() & C4D_Vehicle) sharpbottom++;
|
||||
|
||||
effect.flameborder.Stretch = stretch;
|
||||
effect.flameborder.Size = PV_KeyFrames(0, 0, effect.fire_width * (1 + sharpbottom), 500, effect.fire_width * 2, 1000, effect.fire_width);
|
||||
effect.border_active = (effect.strength > 49) && (effect.fire_height > 10);
|
||||
effect.sharpflame.Size = PV_KeyFrames(0, 0, effect.fire_width * (2 + sharpbottom), 500, effect.fire_width * 3, 1000, effect.fire_width*2);
|
||||
effect.sharpflame.Alpha = PV_KeyFrames(0, 0, 0, 350, 190 * effect.strength/100, 700, 190 * effect.strength/100, 1000, 0);
|
||||
effect.sharpflame.Stretch = stretch;
|
||||
}
|
||||
|
||||
global func FxFireTimer(object target, proplist effect, int time)
|
||||
{
|
||||
// safety
|
||||
|
@ -205,30 +316,53 @@ global func FxFireTimer(object target, proplist effect, int time)
|
|||
//if(!GetPlayerName(effect.caused_by)) effect.caused_by=NO_OWNER;;
|
||||
|
||||
// strength changes over time
|
||||
if(time % 4 == 0)
|
||||
if ((effect.strength < 100) && (time % 8 == 0))
|
||||
{
|
||||
if (effect.strength < 50)
|
||||
{
|
||||
if (time % 8 == 0)
|
||||
{
|
||||
effect.strength = Max(effect.strength - 1, 0);
|
||||
if (effect.strength <= 0)
|
||||
return FX_Execute_Kill;
|
||||
if (effect.strength <= 0)
|
||||
return FX_Execute_Kill;
|
||||
}
|
||||
}
|
||||
else
|
||||
effect.strength = Min(effect.strength + 1, 100);
|
||||
{
|
||||
effect.strength = Min(100, effect.strength + 2);
|
||||
|
||||
if (effect.strength > 49)
|
||||
{
|
||||
effect.smoke.R = 127;
|
||||
effect.smoke.G = 127;
|
||||
effect.smoke.B = 127;
|
||||
}
|
||||
}
|
||||
|
||||
// update particle properties that depend on the effect strength
|
||||
EffectCall(target, effect, "UpdateEffectProperties");
|
||||
}
|
||||
|
||||
var width = target->GetObjWidth() / 2;
|
||||
var height = target->GetObjHeight() / 2;
|
||||
|
||||
|
||||
// target is in liquid?
|
||||
if (time % 24 == 0)
|
||||
if (time % (20 + effect.FreqReduction) == 0)
|
||||
{
|
||||
var mat;
|
||||
if (mat = GetMaterial())
|
||||
if (GetMaterialVal("Extinguisher", "Material", mat))
|
||||
{
|
||||
var steam =
|
||||
{
|
||||
Size = PV_Linear(effect.width*2, effect.width*4),
|
||||
Alpha = PV_Linear(87,0),
|
||||
R = 255,
|
||||
G = 255,
|
||||
B = 255,
|
||||
Rotation = PV_Random(0, 359)
|
||||
};
|
||||
CreateParticle("Dust", 0, -5, 0, 0, 180, steam, 2);
|
||||
return FX_Execute_Kill;
|
||||
|
||||
}
|
||||
|
||||
// check spreading of fire
|
||||
if (effect.strength > 10)
|
||||
{
|
||||
|
@ -242,14 +376,14 @@ global func FxFireTimer(object target, proplist effect, int time)
|
|||
// Do not incinerate inventory objects, since this, too, would mostly affect Clonks and losing one's bow in a fight without noticing it is nothing but annoying to the player.
|
||||
else
|
||||
{
|
||||
inc_objs = FindObjects(Find_AtRect(-width/2, -height/2, width, height), Find_Exclude(target), Find_Layer(target->GetObjectLayer()), Find_NoContainer());
|
||||
inc_objs = FindObjects(Find_AtRect(-effect.width/2, -effect.height/2, effect.width, effect.height), Find_Exclude(target), Find_Layer(target->GetObjectLayer()), Find_NoContainer());
|
||||
}
|
||||
// Loop through the selected set of objects and check contact incinerate.
|
||||
for (var obj in inc_objs)
|
||||
{
|
||||
// Check if the obj still exists, an object could be have been removed in this loop.
|
||||
if (!obj)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
if (obj->GetCategory() & C4D_Living)
|
||||
if (!obj->GetAlive())
|
||||
|
@ -279,7 +413,6 @@ global func FxFireTimer(object target, proplist effect, int time)
|
|||
}
|
||||
}
|
||||
|
||||
//if(time % 20 == 0)target->Message(Format("<c ee0000>%d</c>", effect.strength));
|
||||
// causes on object
|
||||
//target->ExecFire(effect_number, caused_by);
|
||||
if (target->GetAlive())
|
||||
|
@ -288,38 +421,51 @@ global func FxFireTimer(object target, proplist effect, int time)
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((time*10) % 100 <= effect.strength)
|
||||
if ((time*10) % 120 <= effect.strength)
|
||||
{
|
||||
target->DoDamage(2, FX_Call_DmgFire, effect.caused_by);
|
||||
if (target && !Random(2) && !effect.no_burn_decay)
|
||||
if (target && !Random(2) && !effect.no_burn_decay)
|
||||
{
|
||||
target->DoCon(-1);
|
||||
EffectCall(target, effect, "UpdateEffectProperties");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!target)
|
||||
return FX_Execute_Kill;
|
||||
//if(!(time % 2 == 0)) return FX_OK;
|
||||
|
||||
//if(!target->OnFire()) {return FX_Execute_Kill;}
|
||||
if (target->Contained())
|
||||
return FX_OK;
|
||||
|
||||
// particles
|
||||
if(time % 4 == 0)
|
||||
{
|
||||
var size = BoundBy(Max(width, height), 5, 50);
|
||||
if (size > 40)
|
||||
if (time % 8 == 0)
|
||||
return;
|
||||
|
||||
var smoke_color;
|
||||
if(effect.strength < 50)
|
||||
smoke_color = RGBa(255,255,255, 50);
|
||||
else
|
||||
smoke_color = RGBa(100, 100, 100, 50);
|
||||
|
||||
Smoke(RandomX(-width, width), RandomX(-height, height), size, smoke_color);
|
||||
}
|
||||
// Fire particles
|
||||
// Fire denses, smoke, chaotic sparks
|
||||
if (time % effect.FreqReduction == 0)
|
||||
{
|
||||
// A few red fire particles popping up in the higher area. Does not affect very small flames.
|
||||
if (effect.fire_width + effect.fire_height > 40)
|
||||
{
|
||||
if (!Random(2)) CreateParticle("FireDense", PV_Random(-effect.fire_width, effect.pspeed), PV_Random(effect.pspeed, effect.fire_height), PV_Random(-3,3), effect.pspeed, effect.fire_height/2+6, effect.redfiredense);
|
||||
if (!Random(2)) CreateParticle("FireDense", PV_Random(effect.fire_width/2, effect.fire_width), PV_Random(effect.pspeed, effect.fire_height), PV_Random(-3,3), effect.pspeed, effect.fire_height/2+6, effect.redfiredense);
|
||||
}
|
||||
|
||||
// Smoke
|
||||
CreateParticle("SmokeThick", PV_Random(-effect.fire_width,effect.fire_width), -effect.fire_height, 0, -6, 300, effect.smoke);
|
||||
|
||||
// Chaotic particles
|
||||
if (!Random(3) && effect.FreqReduction < 14)
|
||||
CreateParticle("Magic", PV_Random(-effect.fire_width, effect.fire_width), PV_Random(-effect.fire_height, effect.fire_height), PV_Random(25, -25), PV_Random(-25, 12), 50, effect.chaoticspark);
|
||||
|
||||
// Flameborders and sharp flames
|
||||
|
||||
// Flame borders
|
||||
if (effect.border_active)
|
||||
{
|
||||
CreateParticle("FireBorder", 0, effect.maxhgt, 0, effect.pspeed, 30, effect.flameborder);
|
||||
}
|
||||
|
||||
// Sharp flames
|
||||
CreateParticle("FireSharp", 0, effect.maxhgt, 0, effect.pspeed, 30, effect.sharpflame);
|
||||
}
|
||||
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -2039,29 +2039,6 @@ void C4Object::Draw(C4TargetFacet &cgo, int32_t iByPlayer, DrawMode eDrawMode, f
|
|||
if(pOldFoW && (Category & C4D_IgnoreFoW))
|
||||
pDraw->SetFoW(NULL);
|
||||
|
||||
// Fire facet - always draw, even if particles are drawn as well
|
||||
if (OnFire && eDrawMode!=ODM_BaseOnly)
|
||||
{
|
||||
C4Facet fgo;
|
||||
// Straight: Full Shape.Rect on fire
|
||||
if (fix_r == Fix0)
|
||||
{
|
||||
fgo.Set(cgo.Surface,offX + Shape.GetX(),offY + Shape.GetY(),
|
||||
Shape.Wdt,Shape.Hgt-Shape.FireTop);
|
||||
}
|
||||
// Rotated: Reduced fire rect
|
||||
else
|
||||
{
|
||||
C4Rect fr;
|
||||
Shape.GetVertexOutline(fr);
|
||||
fgo.Set(cgo.Surface,
|
||||
offX + fr.x,
|
||||
offY + fr.y,
|
||||
fr.Wdt, fr.Hgt);
|
||||
}
|
||||
::GraphicsResource.fctFire.Draw(fgo,false,(Number + Game.FrameCounter) % MaxFirePhase);
|
||||
}
|
||||
|
||||
// color modulation (including construction sign...)
|
||||
if (ColorMod != 0xffffffff || BlitMode) if (!eDrawMode) PrepareDrawing();
|
||||
|
||||
|
|
Loading…
Reference in New Issue