```lua
-- Файл: lua/weapons/custom_weapon.lua

SWEP.PrintName = "Кастомное Оружие"
SWEP.Author = "ВашеИмя"
SWEP.Instructions = "Левый клик для стрельбы."
SWEP.Spawnable = true
SWEP.AdminOnly = false

-- Настройка боеприпасов
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = "none"

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

-- Отключаем стандартные руки и ViewModel
SWEP.UseHands = false
SWEP.ViewModel = "" -- Оставьте пустым для отключения
SWEP.ViewModelFOV = 54

-- Указываем модель для мира (что видят другие игроки)
SWEP.WorldModel = "models/deadfall/weapons/fb wz,35 vis.mdl" -- Укажите правильный путь к модели

-- Установка типа хватки
function SWEP:Initialize()
    self:SetHoldType("pistol") -- Измените при необходимости
end

-- Создание клиентской модели оружия
if CLIENT then
    function SWEP:CreateWeaponModel()
        if IsValid(self.WeaponModel) then return end
        self.WeaponModel = ClientsideModel(self.WorldModel)
        if IsValid(self.WeaponModel) then
            self.WeaponModel:SetNoDraw(true)
        else
            print("Ошибка: Не удалось создать клиентскую модель оружия по пути " .. self.WorldModel)
        end
    end

    -- Обновление позиции и углов модели оружия
    function SWEP:UpdateWeaponModel()
        if not IsValid(self.WeaponModel) or not IsValid(self:GetOwner()) then return end
        local owner = self:GetOwner()
        local boneIndex = owner:LookupBone("ValveBiped.Bip01_R_Hand") -- Кость правой руки
        if not boneIndex then return end

        local boneMatrix = owner:GetBoneMatrix(boneIndex)
        if not boneMatrix then return end

        local pos, ang = boneMatrix:GetTranslation(), boneMatrix:GetAngles()
        -- Настройка углов поворота для правильного отображения модели
        ang:RotateAroundAxis(ang:Forward(), 10)
        ang:RotateAroundAxis(ang:Right(), 180)
        ang:RotateAroundAxis(ang:Up(), 180)
        -- Настройка позиции относительно кости руки
        pos = pos + ang:Forward() * -1.5 + ang:Right() * -2 + ang:Up() * 2.3
        self.WeaponModel:SetRenderOrigin(pos)
        self.WeaponModel:SetRenderAngles(ang)
    end

    -- Отрисовка модели оружия в мире
    function SWEP:DrawWorldModel()
        if not IsValid(self.WeaponModel) then
            self:CreateWeaponModel()
            if not IsValid(self.WeaponModel) then return end
        end

        if IsValid(self:GetOwner()) then
            self:UpdateWeaponModel()
            self.WeaponModel:DrawModel()
        else
            -- Если нет владельца, отрисовать стандартную модель
            self:DrawModel()
        end
    end

    -- Удаление клиентской модели оружия
    function SWEP:OnRemove()
        if IsValid(self.WeaponModel) then
            self.WeaponModel:Remove()
            self.WeaponModel = nil
        end
    end

    -- Очистка модели при холстере
    function SWEP:Holster()
        if IsValid(self.WeaponModel) then
            self.WeaponModel:Remove()
            self.WeaponModel = nil
        end
        return true
    end
end

-- Деплой оружия
function SWEP:Deploy()
    if CLIENT then self:CreateWeaponModel() end
    self:SendWeaponAnim(ACT_VM_DRAW)
    return true
end

-- Основная логика при первичной атаке (стрельба)
function SWEP:PrimaryAttack()
    if not self:CanPrimaryAttack() then return end
    self:SetNextPrimaryFire(CurTime() + self:GetPrimaryFireDelay())

    local owner = self:GetOwner()
    if not IsValid(owner) then return end

    -- Воспроизвести звуковой эффект
    self:EmitSound("Weapon_Pistol.Single")
    -- Воспроизвести анимацию выстрела
    self:SendWeaponAnim(ACT_VM_PRIMARYATTACK)
    owner:SetAnimation(PLAYER_ATTACK1) -- Анимация игрока при выстреле

    -- Создать эффект выстрела (Muzzle Flash)
    if CLIENT then
        local vm = owner:GetViewModel()
        if IsValid(vm) then
            local attachmentID = vm:LookupAttachment("1") -- Обычно "1" это muzzle
            local attachment = vm:GetAttachment(attachmentID)
            if attachment then
                local effect = EffectData()
                effect:SetOrigin(attachment.Pos)
                effect:SetAngles(attachment.Ang)
                effect:SetScale(1)
                util.Effect("MuzzleFlash", effect)
            end
        end
    end

    -- Логика выстрела пули со всеми эффектами
    if SERVER then
        local bullet = {}
        bullet.Num = 1
        bullet.Src = owner:GetShootPos()          -- Позиция вылета пули
        bullet.Dir = owner:GetAimVector()         -- Направление вылета пули
        bullet.Spread = Vector(0, 0, 0)           -- Разброс (измените при необходимости)
        bullet.Tracer = 1                         -- Частота появления трассеров (1 = каждый выстрел)
        bullet.TracerName = "Tracer"              -- Эффект трассера ("Tracer" - стандартный)
        bullet.Force = 5                          -- Сила попадания
        bullet.Damage = 10                        -- Урон
        bullet.AmmoType = "Pistol"

        owner:FireBullets(bullet)
    end
end

-- Задержка между выстрелами
function SWEP:GetPrimaryFireDelay()
    return 0.5 -- Уменьшил задержку до 0.5 секунд для более отзывчивой стрельбы
end

-- Проверка возможности атаки
function SWEP:CanPrimaryAttack()
    return true -- Поскольку амуниция отключена, всегда можно атаковать
end

-- Действие при вторичной атаке
function SWEP:SecondaryAttack()
    -- Если вторичная атака не используется, оставьте пустым
end
```
Как сделать чтобы оружие можно было перезарядть, в магазине 7 пуль, и 1 в патроннике. Как сделать чтобы рядом с пистолетом писало кол-во патрон в 3д.