Niggles with my Weapon base

Holy crap, i have no idea what i’m getting myself into here.
So, i’m working on a weapon base for a new gamemode i’m trying to put together. Most all the weapons are “Akimbo” held, as in there’s one on either side of the screen.
So far, I’ve gotten them to work somewhat seamlessly, i’ve even mastered tracers and the MuzzleFlashes (Not really, that needs work still)
But now my problem is about the Recoil Animation. Because these weapons will all be very SWEP construction kit heavy, i’m just using invisible generic pistol models. needless to say, the pistol fire animation is all but terrible.
So, i decided to fake my own by using GetViewmodelPosition. problem is, i have no idea how to start this out.
Problem 1: There’s two viewmodels. in the GetViewmodelPosition func, there’s no way i can tell it to differentiate between the two. (In this case they are GetViewModel(0) - left and GetViewModel(1) - right)
Problem 2 : I can’t seem to figure out the math to fake this. (the Y pos snaps back about 10 units, then gradually returns to its original position. This method is used in the weapon base in F2S: Stronghold, but i can’t get a copy very easily anymore so i can’t just look at that for tips)
Problem 3: I STILL cannot find a reliable way to bind my muzzleflashes to a specific position on the ViewModel. They still move around when you walk around and fire.

Should i just give up on my hideous level of depth and go find a CS:S model that has rather linear fire animations? Or would any of you happen to know how to help the issue?

Here’s my base in its entirety, might as well.

[lua]
–Why do i do this to myself
if ( SERVER ) then

AddCSLuaFile( “shared.lua” )

end
SWEP.HoldType = “duel”
if ( CLIENT ) then
SWEP.Category = “AirWar Weaponbase”;
SWEP.PrintName = “AW Weaponbase”
SWEP.Author = “Archemyde”
SWEP.Contact = “”
SWEP.Purpose = “”
SWEP.Instructions = “”
SWEP.Slot = 1
SWEP.SlotPos = 1
SWEP.IconLetter = “f”

SWEP.ViewModelFlip = false
SWEP.ViewModelFlip1 = true
end

SWEP.Spawnable = true
SWEP.AdminSpawnable = true
SWEP.ViewModel = “models/weapons/v_pistol.mdl”
SWEP.WorldModel = “models/weapons/v_pistol.mdl”
SWEP.CSMuzzleFlashes = true
SWEP.ViewModelFOV = 65;

– weapon stats
SWEP.Akimbo = {}
SWEP.Akimbo.Enabled = true
SWEP.Akimbo.FlipSecondaryViewModel = true

SWEP.Primary.Sound = Sound( “Weapon_deagle.Single” );
SWEP.Primary.Recoil = 0.3;
SWEP.Primary.Damage = 76;
SWEP.Primary.NumShots = 1;
SWEP.Primary.Cone = 0.025;
SWEP.Primary.ClipSize = 1000;
SWEP.Primary.Delay = 0.04;
SWEP.Primary.DefaultClip = 1000;
SWEP.Primary.Automatic = true;
SWEP.Primary.Ammo = “pistol”;

SWEP.Secondary.ClipSize = 1000;
SWEP.Secondary.Delay = 0.04;
SWEP.Secondary.DefaultClip = 1000;
SWEP.Secondary.Automatic = false;
SWEP.Secondary.Ammo = “pistol”;
– Weapon effects
SWEP.ShellType = 1
SWEP.ShellAttach = “1”
SWEP.MuzzleAttach = “muzzle”

SWEP.WElements = {
[“deag2”] = { type = “Model”, model = “models/weapons/w_pist_deagle.mdl”, bone = “ValveBiped.Bip01_L_Hand”, rel = “”, pos = Vector(-1.201, 1.319, -0.687), angle = Angle(0, 4.318, 0), size = 1, color = Color(255, 255, 255, 255), surpresslightning = false, material = “”, skin = 0, bodygroup = {} }
}-- leftover bullshit

function SWEP:Initialize()
self:SetWeaponHoldType( self.HoldType )

if( self.Akimbo.Enabled ) then // automate some akimbo setup stuff
    self.Secondary.Ammo = self.Primary.Ammo
    self.Secondary.ClipSize = self.Primary.ClipSize
    self.Secondary.Automatic = self.Primary.Automatic
	self:SetClip1( self.Primary.ClipSize )
    self:SetClip2( self.Secondary.ClipSize )
end

if( self.CSMuzzleFlashes ) then
    self.ShellAttach = 2
    self.MuzzleAttach = 1
