docsresourcesQb Weapons

QB-Weapons - Weapon Management System

The qb-weapons resource provides comprehensive weapon management for QBCore servers, featuring weapon attachments, ammunition systems, weapon degradation, and advanced ballistics.

Overview

QB-Weapons enhances the weapon experience with realistic mechanics, customization options, maintenance requirements, and advanced combat features. The system balances realism with gameplay enjoyment.

Key Features

  • Weapon Attachments: Scopes, silencers, grips, and modifications
  • Ammunition System: Different ammo types and effects
  • Weapon Degradation: Durability and maintenance mechanics
  • Ballistics System: Realistic bullet physics and damage
  • Weapon Crafting: Custom weapon creation and modification
  • Serial Numbers: Weapon tracking and identification
  • License System: Legal weapon ownership requirements
  • Advanced Combat: Enhanced shooting mechanics

Installation

Prerequisites

  • QBCore Framework
  • qb-target (for interaction system)
  • qb-menu (for weapon menus)
  • qb-inventory (for weapon storage)

Installation Steps

  1. Download the Resource
cd resources/[qb]
git clone https://github.com/qbcore-framework/qb-weapons.git
  1. Database Setup
-- Weapon system tables
CREATE TABLE IF NOT EXISTS `weapon_attachments` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `weapon_serial` varchar(100) DEFAULT NULL,
  `attachment_type` varchar(50) DEFAULT NULL,
  `attachment_component` varchar(100) DEFAULT NULL,
  `installed_by` varchar(50) DEFAULT NULL,
  `installed_date` timestamp DEFAULT current_timestamp(),
  PRIMARY KEY (`id`)
);
 
CREATE TABLE IF NOT EXISTS `weapon_licenses` (
  `citizenid` varchar(50) NOT NULL,
  `license_type` varchar(50) DEFAULT 'basic',
  `issued_date` timestamp DEFAULT current_timestamp(),
  `expires_date` timestamp DEFAULT NULL,
  `status` varchar(50) DEFAULT 'active',
  `issued_by` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`citizenid`)
);
  1. Add Items to qb-core/shared/items.lua
-- Weapon Attachments
['weapon_scope'] = {
    ['name'] = 'weapon_scope',
    ['label'] = 'Weapon Scope',
    ['weight'] = 200,
    ['type'] = 'item',
    ['image'] = 'weapon_scope.png',
    ['unique'] = false,
    ['useable'] = true,
    ['shouldClose'] = true,
    ['combinable'] = nil,
    ['description'] = 'Precision scope for weapons'
},
['weapon_silencer'] = {
    ['name'] = 'weapon_silencer',
    ['label'] = 'Weapon Silencer',
    ['weight'] = 150,
    ['type'] = 'item',
    ['image'] = 'weapon_silencer.png',
    ['unique'] = false,
    ['useable'] = true,
    ['shouldClose'] = true,
    ['combinable'] = nil,
    ['description'] = 'Sound suppressor for firearms'
},
-- Ammunition Types
['ammo_regular'] = {
    ['name'] = 'ammo_regular',
    ['label'] = 'Regular Ammunition',
    ['weight'] = 5,
    ['type'] = 'item',
    ['image'] = 'ammo_regular.png',
    ['unique'] = false,
    ['useable'] = false,
    ['shouldClose'] = false,
    ['combinable'] = nil,
    ['description'] = 'Standard ammunition'
},
['ammo_armor_piercing'] = {
    ['name'] = 'ammo_armor_piercing',
    ['label'] = 'Armor Piercing Rounds',
    ['weight'] = 6,
    ['type'] = 'item',
    ['image'] = 'ammo_ap.png',
    ['unique'] = false,
    ['useable'] = false,
    ['shouldClose'] = false,
    ['combinable'] = nil,
    ['description'] = 'High penetration ammunition'
}
  1. Add to server.cfg
ensure qb-weapons

Configuration

Basic Configuration

Config = {}
 
-- General Settings
Config.UseTarget = true
Config.WeaponDegradation = true
Config.RequireLicense = true
Config.AttachmentSystem = true
 
