416 lines
12 KiB
Lua
416 lines
12 KiB
Lua
|
|
local GlowMat = Material( "sprites/light_glow02_add" )
|
|
local FireMat = Material( "effects/fire_cloud1" )
|
|
local HeatMat = Material( "sprites/heatwave" )
|
|
local Materials = {
|
|
"particle/smokesprites_0001",
|
|
"particle/smokesprites_0002",
|
|
"particle/smokesprites_0003",
|
|
"particle/smokesprites_0004",
|
|
"particle/smokesprites_0005",
|
|
"particle/smokesprites_0006",
|
|
"particle/smokesprites_0007",
|
|
"particle/smokesprites_0008",
|
|
"particle/smokesprites_0009",
|
|
"particle/smokesprites_0010",
|
|
"particle/smokesprites_0011",
|
|
"particle/smokesprites_0012",
|
|
"particle/smokesprites_0013",
|
|
"particle/smokesprites_0014",
|
|
"particle/smokesprites_0015",
|
|
"particle/smokesprites_0016"
|
|
}
|
|
|
|
function EFFECT:Init( data )
|
|
self.Entity = data:GetEntity()
|
|
|
|
if not IsValid( self.Entity ) then return end
|
|
|
|
local Pos = self:GetPos()
|
|
|
|
self._Particles = {}
|
|
self.Emitter = ParticleEmitter( Pos, false )
|
|
self.Emitter3D = ParticleEmitter( Pos, true )
|
|
self._LastParticlePos = vector_origin
|
|
end
|
|
|
|
function EFFECT:AddParticle( particle )
|
|
table.insert( self._Particles, particle )
|
|
|
|
for id, particle in pairs( self._Particles ) do
|
|
if not particle or particle:GetLifeTime() > particle:GetDieTime() then
|
|
self._Particles[ id ] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function EFFECT:GetPosition()
|
|
local ent = self.Entity
|
|
|
|
if not IsValid( ent ) then return vector_origin, vector_origin end
|
|
|
|
local Pos = ent:GetPos()
|
|
local Dir = ent:GetForward()
|
|
|
|
local Target = ent:GetTarget()
|
|
local Attachment = ent:GetTargetAttachment()
|
|
|
|
if IsValid( Target ) and Attachment ~= "" then
|
|
local ID = Target:LookupAttachment( Attachment )
|
|
local Muzzle = Target:GetAttachment( ID )
|
|
|
|
if not Muzzle then return vector_origin, vector_origin end
|
|
|
|
Pos = Muzzle.Pos
|
|
Dir = Muzzle.Ang:Forward()
|
|
end
|
|
|
|
return Pos, Dir
|
|
end
|
|
|
|
function EFFECT:Think()
|
|
local ent = self.Entity
|
|
local emitter = self.Emitter
|
|
local emitter3D = self.Emitter3D
|
|
|
|
if not IsValid( emitter ) or not IsValid( emitter3D ) then return true end
|
|
|
|
local T = CurTime()
|
|
|
|
if IsValid( ent ) and not self._KillSwitch then
|
|
if not ent:GetActive() then
|
|
self._KillSwitch = true
|
|
self._KillSwitchTime = CurTime() + 2
|
|
end
|
|
|
|
if (self.nextDFX or 0) < T then
|
|
self.nextDFX = T + 0.01
|
|
|
|
local Pos, Dir = self:GetPosition()
|
|
|
|
self:MakeFlameStream( emitter, emitter3D, Pos, Dir )
|
|
self:MakeFlameMuzzle( emitter, emitter3D, Pos, Dir )
|
|
self:SetRenderBoundsWS( Pos, Pos + Dir * 50000 )
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
if self._KillSwitch and IsValid( emitter ) and IsValid( emitter3D ) then
|
|
if self._KillSwitchTime > T then
|
|
return true
|
|
end
|
|
end
|
|
|
|
if emitter then
|
|
emitter:Finish()
|
|
end
|
|
|
|
if emitter3D then
|
|
emitter3D:Finish()
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
function EFFECT:MakeFlameImpact( Pos, Dir, Size )
|
|
local emitter3D = self.Emitter3D
|
|
|
|
if not IsValid( emitter3D ) then return end
|
|
|
|
local hitparticle = emitter3D:Add( "effects/lvs_base/flamelet"..math.random(1,5), Pos + Dir )
|
|
if hitparticle then
|
|
hitparticle:SetStartSize( Size * 0.25 )
|
|
hitparticle:SetEndSize( Size )
|
|
hitparticle:SetDieTime( math.Rand(0.5,1) )
|
|
hitparticle:SetStartAlpha( 255 )
|
|
hitparticle:SetEndAlpha( 0 )
|
|
hitparticle:SetRollDelta( math.Rand(-2,2) )
|
|
hitparticle:SetAngles( Dir:Angle() )
|
|
end
|
|
end
|
|
|
|
function EFFECT:MakeFlameImpactWater( Pos, Dir, Size )
|
|
local emitter3D = self.Emitter3D
|
|
local emitter = self.Emitter
|
|
|
|
if not IsValid( emitter ) or not IsValid( emitter3D ) then return end
|
|
|
|
local sparticle = emitter:Add( Materials[ math.random(1, #Materials ) ], Pos )
|
|
if sparticle then
|
|
sparticle:SetVelocity( Vector(0,0,400) + VectorRand() * 100 )
|
|
sparticle:SetDieTime( Size * 0.01 )
|
|
sparticle:SetAirResistance( 500 )
|
|
sparticle:SetStartAlpha( 40 )
|
|
sparticle:SetStartSize( 0 )
|
|
sparticle:SetEndSize( Size * 4 )
|
|
sparticle:SetRoll( math.Rand(-3,3) )
|
|
sparticle:SetRollDelta( math.Rand(-1,1) )
|
|
sparticle:SetColor( 255, 255, 255 )
|
|
sparticle:SetGravity( Vector( 0, 0, 800 ) )
|
|
sparticle:SetCollide( false )
|
|
end
|
|
|
|
local hitparticle = emitter3D:Add( "effects/lvs_base/flamelet"..math.random(1,5), Pos + Dir )
|
|
if hitparticle then
|
|
hitparticle:SetStartSize( Size * 0.25 )
|
|
hitparticle:SetEndSize( Size )
|
|
hitparticle:SetDieTime( math.Rand(0.5,1) )
|
|
hitparticle:SetStartAlpha( 255 )
|
|
hitparticle:SetEndAlpha( 0 )
|
|
hitparticle:SetRollDelta( math.Rand(-2,2) )
|
|
hitparticle:SetAngles( Dir:Angle() )
|
|
end
|
|
end
|
|
|
|
function EFFECT:MakeFlameBurst( Pos, Vel, Size )
|
|
local emitter = self.Emitter
|
|
|
|
if not IsValid( emitter ) then return end
|
|
|
|
local fparticle = emitter:Add( "effects/lvs_base/fire", Pos )
|
|
if fparticle then
|
|
fparticle:SetVelocity( VectorRand() * 15 + Vector( 0, 0, 200 ) + Vel )
|
|
fparticle:SetDieTime( math.Rand(0.6,0.8) )
|
|
fparticle:SetAirResistance( 0 )
|
|
|
|
fparticle:SetStartAlpha( 255 )
|
|
fparticle:SetEndAlpha( 255 )
|
|
|
|
fparticle:SetStartSize( 40 )
|
|
fparticle:SetEndSize( 0 )
|
|
|
|
fparticle:SetRollDelta( math.Rand(-2,2) )
|
|
fparticle:SetColor( 255,255,255 )
|
|
fparticle:SetGravity( Vector( 0, 0, 0 ) )
|
|
fparticle:SetCollide( false )
|
|
|
|
self:AddParticle( fparticle )
|
|
end
|
|
|
|
local fparticle = emitter:Add( "effects/lvs_base/flamelet"..math.random(1,5), Pos )
|
|
if fparticle then
|
|
fparticle:SetVelocity( VectorRand() * 25 + Vel )
|
|
fparticle:SetDieTime( math.Rand(0.4,0.8) )
|
|
fparticle:SetStartAlpha( 150 )
|
|
fparticle:SetEndAlpha( 0 )
|
|
fparticle:SetStartSize( 0 )
|
|
fparticle:SetEndSize( math.Rand(60,120) )
|
|
fparticle:SetColor( 255, 255, 255 )
|
|
fparticle:SetGravity( Vector(0,0,100) )
|
|
fparticle:SetRollDelta( math.Rand(-2,2) )
|
|
fparticle:SetAirResistance( 0 )
|
|
end
|
|
|
|
for i = 0, 6 do
|
|
local eparticle = emitter:Add( "effects/fire_embers"..math.random(1,2), Pos )
|
|
|
|
if not eparticle then continue end
|
|
|
|
eparticle:SetVelocity( VectorRand() * 400 + Vel )
|
|
eparticle:SetDieTime( math.Rand(0.4,0.6) )
|
|
eparticle:SetStartAlpha( 255 )
|
|
eparticle:SetEndAlpha( 0 )
|
|
eparticle:SetStartSize( 20 )
|
|
eparticle:SetEndSize( 0 )
|
|
eparticle:SetColor( 255, 255, 255 )
|
|
eparticle:SetGravity( Vector(0,0,600) )
|
|
eparticle:SetRollDelta( math.Rand(-8,8) )
|
|
eparticle:SetAirResistance( 300 )
|
|
end
|
|
|
|
local Dist = (self._LastParticlePos - Pos):Length()
|
|
self._LastParticlePos = Pos
|
|
|
|
if Dist < 250 then
|
|
if math.random(1,8) ~= 1 then return end
|
|
end
|
|
|
|
local sparticle = emitter:Add( Materials[ math.random(1, #Materials ) ], Pos )
|
|
if sparticle then
|
|
sparticle:SetVelocity( Vector(0,0,400) + Vel )
|
|
sparticle:SetDieTime( math.Rand(2,4) * Size )
|
|
sparticle:SetAirResistance( 500 )
|
|
sparticle:SetStartAlpha( 125 )
|
|
sparticle:SetStartSize( 0 )
|
|
sparticle:SetEndSize( 200 * Size )
|
|
sparticle:SetRoll( math.Rand(-3,3) )
|
|
sparticle:SetRollDelta( math.Rand(-1,1) )
|
|
sparticle:SetColor( 0, 0, 0 )
|
|
sparticle:SetGravity( Vector( 0, 0, 800 ) )
|
|
sparticle:SetCollide( false )
|
|
end
|
|
end
|
|
|
|
function EFFECT:MakeFlameMuzzle( emitter, emitter3D, pos, dir )
|
|
local particle = emitter:Add( "effects/lvs_base/flamelet"..math.random(1,5), pos )
|
|
|
|
if not particle then return end
|
|
|
|
local ent = self.Entity
|
|
|
|
if not IsValid( ent ) then return end
|
|
|
|
local velDesired = ent:GetFlameVelocity()
|
|
local vel = dir * velDesired
|
|
|
|
local DieTime = 0.075
|
|
|
|
particle:SetVelocity( VectorRand() * 30 + vel )
|
|
particle:SetDieTime( DieTime )
|
|
particle:SetAirResistance( 0 )
|
|
particle:SetStartAlpha( 255 )
|
|
particle:SetEndLength( velDesired * 0.1 )
|
|
particle:SetStartLength( velDesired * 0.04 )
|
|
particle:SetStartSize( 10 )
|
|
particle:SetEndSize( 0 )
|
|
particle:SetRollDelta( math.Rand(-5,5) )
|
|
particle:SetColor( 50, 50, 255 )
|
|
particle:SetGravity( Vector( 0, 0, -600 ) )
|
|
particle:SetCollide( true )
|
|
end
|
|
|
|
function EFFECT:MakeFlameStream( emitter, emitter3D, pos, dir )
|
|
local particle = emitter:Add( "effects/lvs_base/flamelet"..math.random(1,5), pos )
|
|
|
|
if not particle then return end
|
|
|
|
local ent = self.Entity
|
|
|
|
if not IsValid( ent ) then return end
|
|
|
|
local velDesired = ent:GetFlameVelocity()
|
|
local vel = dir * velDesired
|
|
|
|
local DieTime = math.Rand( ent:GetFlameLifeTime() * 0.5, ent:GetFlameLifeTime() )
|
|
|
|
particle:SetVelocity( VectorRand() * 30 + vel )
|
|
particle:SetDieTime( DieTime )
|
|
particle:SetAirResistance( 0 )
|
|
particle:SetStartAlpha( 255 )
|
|
particle:SetEndLength( velDesired * 0.1 )
|
|
particle:SetStartLength( velDesired * 0.04 )
|
|
particle:SetStartSize( 2 )
|
|
particle:SetEndSize( ent:GetFlameSize() )
|
|
particle:SetRollDelta( math.Rand(-5,5) )
|
|
particle:SetColor( 255, 255, 255 )
|
|
particle:SetGravity( Vector( 0, 0, -600 ) )
|
|
particle:SetCollide( true )
|
|
local Delay = math.Rand( DieTime * 0.5, DieTime )
|
|
local Size = (Delay / DieTime) ^ 2
|
|
timer.Simple( Delay, function()
|
|
if not IsValid( self ) or not particle or particle.NoSmokeSpawn then return end
|
|
|
|
local ParticlePos = particle:GetPos()
|
|
|
|
self:MakeFlameBurst( ParticlePos, vel * 0.2, Size )
|
|
end)
|
|
particle:SetNextThink( CurTime() )
|
|
particle:SetThinkFunction( function( p )
|
|
if not IsValid( self ) then return end
|
|
|
|
p:SetNextThink( CurTime() + 0.05 )
|
|
|
|
local pos = p:GetPos()
|
|
local vel = p:GetVelocity()
|
|
local dir = vel:GetNormalized()
|
|
local speed = vel:Length() * 0.06
|
|
|
|
local traceData = {
|
|
start = pos,
|
|
endpos = pos + dir * speed,
|
|
filter = self.Entity,
|
|
}
|
|
local trace = util.TraceLine( traceData )
|
|
|
|
traceData.mask = MASK_WATER
|
|
local traceWater = util.TraceLine( traceData )
|
|
|
|
if traceWater.Hit and not trace.Hit then
|
|
p:SetDieTime( 0 )
|
|
p.NoSmokeSpawn = true
|
|
local RandomSize = math.Rand(60,80)
|
|
self:MakeFlameImpactWater( traceWater.HitPos, traceWater.HitNormal, RandomSize )
|
|
end
|
|
|
|
if trace.HitWorld or not trace.Hit then return end
|
|
|
|
p:SetDieTime( 0 )
|
|
p.NoSmokeSpawn = true
|
|
local RandomSize = math.Rand(40,60)
|
|
self:MakeFlameImpact( trace.HitPos, trace.HitNormal, RandomSize )
|
|
self:MakeFlameBurst( trace.HitPos, vector_origin, RandomSize / 60 )
|
|
end )
|
|
particle:SetCollideCallback( function( p, hitpos, hitnormal )
|
|
if p.NoSmokeSpawn then return end
|
|
|
|
p:SetDieTime( 0 )
|
|
p.NoSmokeSpawn = true
|
|
|
|
if not IsValid( emitter3D ) then return end
|
|
|
|
local RandomSize = math.Rand(40,60)
|
|
|
|
self:MakeFlameImpact( hitpos, hitnormal, RandomSize )
|
|
self:MakeFlameBurst( hitpos + hitnormal, vector_origin, RandomSize / 60 )
|
|
end )
|
|
|
|
particle.NoFade = true
|
|
self:AddParticle( particle )
|
|
|
|
local particle = emitter:Add( "effects/lvs_base/fire", pos )
|
|
if particle then
|
|
particle:SetVelocity( VectorRand() * 4 + dir * math.Rand(velDesired * 0.8,velDesired * 1.6) )
|
|
particle:SetDieTime( math.Rand(0.75,1.5) )
|
|
particle:SetAirResistance( 40 )
|
|
particle:SetStartAlpha( 255 )
|
|
particle:SetStartSize( 4 )
|
|
particle:SetEndSize( 0 )
|
|
particle:SetRoll( math.Rand(-3,3) )
|
|
particle:SetRollDelta( math.Rand(-6,6) )
|
|
particle:SetColor( 255, 255, 255 )
|
|
particle:SetGravity( VectorRand() * 400 - Vector(0,0,600) )
|
|
particle:SetCollide( true )
|
|
end
|
|
end
|
|
|
|
function EFFECT:Render()
|
|
local ent = self.Entity
|
|
|
|
if not IsValid( ent ) then return end
|
|
|
|
if ent:GetActive() and not self._KillSwitch then
|
|
local Scale = 1
|
|
local Pos, Dir = self:GetPosition()
|
|
|
|
local scroll = -CurTime() * 5
|
|
|
|
local Up = Dir + VectorRand() * 0.08
|
|
|
|
render.UpdateRefractTexture()
|
|
render.SetMaterial( HeatMat )
|
|
render.StartBeam( 3 )
|
|
render.AddBeam( Pos, 8 * Scale, scroll, Color( 0, 0, 255, 200 ) )
|
|
render.AddBeam( Pos + Up * 32 * Scale, 32 * Scale, scroll + 2, color_white )
|
|
render.AddBeam( Pos + Up * 128 * Scale, 32 * Scale, scroll + 5, Color( 0, 0, 0, 0 ) )
|
|
render.EndBeam()
|
|
end
|
|
|
|
if not istable( self._Particles ) then return end
|
|
|
|
for id, particle in pairs( self._Particles ) do
|
|
if not particle then continue end
|
|
|
|
local S = particle:GetLifeTime() / particle:GetDieTime()
|
|
local A = ((1 - S) ^ 2) * 0.5
|
|
local Size = particle:GetStartSize() * A * 8
|
|
|
|
if particle.NoFade then
|
|
Size = particle:GetEndSize() * S * 8
|
|
end
|
|
|
|
render.SetMaterial( GlowMat )
|
|
render.DrawSprite( particle:GetPos(), Size, Size, Color( 255 * A, 150 * A, 75 * A, 255 * A) )
|
|
end
|
|
end
|