end
 if CLIENT then
 
    self:CreateModels(self.VElements) // create viewmodels
    self:CreateModels(self.WElements) // create worldmodels
     
    // init view model bone build function
    self.BuildViewModelBones = function( s )
        if LocalPlayer():GetActiveWeapon() == self and self.ViewModelBoneMods then
            for k, v in pairs( self.ViewModelBoneMods ) do
                local bone = s:LookupBone(k)
                if (!bone) then continue end
                local m = s:GetBoneMatrix(bone)
                if (!m) then continue end
                m:Scale(v.scale)
                m:Rotate(v.angle)
                m:Translate(v.pos)
                s:SetBoneMatrix(bone, m)
            end
        end
    end
     
end

end
function SWEP:Deploy()
if( self.Akimbo.Enabled ) then

    local vm = self.Owner:GetViewModel( 1 ) -- Amidoinitrite?
    vm:SetWeaponModel( self.ViewModel, self )
	 vm:SetColor(255,255,255,255)
  --  self:SendWeaponAnimation( self:GetDeployActivity(), 1, 1.0 )

    if( self.Akimbo.FlipSecondaryViewModel ) then
        self.ViewModelFlip1 = !self.ViewModelFlip
    end

end

– local deployTime = self:SendWeaponAnimation( self:GetDeployActivity(), 0, 1.0 ) // override 4x default

– self:SetNextPrimaryFire( deployFinishes )
– self:SetNextSecondaryFire( deployFinishes )

return true

end

function SWEP:Holster()
if CLIENT then

	local owner = self:GetOwner()
	
	
	if( owner && owner:IsValid() && owner:Alive() && owner:IsPlayer() && owner:GetViewModel( 1 ) ) then
		if IsValid(owner:GetViewModel( 1 )) then
			owner:GetViewModel( 1 ):AddEffects( EF_NODRAW ) 
		end
	end
end
return true

end

function SWEP:PrimaryAttack()
local self = self.Weapon;
local owner = self:GetOwner()
–Absolutely Disgusting.
local clip1 = self:Clip1();
local clip2 = self:Clip2();
local gun = 0
if (clip2 > clip1) then
gun = 1;
elseif (clip1 == 0) then
return;
else gun = 0
end
if (gun == 0) then //Right
if self:Clip1() == 0 then
return false end
self:SetClip1(clip1 - 1);
elseif (gun == 1) then //Left
if self:Clip2() == 0 then
return false end
self:SetClip2(clip2 - 1);
end

    local owner = self.Owner;
	if CLIENT then
	
if (gun == 0) then
self:MakeMuzzleFlash(0)
		/*local pos, ang = self:GetBonePos(owner:GetViewModel(1), "ValveBiped.muzzle" )
		local VectorToAdd = Vector(0,0,10)
		local flashpos = (pos + ang:Forward() * VectorToAdd.x + ang:Right() * VectorToAdd.y + ang:Up() * VectorToAdd.z)
		ParticleEffect("cstm_child_muzzle_small", flashpos, self.Owner:EyeAngles(), owner:GetViewModel():GetAttachment(1))*/


    else
	self:MakeMuzzleFlash(1)
		/*local pos, ang = self:GetBonePos(owner:GetViewModel(0), "ValveBiped.muzzle" )
		local VectorToAdd = Vector(0,0,10)
		local flashpos = (pos + ang:Forward() * VectorToAdd.x + ang:Right() * VectorToAdd.y + ang:Up() * VectorToAdd.z)
		ParticleEffect("cstm_child_muzzle_small", flashpos, self.Owner:EyeAngles(), owner:GetViewModel( 0 ))*/
end
end

self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
self:EmitSound( self.Primary.Sound )

self:ShootBullets( self.Primary.Damage, self.Primary.Bullets, self.Primary.Cone, 0 )
self:AddViewKick()
self:ViewModelKick(0)
-- effects

end
function SWEP:MakeMuzzleFlash(gun) – lololol
local side = gun
print(side)
local owner = self.Weapon:GetOwner()
vml = self.Owner:GetViewModel(0)
vmr = self.Owner:GetViewModel(1)
–muzl = vml:LookupBone(“ValveBiped.muzzle”)
–muzr = vmr:LookupBone(“ValveBiped.muzzle”)
local posl, angl = self:GetBonePos(owner:GetViewModel(1), “ValveBiped.muzzle” )
local posr, angr = self:GetBonePos(owner:GetViewModel(0), “ValveBiped.muzzle” )
local VectorToAdd = Vector(0,0,10)
local flashposleft = (posl + angl:Forward() * VectorToAdd.x + angl:Right() * VectorToAdd.y + angl:Up() * VectorToAdd.z)
local flashposright = (posr + angr:Forward() * VectorToAdd.x + angr:Right() * VectorToAdd.y + angr:Up() * VectorToAdd.z)

	muzl = flashposleft
	muzr = flashposright
	if (muzl or muzr) then
		ef = EffectData()
		if side == 0 then
			ef:SetOrigin(flashposleft)
			ef:SetEntity(vml)
			print(ef:GetEntity())
			elseif side == 1 then
			ef:SetOrigin(flashposright)
			ef:SetEntity(vmr)
		end
		ef:SetAngles(self.Owner:GetAngles())
		util.Effect("aw_muzzle", ef)

	end
	