-- Weapon Categories
Config.WeaponCategories = {
    ["pistols"] = {
        label = "Pistols",
        license_required = "basic",
        attachments_allowed = {"silencer", "flashlight", "scope"},
        max_attachments = 3
    },
    ["rifles"] = {
        label = "Rifles", 
        license_required = "rifle",
        attachments_allowed = {"scope", "silencer", "grip", "bipod"},
        max_attachments = 4
    },
    ["shotguns"] = {
        label = "Shotguns",
        license_required = "shotgun",
        attachments_allowed = {"flashlight", "grip"},
        max_attachments = 2
    }
}
 
-- Attachment Configuration
Config.Attachments = {
    ["silencer"] = {
        label = "Silencer",
        component = "COMPONENT_AT_PI_SUPP",
        effects = {
            noise_reduction = 0.7,
            damage_modifier = 0.95,
            range_modifier = 0.98
        },
        compatible_weapons = {"weapon_pistol", "weapon_combatpistol", "weapon_carbinerifle"}
    },
    ["scope"] = {
        label = "Scope",
        component = "COMPONENT_AT_SCOPE_LARGE",
        effects = {
            accuracy_bonus = 0.15,
            range_bonus = 1.2
        },
        compatible_weapons = {"weapon_carbinerifle", "weapon_assaultrifle", "weapon_sniperrifle"}
    },
    ["flashlight"] = {
        label = "Flashlight",
        component = "COMPONENT_AT_PI_FLSH",
        effects = {
            visibility_bonus = true
        },
        compatible_weapons = {"weapon_pistol", "weapon_combatpistol", "weapon_pumpshotgun"}
    }
}
 
-- Degradation System
Config.Degradation = {
    base_degradation_rate = 0.1, -- Per shot
    repair_kits = {
        ["weapon_repair_kit"] = {
            repair_amount = 25,
            success_rate = 0.9
        },
        ["advanced_repair_kit"] = {
            repair_amount = 50,
            success_rate = 0.95
        }
    },
    breakdown_threshold = 10, -- Weapon jams below this durability
    destruction_threshold = 0  -- Weapon destroyed at 0 durability
}

Ammunition System

-- Ammunition Types and Effects
Config.AmmunitionTypes = {
    ["regular"] = {
        label = "Regular Ammunition",
        damage_modifier = 1.0,
        penetration = 0.5,
        cost = 5
    },
    ["hollow_point"] = {
        label = "Hollow Point",
        damage_modifier = 1.25,
        penetration = 0.3,
        cost = 8,
        license_required = "advanced"
    },
    ["armor_piercing"] = {
        label = "Armor Piercing",
        damage_modifier = 0.9,
        penetration = 0.9,
        cost = 12,
        license_required = "advanced"
    },
    ["incendiary"] = {
        label = "Incendiary Rounds",
        damage_modifier = 1.1,
        penetration = 0.6,
        special_effect = "fire",
        cost = 15,
        license_required = "special"
    }
}
 
-- License Types
Config.LicenseTypes = {
    ["basic"] = {
        label = "Basic Firearms License",
        cost = 2500,
        duration = 90, -- days
        weapons_allowed = {"pistols"},
        background_check = true
    },
    ["rifle"] = {
        label = "Rifle License", 
        cost = 5000,
        duration = 90,
        prerequisites = {"basic"},
        weapons_allowed = {"pistols", "rifles"},
        training_required = true
    },
    ["advanced"] = {
        label = "Advanced Firearms License",
        cost = 10000,
        duration = 60,
        prerequisites = {"rifle"},
        weapons_allowed = {"pistols", "rifles", "shotguns"},
        special_ammunition = true
    }
}

API Reference

Client Exports

AttachComponent

Attach a component to a weapon.

local success = exports['qb-weapons']:AttachComponent(weaponHash, componentHash)
 
-- Parameters:
-- weaponHash: Weapon hash
-- componentHash: Component hash to attach
-- Returns: boolean success status

