361 lines
No EOL
12 KiB
Lua
361 lines
No EOL
12 KiB
Lua
AddCSLuaFile()
|
|
|
|
ENT.Base = "base_gmodentity"
|
|
ENT.PrintName = "Particle Controller - Normal"
|
|
ENT.Author = ""
|
|
|
|
ENT.Spawnable = false
|
|
ENT.AdminSpawnable = false
|
|
ENT.RenderGroup = RENDERGROUP_NONE
|
|
|
|
|
|
|
|
|
|
function ENT:SetupDataTables()
|
|
|
|
self:NetworkVar( "Entity", 0, "TargetEnt" );
|
|
self:NetworkVar( "Entity", 1, "TargetEnt2" );
|
|
|
|
self:NetworkVar( "String", 0, "EffectName" );
|
|
self:NetworkVar( "String", 1, "NumpadState" );
|
|
|
|
self:NetworkVar( "Float", 0, "RepeatRate" );
|
|
|
|
self:NetworkVar( "Int", 0, "AttachNum" );
|
|
self:NetworkVar( "Int", 1, "AttachNum2" );
|
|
self:NetworkVar( "Int", 2, "NumpadKey" );
|
|
|
|
self:NetworkVar( "Bool", 0, "Active" );
|
|
self:NetworkVar( "Bool", 1, "RepeatSafety" );
|
|
self:NetworkVar( "Bool", 2, "Toggle" );
|
|
|
|
//we have 3 pieces of information we need for util.effect, and they're not going to be changed after the ent's been spawned, so there's no reason we can't save space by storing them all in this vector
|
|
self:NetworkVar( "Vector", 0, "UtilEffectInfo" ); //x = scale, y = magnitude, x = radius
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ENT:Initialize()
|
|
|
|
local target = self:GetTargetEnt()
|
|
local target2 = self:GetTargetEnt2()
|
|
|
|
|
|
if !string.StartWith( self:GetEffectName(), "!UTILEFFECT!" ) then
|
|
|
|
//Set things up for a particlesystem effect
|
|
|
|
if SERVER then
|
|
|
|
//Since we can't specify attachment points with Entity:CreateParticleEffect(), we have to improvise.
|
|
|
|
//If target1 is using an attachment, move ourselves to the pos/ang of that attachment and use ourselves as the target for control point 1.
|
|
local attachment1 = target:GetAttachment( self:GetAttachNum() )
|
|
if attachment1 != nil then
|
|
self:SetPos( attachment1.Pos )
|
|
self:SetAngles( attachment1.Ang )
|
|
self:Fire("setparentattachment", target:GetAttachments()[self:GetAttachNum()].name, 0.01)
|
|
self:SetTargetEnt(self)
|
|
end
|
|
|
|
//If target2 is using an attachment, then spawn an entity at the pos/ang of that attachment to use as the target for control point 2.
|
|
if IsValid(target2) then
|
|
local attachment2 = target2:GetAttachment( self:GetAttachNum2() )
|
|
if attachment2 != nil then
|
|
if self.endpoint then self.endpoint = nil end
|
|
self.endpoint = ents.Create( "info_particle_system" )
|
|
self.endpoint:SetKeyValue( "effect_name", "combineball" )
|
|
self.endpoint:SetParent(target2)
|
|
|
|
self.endpoint:SetPos( attachment2.Pos )
|
|
self.endpoint:SetAngles( attachment2.Ang )
|
|
self.endpoint:Fire("setparentattachment", target2:GetAttachments()[self:GetAttachNum2()].name, 0.01)
|
|
|
|
self:DeleteOnRemove(self.endpoint)
|
|
self.endpoint:Spawn()
|
|
self.endpoint:Activate()
|
|
self:SetTargetEnt2(self.endpoint)
|
|
end
|
|
end
|
|
|
|
else
|
|
|
|
//Make a table of control point information, so we only have to do this once instead of every time AttachParticle runs.
|
|
|
|
local clrtb = nil
|
|
if self:GetColor().r == 0 and self:GetColor().g == 0 and self:GetColor().b == 0 then
|
|
//MsgN("color = false")
|
|
else
|
|
//MsgN("color = true")
|
|
if self:GetColor().a == 1 then
|
|
clrtb = { position = Vector( self:GetColor().r / 255, self:GetColor().g / 255, self:GetColor().b / 255 ) }
|
|
else
|
|
clrtb = { position = Vector( self:GetColor().r, self:GetColor().g, self:GetColor().b ) }
|
|
end
|
|
end
|
|
self.cpointtable = {}
|
|
self.cpointtable[1] = { entity = target, attachtype = PATTACH_ABSORIGIN_FOLLOW }
|
|
|
|
if IsValid(target2) then
|
|
self.cpointtable[2] = { entity = target2, attachtype = PATTACH_ABSORIGIN_FOLLOW }
|
|
else
|
|
if clrtb then
|
|
self.cpointtable[2] = clrtb
|
|
else
|
|
self.cpointtable[2] = self.cpointtable[1]
|
|
end
|
|
end
|
|
|
|
for i = 3, 64 do
|
|
if clrtb then
|
|
self.cpointtable[i] = clrtb
|
|
else
|
|
self.cpointtable[i] = self.cpointtable[1]
|
|
end
|
|
end
|
|
|
|
PrecacheParticleSystem(self:GetEffectName())
|
|
|
|
end
|
|
|
|
end
|
|
self:SetModel("models/hunter/plates/plate.mdl") //it's a tiny block so that model-covering fx show up at a single point instead of all over an invisible error model
|
|
self:SetNoDraw(true)
|
|
|
|
|
|
if self:GetRepeatRate() > 0 then
|
|
//we're going to be repeating the effect, so let's set that up and let think do the test
|
|
self.NextRepeat = 0
|
|
else
|
|
//we won't be repeating the effect, so just attach it right now
|
|
if self:GetActive() then self:AttachParticle() end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ENT:Think()
|
|
|
|
if SERVER then return end
|
|
|
|
if self:GetNumpadState() == "off" then
|
|
//MsgN("turn off")
|
|
self:SetNumpadState("")
|
|
self:RemoveParticle(false,self:GetEffectName())
|
|
end
|
|
|
|
if self:GetNumpadState() == "on" then
|
|
//MsgN("turn on")
|
|
self:SetNumpadState("")
|
|
if self:GetRepeatRate() > 0 then
|
|
//we're going to be repeating the effect, so let's set that up and let think do the test
|
|
self.NextRepeat = 0
|
|
else
|
|
//we won't be repeating the effect, so just attach it right now
|
|
if self:GetActive() then self:AttachParticle() end
|
|
end
|
|
end
|
|
|
|
|
|
if self:GetActive() == true and self:GetRepeatRate() > 0 then
|
|
if !( self.NextRepeat > CurTime() ) then
|
|
//the repeat function is built into removeparticle so that we can be sure the old particle is gone before we add a new one
|
|
//disabling repeat safety lets the user bypass this if they want
|
|
if self:GetRepeatSafety() then
|
|
self:RemoveParticle(true,self:GetEffectName())
|
|
else
|
|
self:AttachParticle()
|
|
end
|
|
self.NextRepeat = CurTime() + self:GetRepeatRate()
|
|
end
|
|
end
|
|
|
|
self:NextThink(CurTime())
|
|
return true
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ENT:AttachParticle()
|
|
|
|
if SERVER then return end
|
|
|
|
local target = self:GetTargetEnt()
|
|
local attachnum = self:GetAttachNum()
|
|
local effectname = self:GetEffectName()
|
|
local target2 = self:GetTargetEnt2()
|
|
local attachnum2 = self:GetAttachNum2()
|
|
|
|
if effectname == nil or !target:IsValid() then return end
|
|
|
|
|
|
if string.StartWith( effectname, "!UTILEFFECT!" ) then
|
|
|
|
//Create a util effect
|
|
|
|
//Unfortunately, we have to do all of this every single time the effect repeats, because if we do it in Initialize instead, a whole bunch of stuff doesn't work properly
|
|
|
|
local effectscale = self:GetUtilEffectInfo().x
|
|
local effectmagnitude = self:GetUtilEffectInfo().y
|
|
local effectradius = self:GetUtilEffectInfo().z
|
|
|
|
local luaeffectdata = EffectData()
|
|
luaeffectdata:SetEntity( target )
|
|
if ( string.find(effectname, "Tracer", 0, true) != nil ) then luaeffectdata:SetScale(5000) else luaeffectdata:SetScale( effectscale ) end //for tracer effects, scale is the speed of the bullet, so we need to keep this high
|
|
luaeffectdata:SetMagnitude( effectmagnitude )
|
|
luaeffectdata:SetRadius(effectradius )
|
|
|
|
//flags can be set by typing !FLAG#! at the end of the effect name
|
|
luaeffectdata:SetFlags( 0 )
|
|
if string.EndsWith( effectname, "!" ) then
|
|
if string.find( effectname, "!FLAG1!" ) then luaeffectdata:SetFlags( 1 ) effectname = string.Replace( effectname, "!FLAG1!", "" ) end
|
|
if string.find( effectname, "!FLAG2!" ) then luaeffectdata:SetFlags( 2 ) effectname = string.Replace( effectname, "!FLAG2!", "" ) end
|
|
if string.find( effectname, "!FLAG3!" ) then luaeffectdata:SetFlags( 3 ) effectname = string.Replace( effectname, "!FLAG3!", "" ) end
|
|
if string.find( effectname, "!FLAG4!" ) then luaeffectdata:SetFlags( 4 ) effectname = string.Replace( effectname, "!FLAG4!", "" ) end
|
|
if string.find( effectname, "!FLAG5!" ) then luaeffectdata:SetFlags( 5 ) effectname = string.Replace( effectname, "!FLAG5!", "" ) end
|
|
if string.find( effectname, "!FLAG6!" ) then luaeffectdata:SetFlags( 6 ) effectname = string.Replace( effectname, "!FLAG6!", "" ) end
|
|
if string.find( effectname, "!FLAG7!" ) then luaeffectdata:SetFlags( 7 ) effectname = string.Replace( effectname, "!FLAG7!", "" ) end
|
|
if string.find( effectname, "!FLAG8!" ) then luaeffectdata:SetFlags( 8 ) effectname = string.Replace( effectname, "!FLAG8!", "" ) end
|
|
if string.find( effectname, "!FLAG9!" ) then luaeffectdata:SetFlags( 9 ) effectname = string.Replace( effectname, "!FLAG9!", "" ) end
|
|
end
|
|
|
|
//colors can also be set the same way
|
|
luaeffectdata:SetColor(0)
|
|
if string.EndsWith( effectname, "!" ) then
|
|
if string.find( effectname, "!COLOR1!" ) then luaeffectdata:SetColor( 1 ) effectname = string.Replace( effectname, "!COLOR1!", "" ) end
|
|
if string.find( effectname, "!COLOR2!" ) then luaeffectdata:SetColor( 2 ) effectname = string.Replace( effectname, "!COLOR2!", "" ) end
|
|
if string.find( effectname, "!COLOR3!" ) then luaeffectdata:SetColor( 3 ) effectname = string.Replace( effectname, "!COLOR3!", "" ) end
|
|
if string.find( effectname, "!COLOR4!" ) then luaeffectdata:SetColor( 4 ) effectname = string.Replace( effectname, "!COLOR4!", "" ) end
|
|
if string.find( effectname, "!COLOR5!" ) then luaeffectdata:SetColor( 5 ) effectname = string.Replace( effectname, "!COLOR5!", "" ) end
|
|
if string.find( effectname, "!COLOR6!" ) then luaeffectdata:SetColor( 6 ) effectname = string.Replace( effectname, "!COLOR6!", "" ) end
|
|
if string.find( effectname, "!COLOR7!" ) then luaeffectdata:SetColor( 7 ) effectname = string.Replace( effectname, "!COLOR7!", "" ) end
|
|
if string.find( effectname, "!COLOR8!" ) then luaeffectdata:SetColor( 8 ) effectname = string.Replace( effectname, "!COLOR8!", "" ) end
|
|
if string.find( effectname, "!COLOR9!" ) then luaeffectdata:SetColor( 9 ) effectname = string.Replace( effectname, "!COLOR9!", "" ) end
|
|
end
|
|
|
|
//dumb situational crap
|
|
if string.find( string.lower(effectname), "shakeropes" ) then luaeffectdata:SetMagnitude( effectmagnitude * 20 ) end
|
|
if string.find( string.lower(effectname), "thumperdust" ) then luaeffectdata:SetScale( effectscale * 50 ) end
|
|
if string.find( string.lower(effectname), "bloodspray" ) then luaeffectdata:SetScale( effectscale * 4 ) end
|
|
|
|
if target:GetAttachment(attachnum) != nil then
|
|
luaeffectdata:SetAttachment( attachnum )
|
|
luaeffectdata:SetStart( target:GetAttachment( attachnum ).Pos )
|
|
luaeffectdata:SetOrigin( target:GetAttachment( attachnum ).Pos )
|
|
luaeffectdata:SetAngles( target:GetAttachment( attachnum ).Ang )
|
|
luaeffectdata:SetNormal( target:GetAttachment( attachnum ).Ang:Forward() )
|
|
else
|
|
luaeffectdata:SetStart( target:GetPos() )
|
|
luaeffectdata:SetOrigin( target:GetPos() )
|
|
luaeffectdata:SetAngles( target:GetAngles() )
|
|
luaeffectdata:SetNormal( target:GetAngles():Forward() )
|
|
end
|
|
|
|
if IsValid(target2) then
|
|
if target2:GetAttachment(attachnum2) != nil then
|
|
luaeffectdata:SetOrigin( target2:GetAttachment( attachnum2 ).Pos )
|
|
luaeffectdata:SetNormal( target2:GetAttachment( attachnum2 ).Ang:Forward() )
|
|
else
|
|
luaeffectdata:SetOrigin( target2:GetPos() )
|
|
luaeffectdata:SetNormal( target2:GetAngles():Forward() )
|
|
end
|
|
end
|
|
|
|
util.Effect( string.Replace( effectname, "!UTILEFFECT!", "" ), luaeffectdata )
|
|
|
|
else
|
|
|
|
//Create a particlesystem effect
|
|
|
|
target:CreateParticleEffect(effectname,self.cpointtable)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function ENT:RemoveParticle(arewerepeating,effectwereremoving)
|
|
|
|
local target = self:GetTargetEnt()
|
|
|
|
if CLIENT then
|
|
if target:IsValid() then target:StopParticleEmission(effectwereremoving) end
|
|
|
|
//StopParticleEmission is broken and removes ALL effects on the entity, not just the one specified, so to try and counteract this we'll reactivate them.
|
|
if target != self then
|
|
for _, asdf in pairs( ents:GetAll() ) do
|
|
if asdf != self then
|
|
if IsValid(asdf) and asdf:GetClass() == "particlecontroller_normal" and asdf:GetParent() == target then
|
|
//Make sure the ent is active, but not already creating the particle by itself. We don't want to double their particle by mistake.
|
|
if asdf.GetActive and asdf:GetActive() == true and asdf:GetNumpadState() == "" then asdf:AttachParticle() end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if arewerepeating == true then self:AttachParticle() end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
//numpad functions
|
|
if SERVER then
|
|
|
|
local function NumpadPress( pl, ent )
|
|
|
|
if ( !ent || ent == NULL ) then return end
|
|
|
|
if ( ent:GetToggle() ) then
|
|
if ent:GetActive() == false then
|
|
ent:SetActive(true)
|
|
ent:SetNumpadState("on")
|
|
else
|
|
ent:SetActive(false)
|
|
ent:SetNumpadState("off")
|
|
end
|
|
else
|
|
ent:SetActive( true )
|
|
ent:SetNumpadState("on")
|
|
end
|
|
|
|
end
|
|
|
|
local function NumpadRelease( pl, ent )
|
|
|
|
if ( !ent || ent == NULL ) then return end
|
|
|
|
if ( ent:GetToggle() ) then return end
|
|
|
|
ent:SetActive(false)
|
|
ent:SetNumpadState("off")
|
|
|
|
end
|
|
|
|
numpad.Register( "Particle_Press", NumpadPress )
|
|
numpad.Register( "Particle_Release", NumpadRelease )
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function ENT:OnRemove()
|
|
self:RemoveParticle(false,self:GetEffectName())
|
|
end
|
|
|
|
|
|
|
|
|
|
//don't duplicate this
|
|
duplicator.RegisterEntityClass( "particlecontroller_normal", function( ply, data )
|
|
end, "Data" ) |