end

function SWEP:ViewModelKick(side)
local kickpower = self.Primary.Recoil
local currentside = side
if side == 1 then
CurVM = self.Owner:GetViewModel(1)
CurVM.StartKickTime = CurTime()
CurVM.EndKickTime = CurTime() + 20
elseif side == 0 then
CurVM = self.Owner:GetViewModel(0)
CurVM.StartKickTime = CurTime()
CurVM.EndKickTime = CurTime() + 20
end
local kickpos = Vector(0,50 * kickpower, 0)

end
function SWEP:SecondaryAttack()
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
end
function SWEP:SendWeaponAnimation( anim, idx, pbr )

idx = idx or 0
pbr = pbr or 1.0

local owner = self:GetOwner()
    
if( owner && owner:IsValid() && owner:IsPlayer() ) then

    local vm = owner:GetViewModel( idx )

    local idealSequence = self:SelectWeightedSequence( anim )
    local nextSequence = self:FindTransitionSequence( self:GetSequence(), idealSequence )
    
    vm:RemoveEffects( EF_NODRAW )
    vm:SetPlaybackRate( pbr )

    if( nextSequence > 0 ) then
        vm:SendViewModelMatchingSequence( nextSequence )
    else
        vm:SendViewModelMatchingSequence( idealSequence )
    end

    return vm:SequenceDuration( vm:GetSequence() )
end    

end
function SWEP:ViewModelKick(side)
– i dont even know what i’m trying to do here anymore
local kickpower = self.Primary.Recoil
local currentside = side
if side == 1 then
CurVM = self.Owner:GetViewModel(1)
CurVM.StartKickTime = CurTime()
CurVM.EndKickTime = CurTime() + 20
elseif side == 0 then
CurVM = self.Owner:GetViewModel(0)
CurVM.StartKickTime = CurTime()
CurVM.EndKickTime = CurTime() + 20
end
local kickpos = Vector(0,50 * kickpower, 0)

end
function SWEP:GetViewModelPosition( pos, ang )
local kickpower = self.Primary.Recoil
– local currentside =
–SHIT
return pos, ang
end

function SWEP:GetSwayScale()

return 0.4

end

function SWEP:GetBobScale()

return 1.0

end

function SWEP:ApplyVecAngOffset( pos, ang, destpos, destang, frac )

ang:RotateAroundAxis( ang:Right(),         destang.p * frac )
ang:RotateAroundAxis( ang:Up(),         destang.y * frac )
ang:RotateAroundAxis( ang:Forward(),     destang.r * frac )

local Right     = ang:Right()
local Up         = ang:Up()
local Forward     = ang:Forward()

pos = pos + destpos.x * Right * frac
pos = pos + destpos.y * Forward * frac
pos = pos + destpos.z * Up * frac

return pos, ang

end

function PDTR_CTFWeaponHook()

local p = LocalPlayer()

if( p and IsValid( p ) ) then
    local aw = p:GetActiveWeapon()

    if( aw and IsValid(aw)) then
        if( aw.PreDrawTranslucentRenderables ) then aw:PreDrawTranslucentRenderables() end
    end
end

end
hook.Add( “PreDrawTranslucentRenderables”, “PDTR_CTFWeaponHook”, PDTR_CTFWeaponHook )

function SWEP:GetReloadTimeModifier( )
return 1.0
end

function SWEP:AddViewKick()
self.Owner:ViewPunch( (self.Owner:GetPunchAngle()*0.1) + Angle( -self.Primary.Recoil/10, 0, 0 ) )
end

function SWEP:GetShootDirection()
return ( self.Owner:EyeAngles() + self.Owner:GetPunchAngle() ):Forward() // shoot direction, we need to consider the punch angles as we maybe using ViewPunch for recoil
end

function SWEP:GetSpreadBias()

if( self.Owner and self.Owner:IsPlayer() ) then

    local owner = self.Owner
    local spreadBias = 1.0
    
    if( owner:Crouching() ) then
        spreadBias = spreadBias * 0.75
    end
    if( owner:GetVelocity():Length() >= 20 )then
		spreadBias = spreadBias * 3
	end

    return spreadBias
end

return 1.0