GetWeaponDurability

Get current weapon durability.

local durability = exports['qb-weapons']:GetWeaponDurability(weaponSerial)
 
-- Returns: durability percentage (0-100)

RepairWeapon

Repair a weapon using repair kit.

local success = exports['qb-weapons']:RepairWeapon(weaponSerial, repairKitType)
 
-- Parameters:
-- weaponSerial: Weapon serial number
-- repairKitType: Type of repair kit to use

Server Exports

CreateWeapon

Create a new weapon with serial number.

local weaponData = exports['qb-weapons']:CreateWeapon(weaponType, quality, craftedBy)
 
-- Parameters:
-- weaponType: Type of weapon to create
-- quality: Weapon quality (0-100)
-- craftedBy: Creator citizen ID

CheckWeaponLicense

Verify player’s weapon license.

local isValid = exports['qb-weapons']:CheckWeaponLicense(source, weaponCategory)
 
-- Parameters:
-- source: Player server ID
-- weaponCategory: Category of weapon
-- Returns: boolean license validity

RegisterWeapon

Register weapon to player.

exports['qb-weapons']:RegisterWeapon(source, weaponSerial, weaponType)
 
-- Parameters:
-- source: Player server ID
-- weaponSerial: Weapon serial number
-- weaponType: Type of weapon

Events

Client Events

-- Weapon degraded
RegisterNetEvent('qb-weapons:client:weaponDegraded', function(weaponHash, newDurability)
    -- Handle weapon degradation
end)
 
-- Attachment installed
RegisterNetEvent('qb-weapons:client:attachmentInstalled', function(weaponHash, componentHash)
    -- Handle attachment installation
end)
 
-- Weapon jammed
RegisterNetEvent('qb-weapons:client:weaponJammed', function(weaponHash)
    -- Handle weapon jam
end)

Server Events

-- Weapon fired
RegisterNetEvent('qb-weapons:server:weaponFired', function(weaponHash, ammoType)
    -- Handle weapon firing
end)
 
-- License application
RegisterNetEvent('qb-weapons:server:applyLicense', function(licenseType)
    -- Handle license application
end)
 
-- Weapon crafted
RegisterNetEvent('qb-weapons:server:weaponCrafted', function(weaponType, components)
    -- Handle weapon crafting
end)

Usage Examples

Weapon Degradation System

-- Client-side degradation tracking
local weaponDurability = {}
 
RegisterNetEvent('qb-weapons:client:weaponFired', function()
    local ped = PlayerPedId()
    local weapon = GetSelectedPedWeapon(ped)
    
    if weapon and weapon ~= GetHashKey("WEAPON_UNARMED") then
        local weaponSerial = GetWeaponSerial(weapon)
        
        if weaponSerial then
            -- Apply degradation
            TriggerServerEvent('qb-weapons:server:degradeWeapon', weaponSerial)
        end
    end
end)
 
-- Server-side degradation processing
RegisterNetEvent('qb-weapons:server:degradeWeapon', function(weaponSerial)
    local src = source
    local player = QBCore.Functions.GetPlayer(src)
    
    if not player then return end
    
    -- Get weapon from inventory
    local weapon = GetWeaponBySerial(player, weaponSerial)
    if not weapon then return end
    
    -- Calculate degradation
    local currentDurability = weapon.info.durability or 100
    local degradationAmount = Config.Degradation.base_degradation_rate
    
    -- Apply ammunition type modifiers
    local ammoType = weapon.info.ammo_type or "regular"
    local ammoConfig = Config.AmmunitionTypes[ammoType]
    if ammoConfig and ammoConfig.degradation_modifier then
        degradationAmount = degradationAmount * ammoConfig.degradation_modifier
    end
    
    local newDurability = math.max(0, currentDurability - degradationAmount)
    
    -- Update weapon durability
    weapon.info.durability = newDurability
    player.Functions.SetItemInfo(weapon.slot, weapon.info)
    
    -- Check for weapon jam or breakdown
    if newDurability <= Config.Degradation.breakdown_threshold and newDurability > 0 then
        -- Chance of weapon jam
        if math.random() < 0.1 then -- 10% chance
            TriggerClientEvent('qb-weapons:client:weaponJammed', src, weapon.name)
        end
    elseif newDurability <= 0 then
        -- Weapon destroyed
        player.Functions.RemoveItem(weapon.name, 1, weapon.slot)
        TriggerClientEvent('QBCore:Notify', src, 'Your weapon broke beyond repair!', 'error')
    end
    
    TriggerClientEvent('qb-weapons:client:updateDurability', src, weaponSerial, newDurability)
end)

