Почему иногда у оружия пули вылетают не прямо, а куда то влево вверх, исправь и напиши полный код с фиксами багов.


```lua
-- shared.lua
SWEP.Weight = 5
SWEP.DrawAmmo = true
SWEP.DrawCrosshair = false
SWEP.CSMuzzleFlashes = true
SWEP.Base = "weapon_base"
SWEP.IsQWB = true
SWEP.Author = "qurs"
SWEP.Contact = ""
SWEP.Purpose = ""
SWEP.Instructions = ""
SWEP.ViewModel = "models/weapons/v_knife_t.mdl"
SWEP.DefaultScopeMat = Material("materials/qwb/scope/awp.png")
SWEP.Category = "qurs' weapons base"
SWEP.Spawnable = false
SWEP.UseHands = true
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = "none"
SWEP.ShellType = "9mm"
SWEP.SafetyStanceSound = Sound("weapons/smg1/switch_single.wav")
local angle_zero = Angle()
local passiveHoldTypes = {
        revolver = "normal",
        ar2 = "passive",
        smg = "passive",
}

-- Позиции и углы для разных типов оружия
local defaultBulletPosAng = {
        default = {Vector(7.7, 0.4, 3.95), Angle(-3, 5.5, 0)},
        revolver = {Vector(7.7, 0.4, 3.95), Angle(-3, 5.5, 0)},
        ar2 = {Vector(20, -0.8, 11.2), Angle(-9.5, 0, 0)},
        smg = {Vector(14, -0.8, 6.8), Angle(-9.5, 0, 0)},
}

-- Вычисление пассивного типа захвата
function SWEP:CalculatePassiveHoldType()
        return passiveHoldTypes[self.HoldType] or "normal"
end

-- Обработка изменения режима безопасности
function SWEP:SafetyStanceChanged(old, new)
        local owner = self:GetOwner()
        if not IsValid(owner) then return end
        owner:EmitSound(self.SafetyStanceSound, nil, nil, self.AimSoundVolume or 0.25)
        if new then
                self:SetHoldType(self.PassiveHoldType or self:CalculatePassiveHoldType())
        else
                self:SetHoldType(self.HoldType)
        end
end

-- Настройка сетевых переменных
function SWEP:SetupDataTables()
        self:NetworkVar("Bool", 0, "SafetyStance")
        self:NetworkVar("Vector", 0, "LocalMuzzlePos")
        self:NetworkVar("Angle", 0, "LocalMuzzleAng")
        if SERVER then self:NetworkVarNotify("SafetyStance", self.SafetyStanceChanged) end
end

-- Инициализация оружия
function SWEP:Initialize()
        self:SetHoldType(self.HoldType)
        local holdType = self:GetHoldType()
        local bulletData = defaultBulletPosAng[holdType] or defaultBulletPosAng.default
        local lpos, lang = unpack(bulletData)
        self._sourceLocalMuzzlePos = self.ShootPos or lpos
        self._sourceLocalMuzzleAng = self.ShootAng or lang
        if SERVER then
                self:SetLocalMuzzlePos(self._sourceLocalMuzzlePos)
                self:SetLocalMuzzleAng(self._sourceLocalMuzzleAng)
        end
end

function SWEP:Deploy()
        return true
end

function SWEP:Holster()
        if SERVER then self.Ironsighted = false end
        return true
end

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

-- Перезарядка оружия
function SWEP:Reload()
        if not IsFirstTimePredicted() then return end
        local owner = self:GetOwner()
        if not IsValid(owner) then return end
        if owner:KeyDown(IN_USE) then return end
        if qwb.isPlayerRunning(owner) then return end
        if not self:DefaultReload(ACT_VM_RELOAD) then return end
        owner:SetAnimation(PLAYER_RELOAD)
        if SERVER then
                self.Ironsighted = false
                net.Start("qwb.setIronsight")
                net.WriteBool(self.Ironsighted)
                net.Send(owner)
        end

        self:SetNextPrimaryFire(CurTime() + 2)
end

-- Получение позиции ствола
function SWEP:GetMuzzlePos()
        local owner = self:GetOwner()
        if not IsValid(owner) then return end
        local attID = owner:LookupAttachment("anim_attachment_rh")
        if attID == 0 then return end
        local att = owner:GetAttachment(attID)
        if not att then return end
        local lpos, lang = self:GetLocalMuzzlePos(), self:GetLocalMuzzleAng()
        local pos, ang = LocalToWorld(lpos, lang, att.Pos, att.Ang)
        return pos, ang
end

function SWEP:GetBoneAng()
        local ang = self:GetLocalMuzzleAng()
        local sourceAng = self._sourceLocalMuzzleAng
        local pitch = ang.p - sourceAng.p
        return Angle(-pitch, 0, 0)
end

function SWEP:GetBulletSourcePos()
        return self:GetMuzzlePos()
end

-- Стрельба пулями
function SWEP:ShootBullet(src, dir, num_bullets, aimcone, tracer)
        local bullet = {
                Num = num_bullets,
                Src = src,
                Dir = dir,
                Spread = Vector(aimcone, aimcone, 0),
                Tracer = tracer or 5,
                Force = 1,
                Damage = self.Primary.Damage,
                AmmoType = self.Primary.Ammo,
                TracerName = self.TracerName,
        }

        self:GetOwner():FireBullets(bullet)
        self:TakePrimaryAmmo(1)
        self:ShootEffects()
end

-- Кастомизация вспышки ствола
function SWEP:MuzzleFlashCustom()
        if SERVER then
                net.Start("qwb.muzzleFlashLight")
                net.WriteEntity(self)
                net.SendPVS(self:GetBulletSourcePos())
                return
        end

        local effectData = EffectData()
        effectData:SetEntity(self)
        effectData:SetFlags(1)
        util.Effect("MuzzleFlash", effectData)
end

-- Эффект выброса гильз
function SWEP:ShellEffect()
        if SERVER then return end
        if self.NoShell then return end
        local shellType = self.ShellType
        local effectData = EffectData()
        local pos = self:GetPos()
        if self.ShellOffset then
                local att = self:GetAttachment(self:LookupAttachment("muzzle"))
                if att then pos = LocalToWorld(self.ShellOffset, angle_zero, att.Pos, att.Ang) end
        end

        effectData:SetOrigin(pos)
        effectData:SetFlags(self.ShellVelocity or 75)
        util.Effect("EjectBrass_" .. shellType, effectData)
end

-- Обработка эффектов стрельбы
function SWEP:ShootEffects()
        self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
        self:MuzzleFlashCustom()
        self:ShellEffect()
        self:EmitSound(self.Primary.Sound)
        self.RecoilAnimBack = nil
        self.RecoilAnim = true
end

-- Основная атака (стрельба)
function SWEP:PrimaryAttack()
        if not self:CanPrimaryAttack() then return end
        if not IsValid(self) or not IsValid(self:GetOwner()) then return end
        local owner = self:GetOwner()
        local pos, ang = self:GetBulletSourcePos()
        if not pos or not ang then return end
        local forward = ang:Forward()
        owner:LagCompensation(true)
        self:ShootBullet(pos, forward, self.Primary.NumShots or 1, self.Primary.Spread or 0.01, 1)
        owner:LagCompensation(false)
        self:SetNextPrimaryFire(CurTime() + self.Primary.Delay)
        if SERVER then self:CreateShootRage() end
        if not self.Ironsighted and self.HipFireRecoil then
                local pitch = math.random() >= 0.5 and -self.HipFireRecoil or self.HipFireRecoil
                local yaw = math.random() >= 0.5 and -self.HipFireRecoil or self.HipFireRecoil
                local roll = math.random() >= 0.5 and -self.HipFireRecoil or self.HipFireRecoil
                owner:SetViewPunchAngles(Angle(pitch, yaw, roll))
        end

        if self.PostPrimaryAttack then self:PostPrimaryAttack() end
end

-- Проверка возможности атаки
function SWEP:CanPrimaryAttack()
        if self:GetSafetyStance() then return false end
        local owner = self:GetOwner()
        if not IsValid(owner) then return false end
        if qwb.isPlayerRunning(owner) then return false end
        if self:Clip1() <= 0 then
                self:EmitSound("weapons/clipempty_rifle.wav")
                self:SetNextPrimaryFire(CurTime() + 0.7)
                return false
        end

        if owner:WaterLevel() > 2 then return false end
        return true
end

-- Основной цикл оружия
function SWEP:Think()
        local owner = self:GetOwner()
        if not IsValid(owner) then return end
        -- Переключение режима безопасности
        if owner:KeyDown(IN_USE) and owner:KeyDown(IN_RELOAD) and (not self.SafetyStanceCD or CurTime() >= self.SafetyStanceCD) then
                self.SafetyStanceCD = CurTime() + 0.4
                self:SetSafetyStance(not self:GetSafetyStance())
        end

        -- Управление типом захвата
        local passiveHoldType = self.PassiveHoldType or self:CalculatePassiveHoldType()
        if qwb.isPlayerRunning(owner) and self:GetHoldType() ~= passiveHoldType then
                self:SetHoldType(passiveHoldType)
                if self.Ironsighted then self.Ironsighted = false end
        elseif not qwb.isPlayerRunning(owner) and not self:GetSafetyStance() and self:GetHoldType() == passiveHoldType then
                self:SetHoldType(self.HoldType)
        end

        -- Управление "Shoot Rage"
        self.ShootRageDelta = self.ShootRageDelta or 0
        if self.ShootRage and self.ShootRage > 0 then
                self.ShootRageDelta = self.ShootRageDelta + 0.2
                self.ShootRage = math.max(self.ShootRage - 0.05, 0)
        else
                self.ShootRageDelta = 0
        end

        -- Анимация отдачи
        if self.RecoilAnim then
                local bone1 = owner:LookupBone("ValveBiped.Bip01_R_Hand")
                local bone2 = owner:LookupBone("ValveBiped.Bip01_R_UpperArm")
                if bone1 and bone2 then
                        local needle1 = Angle(self.Recoil / 50 * 90, 0, 0)
                        local needle2 = Angle(0, (self.ShootRage or 0) * math.sin(self.ShootRageDelta or 0), 0)
                        local currentAng1 = owner:GetManipulateBoneAngles(bone1)
                        local newAng1 = LerpAngle(0.8, currentAng1, needle1)
                        owner:ManipulateBoneAngles(bone1, newAng1)
                        local currentAng2 = owner:GetManipulateBoneAngles(bone2)
                        local newAng2 = LerpAngle(0.45, currentAng2, needle2)
                        owner:ManipulateBoneAngles(bone2, newAng2)
                        local ang = owner:GetManipulateBoneAngles(bone1)
                        if math.abs(ang.p - needle1.p) <= 0.1 then
                                self.RecoilAnim = nil
                                self.RecoilAnimBack = true
                        end
                end
        elseif self.RecoilAnimBack then
                local bone1 = owner:LookupBone("ValveBiped.Bip01_R_Hand")
                local bone2 = owner:LookupBone("ValveBiped.Bip01_R_UpperArm")
                if bone1 and bone2 then
                        local needle1 = Angle(0, 0, 0)
                        local needle2 = Angle(0, (self.ShootRage or 0) * math.sin(self.ShootRageDelta or 0), 0)
                        local currentAng1 = owner:GetManipulateBoneAngles(bone1)
                        local newAng1 = LerpAngle(0.1, currentAng1, needle1)
                        owner:ManipulateBoneAngles(bone1, newAng1)
                        local currentAng2 = owner:GetManipulateBoneAngles(bone2)
                        local newAng2 = LerpAngle(0.1, currentAng2, needle2)
                        owner:ManipulateBoneAngles(bone2, newAng2)
                        local ang = owner:GetManipulateBoneAngles(bone1)
                        if math.abs(ang.p - needle1.p) <= 0.1 then self.RecoilAnimBack = nil end
                end
        end
end
```