end
local gun = 0
if CLIENT then
–holy fuck this looks like shit
function SWEP:GetTracerOrigin()
local owner = self.Owner;
if gun == 0 then gun = 1
elseif gun == 1 then gun = 0
end
print(gun)
if gun == 0 then
–PrintTable( owner:GetViewModel(1))
local pos, ang = self:GetBonePos(owner:GetViewModel(1), “ValveBiped.muzzle” )
local VectorToAdd = Vector(0,0,10)
return (pos + ang:Forward() * VectorToAdd.x + ang:Right() * VectorToAdd.y + ang:Up() * VectorToAdd.z)

	elseif gun == 1 then
		local pos, ang = self:GetBonePos(owner:GetViewModel(1), "ValveBiped.muzzle" )
		local VectorToAdd = Vector(0,0,0)
		return (pos + ang:Forward() * VectorToAdd.x + ang:Right() * VectorToAdd.y + ang:Up() * VectorToAdd.z)
		
	--else return owner:GetShootPos() 
	end
end

end
function SWEP:ShootBullets( damage, bullets, spread, vmidx )
local vm = self.Owner:GetViewModel( vmidx or 0 )
spread = spread * self:GetSpreadBias()

local bullet = {}
bullet.Num         = numbullets
bullet.Src         = self.Owner:GetShootPos()
bullet.Dir         = self:GetShootDirection()            
bullet.Spread     = Vector( spread, spread, 0 )        
bullet.Tracer    = 1
bullet.Force    = 100                           
bullet.Damage    = math.Round(damage)
bullet.AmmoType = "Pistol"
bullet.TracerName     = "Tracer"
bullet.Callback = function ( attacker, tr, dmginfo )
    self.Weapon:BulletCallback( attacker, tr, dmginfo, 0 )
end

self.Owner:FireBullets( bullet )

end

function SWEP:BulletCallback( attacker, tr, dmginfo, bounce )

if( !self or !IsValid( self.Weapon ) ) then return end

return { damage = true, effect = true, effects = true };

end

function SWEP:GetPrimaryAttackActivity()
return ACT_VM_PRIMARYATTACK
end

function SWEP:GetIdleActivity()
return ACT_VM_IDLE
end

function SWEP:GetShootPlaybackRate()

return 1.0

end

if( CLIENT ) then
SWEP.DrawCrosshair = false // do not draw the default crosshair

crosshair_r = 255
crosshair_g = 0
crosshair_b = 0
crosshair_a = 200
crosshair_scale = CreateClientConVar( “crosshair_scale”, 1.7, true, false );
crosshair = GetConVar( “crosshair” );

function SWEP:DrawHUD()
	self:DrawCustomCrosshair()
	self:DrawAmmoCounter()
end

function SWEP:DrawCrosshairBit( x, y, width, height, alpha )
/*
	surface.SetDrawColor( 0, 0, 0, alpha );
	surface.DrawRect( x, y, width, height );
  */  
	surface.SetDrawColor( crosshair_r, crosshair_g, crosshair_b, alpha );    
	surface.DrawRect( x+1, y+1, width-2, height-2 );
	
end

function SWEP:DrawAmmoCounter()

	local screenScale = ( ScrH() / 720 )
	local ammoWidth = 120 * screenScale
	local blockHeight = 6 * screenScale
	local blockGap = 3 * screenScale
	
	if( self.Primary.ClipSize > 0 ) then
		local blockWidth = (ammoWidth / self.Primary.ClipSize) - ( blockGap / (self.Primary.ClipSize - 1) )
		local sourcePosX = ScrW() - 20 - ammoWidth - ( blockGap * self.Primary.ClipSize )
		local sourcePosY = ScrH() - 20 - blockHeight
		
		local secondaryPosY = sourcePosY - blockHeight - 7
		
		for i=0,self.Primary.ClipSize-1 do
			local blockColor = Color( 0, 0, 0, 150 )
			
			if( i < self:Clip1() ) then
				blockColor = Color( 255, 255, 255, 200 )
			end
			
			surface.SetDrawColor( 0, 0, 0, 75 )
			surface.DrawRect( sourcePosX + ( blockWidth * i ) + ( blockGap * i ) - 1, sourcePosY - 1, blockWidth + 2, blockHeight + 2 )
			
			surface.SetDrawColor( blockColor.r, blockColor.g, blockColor.b, blockColor.a )
			surface.DrawRect( sourcePosX + ( blockWidth * i ) + ( blockGap * i ), sourcePosY, blockWidth, blockHeight )
			
			if( self.Akimbo.Enabled ) then
				blockColor = Color( 0, 0, 0, 150 )
			
				if( i < self:Clip2() ) then
					blockColor = Color( 255, 255, 255, 200 )
				end                
		
				surface.SetDrawColor( 0, 0, 0, 75 )
				surface.DrawRect( sourcePosX + ( blockWidth * i ) + ( blockGap * i ) - 1, secondaryPosY - 1, blockWidth + 2, blockHeight + 2 )
				
				surface.SetDrawColor( blockColor.r, blockColor.g, blockColor.b, blockColor.a )
				surface.DrawRect( sourcePosX + ( blockWidth * i ) + ( blockGap * i ), secondaryPosY, blockWidth, blockHeight )
			end
		end
	end
