Able to change smoke emitter opacity individually based on player variable?

Hey all. I’ve been wanting to make a smoke grenade for TTT. It’s a traitor weapon they can buy in the store, and then subsequently throw.

I’ve gotten it all written, but I’ve stumbled across an issue. When I try and make the smoke opacity different for player who are traitors than for players who aren’t(basically allowing traitors to see through it) It basically won’t work correctly. it seems to either draw one opacity or the other, not on an individual basis. Can anyone help? Here’s my code: (remember that smoke grenades are defined in two files, the weapon file, and the file that defines what it does once it explodes. I’m only posting the second one.




if SERVER then
   AddCSLuaFile("shared.lua")
end

ENT.Type = "anim"
ENT.Base = "ttt_basegrenade_proj"
ENT.Model = Model("models/weapons/w_eq_smokegrenade_thrown.mdl")


AccessorFunc( ENT, "radius", "Radius", FORCE_NUMBER )

function ENT:Initialize()
   if not self:GetRadius() then self:SetRadius(20) end

   return self.BaseClass.Initialize(self)
end

if CLIENT then

   local smokeparticles = {
      Model("particle/particle_smokegrenade"),
      Model("particle/particle_noisesphere")
   };

   function ENT:CreateSmoke(center)
      local em = ParticleEmitter(center)

      local r = self:GetRadius()
      for i=1, 20 do
         local prpos = VectorRand() * r
         prpos.z = prpos.z + 32
         local p = em:Add(table.Random(smokeparticles), center + prpos)
		 for _,ply in pairs(player.GetAll()) do
         if p and ply:IsActiveTraitor() then
            p:SetColor(230, 0, 0)
            p:SetStartAlpha(20)
            p:SetEndAlpha(10)
            p:SetVelocity(VectorRand() * math.Rand(900, 1300))
            p:SetLifeTime(0)
            
            p:SetDieTime(math.Rand(80, 100))

            p:SetStartSize(math.random(550, 650))
            p:SetEndSize(math.random(400, 440))
            p:SetRoll(math.random(-180, 180))
            p:SetRollDelta(math.Rand(-0.1, 0.1))
            p:SetAirResistance(600)

            p:SetCollide(true)
            p:SetBounce(0.4)

            p:SetLighting(false)
		else
			p:SetColor(230, 0, 0)
            p:SetStartAlpha(230)
            p:SetEndAlpha(200)
            p:SetVelocity(VectorRand() * math.Rand(900, 1300))
            p:SetLifeTime(0)
            
            p:SetDieTime(math.Rand(80, 100))

            p:SetStartSize(math.random(550, 650))
            p:SetEndSize(math.random(400, 440))
            p:SetRoll(math.random(-180, 180))
            p:SetRollDelta(math.Rand(-0.1, 0.1))
            p:SetAirResistance(600)

            p:SetCollide(true)
            p:SetBounce(0.4)

            p:SetLighting(false)
			end
		 end
      end

      em:Finish()
   end
end

function ENT:Explode(tr)
   if SERVER then
      self:SetNoDraw(true)
      self:SetSolid(SOLID_NONE)

      -- pull out of the surface
      if tr.Fraction != 1.0 then
         self:SetPos(tr.HitPos + tr.HitNormal * 0.6)
      end

      local pos = self:GetPos()

      self:Remove()
   else
      local spos = self:GetPos()
      local trs = util.TraceLine({start=spos + Vector(0,0,64), endpos=spos + Vector(0,0,-128), filter=self})
      util.Decal("SmallScorch", trs.HitPos + trs.HitNormal, trs.HitPos - trs.HitNormal)      

      self:SetDetonateExact(0)

      if tr.Fraction != 1.0 then
         spos = tr.HitPos + tr.HitNormal * 0.6
      end

      -- Smoke particles can't get cleaned up when a round restarts, so prevent
      -- them from existing post-round.
      if GetRoundState() == ROUND_POST then return end

      self:CreateSmoke(spos)
   end
end



[editline]5th October 2013[/editline]

hullo?

Just see if LocalPlayer( ):IsActiveTraitor( )

Wrap the p:SetStartAlpha p:SetEndAlpha functions with if / else statements.

Your issue is that you are running it for all players on the client. clients run it individually, so you’re running it so many times for each individual client!!!

Remove that for loop, just use LocalPlayer( )!

like this?




if SERVER then
   AddCSLuaFile("shared.lua")
end

ENT.Type = "anim"
ENT.Base = "ttt_basegrenade_proj"
ENT.Model = Model("models/weapons/w_eq_smokegrenade_thrown.mdl")


AccessorFunc( ENT, "radius", "Radius", FORCE_NUMBER )

function ENT:Initialize()
   if not self:GetRadius() then self:SetRadius(20) end

   return self.BaseClass.Initialize(self)
end

if CLIENT then

   local smokeparticles = {
      Model("particle/particle_smokegrenade"),
      Model("particle/particle_noisesphere")
   };

   function ENT:CreateSmoke(center)
      local em = ParticleEmitter(center)

      local r = self:GetRadius()
      for i=1, 20 do
         local prpos = VectorRand() * r
         prpos.z = prpos.z + 32
         local p = em:Add(table.Random(smokeparticles), center + prpos)
         if p and LocalPlayer:IsActiveTraitor() then
            p:SetColor(230, 0, 0)
            p:SetStartAlpha(20)
            p:SetEndAlpha(10)
            p:SetVelocity(VectorRand() * math.Rand(900, 1300))
            p:SetLifeTime(0)
            
            p:SetDieTime(math.Rand(80, 100))

            p:SetStartSize(math.random(550, 650))
            p:SetEndSize(math.random(400, 440))
            p:SetRoll(math.random(-180, 180))
            p:SetRollDelta(math.Rand(-0.1, 0.1))
            p:SetAirResistance(600)

            p:SetCollide(true)
            p:SetBounce(0.4)

            p:SetLighting(false)
		elseif p and not LocalPlayer():IsActiveTraitor() then
			p:SetColor(230, 0, 0)
            p:SetStartAlpha(230)
            p:SetEndAlpha(200)
            p:SetVelocity(VectorRand() * math.Rand(900, 1300))
            p:SetLifeTime(0)
            
            p:SetDieTime(math.Rand(80, 100))

            p:SetStartSize(math.random(550, 650))
            p:SetEndSize(math.random(400, 440))
            p:SetRoll(math.random(-180, 180))
            p:SetRollDelta(math.Rand(-0.1, 0.1))
            p:SetAirResistance(600)

            p:SetCollide(true)
            p:SetBounce(0.4)

            p:SetLighting(false)
		 end
      end

      em:Finish()
   end
end

function ENT:Explode(tr)
   if SERVER then
      self:SetNoDraw(true)
      self:SetSolid(SOLID_NONE)

      -- pull out of the surface
      if tr.Fraction != 1.0 then
         self:SetPos(tr.HitPos + tr.HitNormal * 0.6)
      end

      local pos = self:GetPos()

      self:Remove()
   else
      local spos = self:GetPos()
      local trs = util.TraceLine({start=spos + Vector(0,0,64), endpos=spos + Vector(0,0,-128), filter=self})
      util.Decal("SmallScorch", trs.HitPos + trs.HitNormal, trs.HitPos - trs.HitNormal)      

      self:SetDetonateExact(0)

      if tr.Fraction != 1.0 then
         spos = tr.HitPos + tr.HitNormal * 0.6
      end

      -- Smoke particles can't get cleaned up when a round restarts, so prevent
      -- them from existing post-round.
      if GetRoundState() == ROUND_POST then return end

      self:CreateSmoke(spos)
   end
end



forget the elseif you added, the else was fine
you forgot the () on the end of one of your 'LocalPlayer’s

Did those changes :slight_smile: Anything else to fix?

Edit: Throwing an error. Line 53 expected ‘=’ near ‘end’





if SERVER then
   AddCSLuaFile("shared.lua")
end

ENT.Type = "anim"
ENT.Base = "ttt_basegrenade_proj"
ENT.Model = Model("models/weapons/w_eq_smokegrenade_thrown.mdl")


AccessorFunc( ENT, "radius", "Radius", FORCE_NUMBER )

function ENT:Initialize()
   if not self:GetRadius() then self:SetRadius(20) end

   return self.BaseClass.Initialize(self)
end

if CLIENT then

   local smokeparticles = {
      Model("particle/particle_smokegrenade"),
      Model("particle/particle_noisesphere")
   };

   function ENT:CreateSmoke(center)
      local em = ParticleEmitter(center)

      local r = self:GetRadius()
      for i=1, 20 do
         local prpos = VectorRand() * r
         prpos.z = prpos.z + 32
         local p = em:Add(table.Random(smokeparticles), center + prpos)
         if p and LocalPlayer():IsActiveTraitor() then
            p:SetColor(230, 0, 0)
            p:SetStartAlpha(20)
            p:SetEndAlpha(10)
            p:SetVelocity(VectorRand() * math.Rand(900, 1300))
            p:SetLifeTime(0)
            
            p:SetDieTime(math.Rand(80, 100))

            p:SetStartSize(math.random(550, 650))
            p:SetEndSize(math.random(400, 440))
            p:SetRoll(math.random(-180, 180))
            p:SetRollDelta(math.Rand(-0.1, 0.1))
            p:SetAirResistance(600)

            p:SetCollide(true)
            p:SetBounce(0.4)

            p:SetLighting(false)
		else p and not LocalPlayer():IsActiveTraitor() then
			p:SetColor(230, 0, 0)
            p:SetStartAlpha(230)
            p:SetEndAlpha(200)
            p:SetVelocity(VectorRand() * math.Rand(900, 1300))
            p:SetLifeTime(0)
            
            p:SetDieTime(math.Rand(80, 100))

            p:SetStartSize(math.random(550, 650))
            p:SetEndSize(math.random(400, 440))
            p:SetRoll(math.random(-180, 180))
            p:SetRollDelta(math.Rand(-0.1, 0.1))
            p:SetAirResistance(600)

            p:SetCollide(true)
            p:SetBounce(0.4)

            p:SetLighting(false)
			end
		 end
      end

      em:Finish()
   end

function ENT:Explode(tr)
   if SERVER then
      self:SetNoDraw(true)
      self:SetSolid(SOLID_NONE)

      -- pull out of the surface
      if tr.Fraction != 1.0 then
         self:SetPos(tr.HitPos + tr.HitNormal * 0.6)
      end

      local pos = self:GetPos()

      self:Remove()
   else
      local spos = self:GetPos()
      local trs = util.TraceLine({start=spos + Vector(0,0,64), endpos=spos + Vector(0,0,-128), filter=self})
      util.Decal("SmallScorch", trs.HitPos + trs.HitNormal, trs.HitPos - trs.HitNormal)      

      self:SetDetonateExact(0)

      if tr.Fraction != 1.0 then
         spos = tr.HitPos + tr.HitNormal * 0.6
      end

      -- Smoke particles can't get cleaned up when a round restarts, so prevent
      -- them from existing post-round.
      if GetRoundState() == ROUND_POST then return end

      self:CreateSmoke(spos)
   end
end



I’m not sure which line 53 is. But, tab your lines!! If you start an if, tab in. If you end an if, tab out.

when you write an ELSE, it’s an else. you added a then to the else.

[lua]if ( condition ) then

else
// This matches anything which is NOT the condition

end[/lua]

It looks like you did

[lua]if ( condition ) then

else p && !LocalPlayer( ):IsActiveTraitor( ) then
// This matches anything which is NOT the condition

end[/lua]

If you remove the p && !LocalPlayer( ):IsActiveTraitor( ) then

or make the else an elseif you should be fine.

herp derp fixed. Thanks a bunch! :slight_smile:

Would you mind helping me with another issue I’m having? I’m sure it’s yet another lack of knowledge, but I just started coding lua 3 days ago, so it’s a steep learning curve.

So I’m trying to code some SWEP’s that will give you varying effects when you put them on. For instance moon shoes will give you lower gravity to jump further, or juke boots will make you invisible but freeze you in place. I don’t have a problem removing the effects when they die, I just hook into player die and remove the effects if they had the weapon out. But the problem I’m coming across is removing the effects On Drop.

Apparently all other SWEP functions are shared client/server, but OnDrop is Server only, and I can’t figure out how to remove the effects from the client. Maybe you could help? You seem like a LUA god.

Here’s my code:



if SERVER then
   AddCSLuaFile( "shared.lua" )
end

if CLIENT then
   SWEP.PrintName = "Juke Boots"
   SWEP.Slot      = -1

   SWEP.ViewModelFOV  = 10
   SWEP.ViewModelFlip = false
   
end

if SERVER then
   resource.AddFile("materials/VGUI/ttt/icon_HSGjukeboots.vmt")
end
if CLIENT then
SWEP.Icon = "VGUI/ttt/icon_HSGjukeboots"
end

-- Always derive from weapon_tttbase.
SWEP.Base				= "weapon_tttbase"

--- Standard GMod values

SWEP.Base					= "weapon_tttbase"
SWEP.HoldType				= "normal"
SWEP.drawworld				= false

SWEP.Primary.ClipSize       = -1
SWEP.Primary.DefaultClip    = -1
SWEP.Primary.Automatic      = false
SWEP.Primary.Ammo       	= "none"
SWEP.Primary.Delay 			= 1.0

SWEP.Secondary.ClipSize     = -1
SWEP.Secondary.DefaultClip  = -1
SWEP.Secondary.Automatic    = false
SWEP.Secondary.Ammo     	= "none"
SWEP.Secondary.Delay 		= 1.0

SWEP.ViewModel  = "models/weapons/v_crowbar.mdl"
SWEP.WorldModel = "models/weapons/w_toolgun.mdl"

--- TTT config values
SWEP.Kind = WEAPON_NONE
SWEP.AutoSpawnable = false
SWEP.CanBuy = { ROLE_TRAITOR }
SWEP.InLoadoutFor = nil
SWEP.LimitedStock = true
SWEP.AllowDrop = true
SWEP.IsSilent = false
SWEP.NoSights = true

function SWEP:PrimaryAttack()
end

function SWEP:DrawWorldModelTranslucent()
end

function SWEP:DrawWorldModel()
end

function SWEP:ShouldDropOnDie()
   return false
end

local function playerDies( victim )
	if victim.HasLeadshoes then
	victim:Freeze( false );
	ULib.invisible(victim, should_uncloak, 255 )
	end
end
 
hook.Add( "PlayerDeath", "playerDeathTest", playerDies )


function SWEP:Deploy()
function HasOwner( )
end
if SERVER then
self.Owner.HasLeadshoes = true
self.Owner:Freeze ( true );
ULib.invisible(self.Owner, not should_uncloak, 254 )
self.Owner:SetNWBool("disguised", true)
end
return
end

function SWEP:Holster()
self.Owner.HasLeadshoes = false
if SERVER then
self.Owner:Freeze( false );
ULib.invisible(self.Owner, should_uncloak, 0 )
self.Owner:SetNWBool("disguised", false)
end
return true
end

function SWEP:OnDrop()
end

function SWEP:OnRemove()
    if CLIENT and IsValid(self.Owner) and self.Owner == LocalPlayer() and self.Owner:Alive() then
      RunConsoleCommand("lastinv")
	end
end

if CLIENT then

   SWEP.EquipMenuData = {
      type = "Boots",
      desc = "These boots will freeze you in place, hide your name, 
and make you invisible! 
Just hope they don't bump into you..."
   };
end





Well, OnRemove might work. But, for anything that’s REALM X only, you can network it to get it to the other side…

On the server:
[lua]util.AddNetworkString( “YourNetworkMessage” );[/lua]

then on drop

[lua]net.Start( “YourNetworkMessage” )
net.WriteTable( { id = self:EntIndex( ), weapon = self:GetClass( ), owner = self.Owner:EntIndex( ) } )
net.Broadcast( )[/lua]

then on client
[lua]net.Receive( “YourNetworkMessage”, function( byte, Player ) // or vice versa
local _tab = net.ReadTable();
local _id = _tab.id;
local _ent = Entity( _id );
local _ownerid = _tab.owner;
local _owner = Entity( _ownerid )
local _class = _tab.weapon;

// remove the effect, is that enough data?
end )[/lua]

I did this and I get “[ERROR] addons/pyroweaponpack/lua/weapons/weapon_ttt_jukeboots/shared.lua:118: attempt to call method ‘Freeze’ (a nil value)”



if SERVER then
util.AddNetworkString( "jukebootdrop" );
end

function SWEP:OnDrop()
net.Start( "jukebootdrop" )
   net.WriteTable( { id = self:EntIndex( ), weapon = self:GetClass( ), owner = self.Owner:EntIndex( ) } )
net.Broadcast( )
end

net.Receive( "jukebootdrop", function( byte, Player ) // or vice versa
   local _tab = net.ReadTable();
   local _id = _tab.id;
   local _ent = Entity( _id );
   local _ownerid = _tab.owner;
   local _owner = Entity( _ownerid )
   local _class = _tab.weapon;
	_owner:Freeze( false );
	ULib.invisible(_owner, should_uncloak, 0 )
	_owner:SetNWBool("disguised", false)
   
end )



edit: please bare with me, I’m very new to this and I appreciate your help a whole lot.

Freeze is a server-side function as far as I’m aware. the net.Receive is received by clients.

Oh. Ok so I guess I’ll have to use self.Owner:SetMoveType(MOVETYPE_NONE) which, unfortunately, has some issues that Freeze doesn’t seem to have.

If you’re currently moving when you switch to movetype_none, your footstep sound continues to play is the biggest one.

[editline]6th October 2013[/editline]

Alright here is my final revision: I changed from using Freeze to SetMoveType, and I change from using ULiB.invisible to SetRenderMode which seemed to fix those errors.

I also started using SWEP:OnRemove() which also helped, but I’ve got one final hurdle it seems.

Here’s the code:



local function playerDies( victim )
	if victim.HasLeadshoes then
	victim:SetMoveType(MOVETYPE_WALK)
	self.Owner:SetRenderMode(RENDERMODE_NORMAL)
	end
end
 
hook.Add( "PlayerDeath", "playerDeathTest", playerDies )


function SWEP:Deploy()
self.Owner.HasLeadshoes = true
self.Owner:SetRenderMode(RENDERMODE_NONE)
self.Owner:SetMoveType(MOVETYPE_NONE);
self.Owner:SetNWBool("disguised", true)
end

function SWEP:Holster()
self.Owner.HasLeadshoes = false
self.Owner:SetRenderMode(RENDERMODE_NORMAL)
self.Owner:SetMoveType(MOVETYPE_WALK)
self.Owner:SetNWBool("disguised", false)
return true
end

if SERVER then
util.AddNetworkString( "jukebootdrop" );
end


function SWEP:OnDrop()
self:Remove()
end

function SWEP:OnRemove()
self.Owner:SetRenderMode(RENDERMODE_NORMAL)
self.Owner:SetMoveType(MOVETYPE_WALK)
self.Owner:SetNWBool("disguised", false)
end


I am getting this error: Tried to use NULL entity!
This is occuring on line 100, which is the line “self.Owner:SetRenderMode(RENDERMODE_NORMAL)” right below function SWEP:OnRemove().

I don’t return that error anywhere else, so I don’t understand why it returns in OnRemove.