Attachment System

-- Attachment installation system
RegisterNetEvent('qb-weapons:client:installAttachment', function(attachmentType)
    local ped = PlayerPedId()
    local weapon = GetSelectedPedWeapon(ped)
    
    if weapon == GetHashKey("WEAPON_UNARMED") then
        QBCore.Functions.Notify("You need to have a weapon equipped", "error")
        return
    end
    
    -- Check if attachment is compatible
    local weaponName = GetWeaponNameFromHash(weapon)
    local attachmentConfig = Config.Attachments[attachmentType]
    
    if not attachmentConfig then
        QBCore.Functions.Notify("Invalid attachment type", "error")
        return
    end
    
    local isCompatible = false
    for i = 1, #attachmentConfig.compatible_weapons do
        if attachmentConfig.compatible_weapons[i] == weaponName then
            isCompatible = true
            break
        end
    end
    
    if not isCompatible then
        QBCore.Functions.Notify("Attachment not compatible with this weapon", "error")
        return
    end
    
    -- Check if player has attachment item
    QBCore.Functions.TriggerCallback('qb-weapons:server:hasAttachment', function(hasAttachment)
        if hasAttachment then
            -- Install attachment animation
            QBCore.Functions.Progressbar("installing_attachment", "Installing " .. attachmentConfig.label .. "...", 10000, false, true, {
                disableMovement = true,
                disableCarMovement = true,
                disableMouse = false,
                disableCombat = true,
            }, {
                animDict = "amb@world_human_clipboard@male@base",
                anim = "base",
            }, {}, {}, function()
                -- Installation complete
                TriggerServerEvent('qb-weapons:server:installAttachment', weapon, attachmentType)
            end)
        else
            QBCore.Functions.Notify("You don't have this attachment", "error")
        end
    end, attachmentType)
end)
 
-- Server-side attachment installation
RegisterNetEvent('qb-weapons:server:installAttachment', function(weaponHash, attachmentType)
    local src = source
    local player = QBCore.Functions.GetPlayer(src)
    local attachmentConfig = Config.Attachments[attachmentType]
    
    if not player or not attachmentConfig then return end
    
    -- Remove attachment item from inventory
    local attachmentItem = "weapon_" .. attachmentType
    if player.Functions.RemoveItem(attachmentItem, 1) then
        -- Apply attachment to weapon
        local weaponSerial = GetPlayerWeaponSerial(src, weaponHash)
        if weaponSerial then
            -- Store attachment in database
            MySQL.insert('INSERT INTO weapon_attachments (weapon_serial, attachment_type, attachment_component, installed_by) VALUES (?, ?, ?, ?)', {
                weaponSerial,
                attachmentType,
                attachmentConfig.component,
                player.PlayerData.citizenid
            })
            
            -- Apply visual component
            TriggerClientEvent('qb-weapons:client:applyAttachment', src, weaponHash, attachmentConfig.component)
            
            TriggerClientEvent('QBCore:Notify', src, attachmentConfig.label .. ' installed successfully!', 'success')
        end
    end
end)

License System