end

function SWEP:DrawCustomCrosshair()

if( crosshair:GetBool() == false or crosshair_a <= 0 ) then return end

if( !self.LastCrosshairGap ) then
    self.LastCrosshairGap = 0;
end    

– if( self:IsIronsighted() and CurTime() > self.dt.ironsightTime + self.IronsightTime ) then return end

local x = ScrW()/2
local y = ScrH()/2

local gap = math.Approach( self.LastCrosshairGap, ( (self.Primary.Cone * ( 260 * (ScrH()/720) ) ) * self:GetSpreadBias()) * crosshair_scale:GetFloat(), FrameTime() * 80 );
gap = math.Clamp( gap, 0, (ScrH()/2)-100 );
local length = ( gap + 13 ) * 0.6
local alpha = crosshair_a;

if( gap > 40 * (ScrH()/720) ) then
    local overgap = gap - ( 40 * (ScrH()/720) )
    local newalpha = alpha - (overgap * 4);
    
    alpha = math.Clamp( newalpha, 0, 255 );
end

if( alpha > 0 ) then
    self:DrawCrosshairBit( x - gap - length, y - 1, length, 3, alpha ) -- left
    self:DrawCrosshairBit( x + gap + 1, y - 1, length, 3, alpha ) -- right
    self:DrawCrosshairBit( x - 1, y - gap - length, 3, length, alpha ) -- top 
    self:DrawCrosshairBit( x - 1, y + gap + 1, 3, length, alpha ) -- bottom
end

self.LastCrosshairGap = gap;

end
end

– firemode enum
FM_AUTOMATIC = 1
FM_SEMIAUTOMATIC = 2
FM_BURSTFIRE = 3

– Bullet types (for the shell effect)
SHELL_9MM = 1
SHELL_57 = 2
SHELL_556 = 3
SHELL_762NATO = 4
SHELL_12GAUGE = 5
SHELL_338MAG = 6
SHELL_50CAL = 7

SWEP.CustomShellEject = false

function SWEP:DoShootEffects( vmidx )

-- effects
if( SERVER or (CLIENT and IsFirstTimePredicted())) then
    if( self.CustomShellEject ) then
        self:EjectShell( self.ShellType, self.ShellAttach, vmidx )
    end
    
    self:BarrelSmoke( vmidx )
end

end

function SWEP:EjectShell( shell_type, attachment, vmidx )

if( self.Owner and self.Owner:IsValid() and self.Owner:IsPlayer() ) then

    local vm = self.Owner:GetViewModel( vmidx or 0 )
    
    local rf = nil
    
    if( SERVER ) then
        rf = RecipientFilter()
        self:GetEffectPlayerFilter( rf )
    end
    
    local attachInfo = vm:GetAttachment( vm:LookupAttachment( self.ShellAttach ) )
    local ed = EffectData()
    ed:SetOrigin( attachInfo.Pos )
    ed:SetAngle( attachInfo.Ang )
    ed:SetEntity( vm )
    ed:SetAttachment( vm:LookupAttachment( self.ShellAttach ) )
    ed:SetScale( shell_type or SHELL_762NATO )
        
    util.Effect( "weapon_shell", ed, true, rf or true )
end

end

function SWEP:BarrelSmoke( vmidx )

local rf = nil

if( SERVER ) then
    rf = RecipientFilter()
    self:GetEffectPlayerFilter( rf )
end
    
// Make gunsmoke
local effectdata = EffectData()
local vm = self.Owner:GetViewModel( vmidx or 0 )

if( CLIENT and self.Owner == LocalPlayer() ) then
    effectdata:SetEntity( vm )
else
    effectdata:SetOrigin( self.Owner:GetShootPos() )
    effectdata:SetEntity( self.Weapon )
end
    effectdata:SetStart( self.Owner:GetShootPos() )
    effectdata:SetNormal( self.Owner:GetAimVector() )
    effectdata:SetAttachment( 1 )
    
util.Effect( "gunsmoke", effectdata, true, rf or true )

end

function SWEP:GetEffectPlayerFilter( rf )

if( CLIENT ) then
    if( self.Owner == LocalPlayer() ) then
        rf:AddPlayer( self.Owner )
    end
else
    rf:AddPVS( self.Owner:GetPos() )
    rf:RemovePlayer( self.Owner )
end

