dobrograd-13-06-2022/garrysmod/addons/gmod-tools/lua/entities/particlecontroller_normal.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

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" )