-- Weapon license application system
RegisterNetEvent('qb-weapons:client:applyForLicense', function(licenseType)
    local licenseConfig = Config.LicenseTypes[licenseType]
    if not licenseConfig then return end
    
    -- Check prerequisites
    QBCore.Functions.TriggerCallback('qb-weapons:server:checkPrerequisites', function(meetsRequirements, canAfford)
        if not meetsRequirements then
            QBCore.Functions.Notify("You don't meet the requirements for this license", "error")
            return
        end
        
        if not canAfford then
            QBCore.Functions.Notify("Insufficient funds: $" .. licenseConfig.cost, "error")
            return
        end
        
        -- Background check process
        if licenseConfig.background_check then
            QBCore.Functions.Progressbar("background_check", "Processing background check...", 15000, false, true, {
                disableMovement = true,
                disableCarMovement = true,
                disableMouse = false,
                disableCombat = true,
            }, {
                animDict = "amb@world_human_clipboard@male@base",
                anim = "base",
            }, {}, {}, function()
                -- Background check complete
                if math.random() < 0.95 then -- 95% pass rate
                    TriggerServerEvent('qb-weapons:server:issueLicense', licenseType)
                else
                    QBCore.Functions.Notify("Background check failed", "error")
                end
            end)
        else
            TriggerServerEvent('qb-weapons:server:issueLicense', licenseType)
        end
        
    end, licenseType)
end)
 
-- Server-side license issuance
RegisterNetEvent('qb-weapons:server:issueLicense', function(licenseType)
    local src = source
    local player = QBCore.Functions.GetPlayer(src)
    local licenseConfig = Config.LicenseTypes[licenseType]
    
    if not player or not licenseConfig then return end
    
    -- Process payment
    if player.Functions.RemoveMoney('bank', licenseConfig.cost, 'weapon-license') then
        -- Calculate expiration date
        local expirationDate = os.date("%Y-%m-%d %H:%M:%S", os.time() + (licenseConfig.duration * 24 * 60 * 60))
        
        -- Issue license
        MySQL.insert('INSERT INTO weapon_licenses (citizenid, license_type, expires_date, issued_by) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE license_type = ?, expires_date = ?', {
            player.PlayerData.citizenid,
            licenseType,
            expirationDate,
            'Los Santos Firearms Bureau',
            licenseType,
            expirationDate
        })
        
        -- Give license item
        player.Functions.AddItem('weapon_license', 1, false, {
            type = licenseType,
            expires = expirationDate,
            holder = player.PlayerData.charinfo.firstname .. " " .. player.PlayerData.charinfo.lastname
        })
        
        TriggerClientEvent('QBCore:Notify', src, 'Weapon license issued successfully!', 'success')
    else
        TriggerClientEvent('QBCore:Notify', src, 'Payment failed', 'error')
    end
end)

Troubleshooting

Common Issues

Attachments Not Working

-- Check weapon compatibility
function CheckWeaponCompatibility(weaponHash, attachmentType)
    local weaponName = GetWeaponNameFromHash(weaponHash)
    local attachmentConfig = Config.Attachments[attachmentType]
    
    if not attachmentConfig then
        print("Attachment config not found:", attachmentType)
        return false
    end
    
    for i = 1, #attachmentConfig.compatible_weapons do
        if attachmentConfig.compatible_weapons[i] == weaponName then
            return true
        end
    end
    
    print("Weapon not compatible:", weaponName, "with", attachmentType)
    return false
end

Degradation Issues

  • Verify weapon serial tracking system
  • Check degradation rate calculations
  • Ensure proper inventory integration

License Verification Problems

-- Debug license checking
RegisterCommand('checklicense', function()
    QBCore.Functions.TriggerCallback('qb-weapons:server:getLicense', function(license)
        if license then
            print("License type:", license.license_type)
            print("Expires:", license.expires_date)
            print("Status:", license.status)
        else
            print("No weapon license found")
        end
    end)
end)

Debug Commands

-- Give weapon attachment
/giveattachment [player_id] [attachment_type]
 
-- Repair weapon
/repairweapon [player_id] [weapon_serial]
 
-- Check weapon durability
/checkdurability [weapon_serial]
 
-- Issue weapon license
/issuelicense [player_id] [license_type]
⚠️

Test weapon mechanics thoroughly to ensure proper balance between realism and gameplay enjoyment.