end

function SWEP:OnRemove()

// other onremove code goes here
 
if CLIENT then
    self:RemoveModels()
end

end

if CLIENT then

SWEP.vRenderOrder = nil
function SWEP:ViewModelDrawn()
     if not self.Owner then return end
    local vm = self.Owner:GetViewModel()
    if !IsValid(vm) then return end
    if (!self.VElements) then return end
     
    if vm.BuildBonePositions ~= self.BuildViewModelBones then
        vm.BuildBonePositions = self.BuildViewModelBones
    end

    if (self.ShowViewModel == nil or self.ShowViewModel) then
        vm:SetColor(255,255,255,255)
    else
        // we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
        vm:SetColor(255,255,255,1) 
    end
     
    if (!self.vRenderOrder) then
         
        // we build a render order because sprites need to be drawn after models
        self.vRenderOrder = {}

        for k, v in pairs( self.VElements ) do
            if (v.type == "Model") then
                table.insert(self.vRenderOrder, 1, k)
            elseif (v.type == "Sprite" or v.type == "Quad") then
                table.insert(self.vRenderOrder, k)
            end
        end
         
    end

    for k, name in ipairs( self.vRenderOrder ) do
     
        local v = self.VElements[name]
        if (!v) then self.vRenderOrder = nil break end
     
        local model = v.modelEnt
        local sprite = v.spriteMaterial
         
        if (!v.bone) then continue end
         
        local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
         
        if (!pos) then continue end
         
        if (v.type == "Model" and IsValid(model)) then

            model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
            ang:RotateAroundAxis(ang:Up(), v.angle.y)
            ang:RotateAroundAxis(ang:Right(), v.angle.p)
            ang:RotateAroundAxis(ang:Forward(), v.angle.r)

            model:SetAngles(ang)
            model:SetModelScale(v.size)
             
            if (v.material == "") then
                model:SetMaterial("")
            elseif (model:GetMaterial() != v.material) then
                model:SetMaterial( v.material )
            end
             
            if (v.skin and v.skin != model:GetSkin()) then
                model:SetSkin(v.skin)
            end
             
            if (v.bodygroup) then
                for k, v in pairs( v.bodygroup ) do
                    if (model:GetBodygroup(k) != v) then
                        model:SetBodygroup(k, v)
                    end
                end
            end
             
            if (v.surpresslightning) then
                render.SuppressEngineLighting(true)
            end
             
            render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
            render.SetBlend(v.color.a/255)
            model:DrawModel()
            render.SetBlend(1)
            render.SetColorModulation(1, 1, 1)
             
            if (v.surpresslightning) then
                render.SuppressEngineLighting(false)
            end
             
        elseif (v.type == "Sprite" and sprite) then
             
            local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
            render.SetMaterial(sprite)
            render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
             
        elseif (v.type == "Quad" and v.draw_func) then
             
            local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
            ang:RotateAroundAxis(ang:Up(), v.angle.y)
            ang:RotateAroundAxis(ang:Right(), v.angle.p)
            ang:RotateAroundAxis(ang:Forward(), v.angle.r)
             
            cam.Start3D2D(drawpos, ang, v.size)
                v.draw_func( self )
            cam.End3D2D()

        end
         
    end
     
end

SWEP.wRenderOrder = nil
function SWEP:DrawWorldModel()
     
    if (self.ShowWorldModel == nil or self.ShowWorldModel) then
        self:DrawModel()
    end
     
    if (!self.WElements) then return end
     
    if (!self.wRenderOrder) then

        self.wRenderOrder = {}

        for k, v in pairs( self.WElements ) do
            if (v.type == "Model") then
                table.insert(self.wRenderOrder, 1, k)
            elseif (v.type == "Sprite" or v.type == "Quad") then
                table.insert(self.wRenderOrder, k)
            end
        end

    end
     
    if (IsValid(self.Owner)) then
        bone_ent = self.Owner
    else
        // when the weapon is dropped
        bone_ent = self
    end
     
    for k, name in pairs( self.wRenderOrder ) do
     
        local v = self.WElements[name]
        if (!v) then self.wRenderOrder = nil break end
         
        local pos, ang
         
        if (v.bone) then
            pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
        else
            pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
        end
         
        if (!pos) then continue end
         
        local model = v.modelEnt
        local sprite = v.spriteMaterial
         
        if (v.type == "Model" and IsValid(model)) then

            model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
            ang:RotateAroundAxis(ang:Up(), v.angle.y)
            ang:RotateAroundAxis(ang:Right(), v.angle.p)
            ang:RotateAroundAxis(ang:Forward(), v.angle.r)

            model:SetAngles(ang)
            model:SetModelScale(1,0)
             
            if (v.material == "") then
                model:SetMaterial("")
            elseif (model:GetMaterial() != v.material) then
                model:SetMaterial( v.material )
            end
             
            if (v.skin and v.skin != model:GetSkin()) then
                model:SetSkin(v.skin)
            end
             
            if (v.bodygroup) then
                for k, v in pairs( v.bodygroup ) do
                    if (model:GetBodygroup(k) != v) then
                        model:SetBodygroup(k, v)
                    end
                end
            end
             
            if (v.surpresslightning) then
                render.SuppressEngineLighting(true)
            end
             
            render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
            render.SetBlend(v.color.a/255)
            model:DrawModel()
            render.SetBlend(1)
            render.SetColorModulation(1, 1, 1)
             
            if (v.surpresslightning) then
                render.SuppressEngineLighting(false)
            end
             
        elseif (v.type == "Sprite" and sprite) then
             
            local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
            render.SetMaterial(sprite)
            render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
             
        elseif (v.type == "Quad" and v.draw_func) then
             
            local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
            ang:RotateAroundAxis(ang:Up(), v.angle.y)
            ang:RotateAroundAxis(ang:Right(), v.angle.p)
            ang:RotateAroundAxis(ang:Forward(), v.angle.r)
             
            cam.Start3D2D(drawpos, ang, v.size)
                v.draw_func( self )
            cam.End3D2D()

        end
         
    end
     
end

function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
     
    local bone, pos, ang
    if (tab.rel and tab.rel != "") then
         
        local v = basetab[tab.rel]
         
        if (!v) then return end
         
        // Technically, if there exists an element with the same name as a bone
        // you can get in an infinite loop. Let's just hope nobody's that stupid.
        pos, ang = self:GetBoneOrientation( basetab, v, ent )
         
        if (!pos) then return end
         
        pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
        ang:RotateAroundAxis(ang:Up(), v.angle.y)
        ang:RotateAroundAxis(ang:Right(), v.angle.p)
        ang:RotateAroundAxis(ang:Forward(), v.angle.r)
             
    else
     
        bone = ent:LookupBone(bone_override or tab.bone)

        if (!bone) then return end
         
        pos, ang = Vector(0,0,0), Angle(0,0,0)
        local m = ent:GetBoneMatrix(bone)
        if (m) then
            pos, ang = m:GetTranslation(), m:GetAngles()
        end
         
        if (IsValid(self.Owner) and self.Owner:IsPlayer() and
            ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
            ang.r = -ang.r // Fixes mirrored models
        end
     
    end
     
    return pos, ang
end
function SWEP:GetBonePos( ent, bone_name)
     
    local bone, pos, ang
     
        bone = ent:LookupBone(bone_name)

        if (!bone) then return end
         
        pos, ang = Vector(0,0,0), Angle(0,0,0)
        local m = ent:GetBoneMatrix(bone)
        if (m) then
            pos, ang = m:GetTranslation(), m:GetAngles()
        end
         
        if (IsValid(self.Owner) and self.Owner:IsPlayer() and
            ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
            ang.r = -ang.r // Fixes mirrored models
        end
     
     
    return pos, ang
end


function SWEP:CreateModels( tab )

    if (!tab) then return end

    // Create the clientside models here because Garry says we can't do it in the render hook
    for k, v in pairs( tab ) do
        if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model)) then
             
            v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
            if (IsValid(v.modelEnt)) then
                v.modelEnt:SetPos(self:GetPos())
                v.modelEnt:SetAngles(self:GetAngles())
                v.modelEnt:SetParent(self)
                v.modelEnt:SetNoDraw(true)
                v.createdModel = v.model
            else
                v.modelEnt = nil
            end
             
        elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite) 
            and file.Exists ("../materials/"..v.sprite..".vmt")) then
             
            local name = v.sprite.."-"
            local params = { ["$basetexture"] = v.sprite }
            // make sure we create a unique name based on the selected options
            local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
            for i, j in pairs( tocheck ) do
                if (v[j]) then
                    params["$"..j] = 1
                    name = name.."1"
                else
                    name = name.."0"
                end
            end

            v.createdSprite = v.sprite
            v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
             
        end
    end
     
end

function SWEP:OnRemove()
    self:RemoveModels()
end

function SWEP:RemoveModels()
    if (self.VElements) then
        for k, v in pairs( self.VElements ) do
            if (IsValid( v.modelEnt )) then v.modelEnt:Remove() end
        end
    end
    if (self.WElements) then
        for k, v in pairs( self.WElements ) do
            if (IsValid( v.modelEnt )) then v.modelEnt:Remove() end
        end
    end
    self.VElements = nil
    self.WElements = nil
end

end

[/lua]

And a small video.

http://puu.sh/6vBik

Maybe somebody can shine some light on this issue for me?

I suggest you go into HLMV and carefully measure how far the viewmodel gets pushed every shot, both in Y direction, but also Z and X, also measure how long time it takes for it to go back. Also apply a random offset to the push magnitude.

For effects, a 0 simple timer seems to fix some issues with flashes.

In ShootEffects
[lua]local effectdata = EffectData( )
effectdata:SetOrigin( self.Owner:GetShootPos( ) )
effectdata:SetEntity( self.Weapon )
effectdata:SetStart( self.Owner:GetShootPos( ) )
effectdata:SetNormal( self.Owner:GetAimVector( ) )
effectdata:SetAttachment( 1 )

timer.Simple(0, function()
	if not self.Owner then return end
	if not IsFirstTimePredicted() then return end
	util.Effect("gunsmoke", effectdata)
end)[/lua]

Attachment should VARY depending on type. Muzzle could be 1, or muzzle depending on if it’s hl2, css, etc. Ejection port is typically 2, or some name. Make sure you account for that.

Also, do the FirstTimePredicted logic.

It seems you’ve done that, but try the timer, some effects are finicky without it; it’s strange but seems to be a “hack” fix.

IIRC doing it like that actually messes up prediction, you want to do it like this

[LUA]
if not IsFirstTimePredicted() then
util.Effect(“gunsmoke”, effectdata)
end
[/LUA]

btw dont use this code archymedes or anyone on this thread because you might recieve a dmca

I’m saying: Try a 0 second simple timer.

could you tell me in layman’s terms how IsFirstTimePredicted() helps fix this issue?
I’ve followed the code above, and it seems to do the trick quite well when there’s an animation being played on the viewmodels. When no animation is played, the muzzleflash don’t show.
(I’ve switched to using the Galil models, due to its fire animation being rather fluid and linear - Although calling ACT_VM_PRIMARYATTACK on it’s model produces the draw animation for whatever reason)

[editline]27th January 2014[/editline]

oh, and here’s current muzzleflash func.
[lua]

function SWEP:MakeMuzzleFlash(gun) – lololol
local side = gun
print(side)
local owner = self.Weapon:GetOwner()
vml = self.Owner:GetViewModel(0)
vmr = self.Owner:GetViewModel(1)
–muzl = vml:LookupBone(“ValveBiped.muzzle”)
–muzr = vmr:LookupBone(“ValveBiped.muzzle”)
local posl, angl = self:GetBonePos(owner:GetViewModel(1), “v_weapon.galil” )
local posr, angr = self:GetBonePos(owner:GetViewModel(0), “v_weapon.galil” )
local VectorToAdd = Vector(0,0,0)
local flashposleft = (posl + angl:Forward() * VectorToAdd.x + angl:Right() * VectorToAdd.y + angl:Up() * VectorToAdd.z)
local flashposright = (posr + angr:Forward() * VectorToAdd.x + angr:Right() * VectorToAdd.y + angr:Up() * VectorToAdd.z)

	muzl = flashposleft
	muzr = flashposright
	if (muzl or muzr) then
		ef = EffectData()
		if side == 0 then
			ef:SetOrigin(flashposleft)
			ef:SetEntity(vml)
			ef:SetAttachment(0)
			print(ef:GetEntity())
			elseif side == 1 then
			ef:SetOrigin(flashposright)
			ef:SetEntity(vmr)
			ef:SetAttachment(1)
		end
		ef:SetAngles(self.Owner:GetAngles())
		timer.Simple(0, function()
	if not self.Owner then return end
	if not IsFirstTimePredicted() then return end
	util.Effect("aw_muzzle", ef)
end)

	end
	
end

[/lua]

The way sweps are done client-side is by spamming. The functions are spammed until both the client and the server call them at the same time. This results in the server calling it once, and the client calling it 1, 2, 10 times… Using the IsFirstTimePredicted ensures that particular code only gets ran once on the client.

Adding the timer ensures the muzzle effect gets called on the next frame; there are sometimes issues with properly getting the attachment pos where the timer has resolved them.

I see how that makes sense, thanks for explaining that.
is there anything wrong with my code above that would cause the muzzleflashes to not show up?

bumparoo, still unable to find a solution.
Am i really this bad at lua?

[editline]28th January 2014[/editline]

Let’s get specific on the muzzleflashes.
With some digging, i found out the reason of why the muzzle effects are coming from some wierd area below the front of the gun. Using my code, it’s using the “v_weapon.attachment1” bone.
here’s an image of it:

http://puu.sh/6BOJn.jpg

Why the shit would they put a bone THERE? What purpose could that possibly serve? There’s not even an attachment for the muzzle area as far as i can tell!

Did you end up sorting this issue out?