# Installation guide

{% hint style="danger" %}
If you don't have any experience in development we are highly recommend to follow each step in this documentation, and if you have a developer ask them to install the script for you as they have more experience.
{% endhint %}

***

## Asset download&#x20;

{% hint style="success" %}
Once the purchase is made on our [<mark style="color:blue;">official website</mark>](https://store.brutalscripts.com), you will receive your asset directly in your [<mark style="color:blue;">Keymaster</mark>](https://keymaster.fivem.net), in the Granted Assets panel you will see the asset, download it and do the following steps to install it correctly.
{% endhint %}

* Put the script folder to your server.
* Start the script in the server.cfg. (ensure brutal\_gangs)
* Restart your server! (And you get permission to use the script)

{% hint style="info" %}
[<mark style="color:blue;">**Click here if you haven't installed any script ever**</mark>](https://www.youtube.com/watch?v=55RQrpLhs1w)
{% endhint %}

***

## Upload the SQL

{% hint style="warning" %}
Do not rename your previous SQL or columns to adapt them to this system, use the complete database without making use of edits in your old databases.
{% endhint %}

{% tabs %}
{% tab title="ESX" %}

```sql
CREATE TABLE IF NOT EXISTS `brutal_gangs` (
  `job` varchar(50) NOT NULL,
  `label` varchar(50) DEFAULT NULL,
  `level` int(11) DEFAULT 0,
  `datas` longtext DEFAULT NULL,
  `vehicles` longtext DEFAULT NULL,
  UNIQUE KEY `job` (`job`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;

ALTER TABLE `users`
ADD COLUMN IF NOT EXISTS `gang_rank` TEXT NULL DEFAULT NULL,
ADD COLUMN IF NOT EXISTS `last_gang` TEXT NULL DEFAULT NULL;

CREATE TABLE brutal_gangs_graffiti (
    id INT AUTO_INCREMENT PRIMARY KEY,
    gang VARCHAR(50),
    name VARCHAR(255),
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

CREATE TABLE `brutal_gangs_graffiti_settings` (
    `external_url` TINYINT(4) NULL DEFAULT NULL,
    `words` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8_general_ci'
)
COLLATE='utf8_general_ci'
ENGINE=Aria;

INSERT INTO `brutal_gangs_graffiti_settings` (`external_url`, `words`)
VALUES (1, '[]');

CREATE TABLE brutal_gangs_hqs (
    name VARCHAR(50) PRIMARY KEY,
    zone JSON,
    middle_point JSON,
    occupiable TINYINT,
    visibility TINYINT,
    default_coords JSON
) ENGINE=InnoDB;

CREATE TABLE brutal_gangs_zones (
    name VARCHAR(50) PRIMARY KEY,
    label LONGTEXT,
    type VARCHAR(50),
    zone LONGTEXT,
    cost INT DEFAULT 0,
    npc LONGTEXT,
    level INT,
    time_limit INT,
    reward LONGTEXT,
    last_raided INT,
    last_collected INT
) ENGINE=InnoDB;
```

{% endtab %}

{% tab title="QBCORE" %}

```sql
CREATE TABLE IF NOT EXISTS `brutal_gangs` (
  `job` varchar(50) NOT NULL,
  `label` varchar(50) DEFAULT NULL,
  `level` int(11) DEFAULT 0,
  `datas` longtext DEFAULT NULL,
  `vehicles` longtext DEFAULT NULL,
  UNIQUE KEY `job` (`job`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;

ALTER TABLE `players`
ADD COLUMN IF NOT EXISTS `gang_rank` TEXT NULL DEFAULT NULL,
ADD COLUMN IF NOT EXISTS `last_gang` TEXT NULL DEFAULT NULL;

CREATE TABLE brutal_gangs_graffiti (
    id INT AUTO_INCREMENT PRIMARY KEY,
    gang VARCHAR(50),
    name VARCHAR(255),
    created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

CREATE TABLE `brutal_gangs_graffiti_settings` (
    `external_url` TINYINT(4) NULL DEFAULT NULL,
    `words` LONGTEXT NULL DEFAULT NULL COLLATE 'utf8_general_ci'
)
COLLATE='utf8_general_ci'
ENGINE=Aria;

INSERT INTO `brutal_gangs_graffiti_settings` (`external_url`, `words`)
VALUES (1, '[]');

CREATE TABLE brutal_gangs_hqs (
    name VARCHAR(50) PRIMARY KEY,
    zone JSON,
    middle_point JSON,
    occupiable TINYINT,
    visibility TINYINT,
    default_coords JSON
) ENGINE=InnoDB;

CREATE TABLE brutal_gangs_zones (
    name VARCHAR(50) PRIMARY KEY,
    label LONGTEXT,
    type VARCHAR(50),
    zone LONGTEXT,
    cost INT DEFAULT 0,
    npc LONGTEXT,
    level INT,
    time_limit INT,
    reward LONGTEXT,
    last_raided INT,
    last_collected INT
) ENGINE=InnoDB;
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
[<mark style="color:blue;">**Click here if you don't know how to upload the sql, here is a quick guide**</mark>](https://www.youtube.com/watch?v=NXqmYn7bbMM) <mark style="color:blue;">**(phpMyAdmin)**</mark>
{% endhint %}

{% hint style="info" %}
[<mark style="color:blue;">**Click here if you don't know how to upload the sql, here is a quick guide**</mark>](https://www.youtube.com/watch?v=s3tqlHV3yb0) <mark style="color:blue;">**(HeidiSQL)**</mark>
{% endhint %}

{% embed url="<https://forum.cfx.re/t/how-to-how-to-import-an-sql-into-your-database/5168087/2>" %}

***

## Upload the items&#x20;

{% hint style="warning" %}
If you don't have the items integrated correctly, you will receive random errors.
{% endhint %}

{% hint style="danger" %}
Check that you don't have duplicate items in your inventory or database before integrating them, otherwise you might have some errors.
{% endhint %}

This asset depends on certain items for its operation, so don't forget to integrate all items correctly into your database or inventory system, depending on how you use your server.

If your inventory is not among the following, you can create the file yourself using the examples of each item by displaying any of the following tabs.

<details>

<summary>Items for esx_inventory</summary>

```sql
INSERT INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES
('spraycan', 'Spray Can', 1, 0, 1),
('sprayremover', 'Spray Remover', 1, 0, 1),
```

</details>

<details>

<summary>Items for qb-inventory</summary>

```lua
['spraycan'] 			 		 = {['name'] = 'spraycan', 						['label'] = 'Spray Can', 						['weight'] = 1, 		['type'] = 'item', 		['image'] = 'spraycan.png', 				['unique'] = false, 	['useable'] = false, 	['shouldClose'] = true,	   ['combinable'] = nil,   ['description'] = ''},
['sprayremover'] 			 			 = {['name'] = 'sprayremover', 							['label'] = 'Spray Remover', 						['weight'] = 1, 		['type'] = 'item', 		['image'] = 'sprayremover.png', 				['unique'] = false, 	['useable'] = false, 	['shouldClose'] = true,	   ['combinable'] = nil,   ['description'] = ''},
```

</details>

<details>

<summary>Items for qs-inventory</summary>

```lua
["spraycan"] = {
    ["name"] = "spraycan",
    ["label"] = "Spray Can",
    ["weight"] = 10,
    ["type"] = "item",
    ["image"] = "spraycan.png",
    ["unique"] = false,
    ["useable"] = false,
    ["shouldClose"] = true,
    ["combinable"] = nil,
    ["description"] = "Not have"
},

["sprayremover"] = {
    ["name"] = "sprayremover",
    ["label"] = "Spray Remover",
    ["weight"] = 10,
    ["type"] = "item",
    ["image"] = "sprayremover.png",
    ["unique"] = false,
    ["useable"] = false,
    ["shouldClose"] = true,
    ["combinable"] = nil,
    ["description"] = "Not have"
},
```

</details>

<details>

<summary>Items for ox-inventory</summary>

```lua
["spraycan"] = {
    label = "Spray Can",
    weight = 1,
    stack = true,
    close = false,
},

["sprayremover"] = {
    label = "Spray Remover",
    weight = 1,
    stack = true,
    close = false,
},
```

</details>

{% hint style="info" %}
[<mark style="color:blue;">**Click here if you don't know how to upload the sql, here is a quick guide**</mark>](https://www.youtube.com/watch?v=NXqmYn7bbMM)
{% endhint %}

***

## Asset positioning

{% hint style="danger" %}
Correctly position the assets in the server.cfg by following this step, if something goes wrong you will probably get errors about exports not found, do not skip this step!
{% endhint %}

```lua
-- First we will start the cores, never below
ensure es_extended or qb-core

-- The Notify / TextUI or target system / Progressbar / Inventory / Billing have to be above our asset
ensure [notify]
ensure [inventory]
ensure [billing]
ensure [textui] -- or target system 

-- Start the Brutal Gangs at the end
ensure brutal_gangs
```

***

## Setting up the Webhook&#x20;

If you want to use the opportunnities which can be given by a webhook then you will have to set it up in our assets. You can do it by changeing a value to your [<mark style="color:blue;">discord webhook</mark>](https://docs.brutalscripts.com/site/others/discord-webhook) in the sv-utils.lua file.

<figure><img src="https://4039149930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7v0UUR2mr3gc8OlYzKhO%2Fuploads%2FYD3dBIsrNLZ1Jvx3Sm8L%2FK%C3%A9perny%C5%91k%C3%A9p%202024-02-16%20213349.png?alt=media&#x26;token=fa6bcf52-a448-4a88-acfe-f12faacb75a3" alt=""><figcaption><p>sv-utils.lua</p></figcaption></figure>

{% content-ref url="../../others/discord-webhook" %}
[discord-webhook](https://docs.brutalscripts.com/site/others/discord-webhook)
{% endcontent-ref %}

***

## Setting the loaded event

{% hint style="danger" %}
If you are using a multicharacter system then this step is really important to make our script working propetly! If you don't use any or the loaded event is the same as the basic core one then you are done with this step.
{% endhint %}

In the client-core.lua file go to the LoadedEvent variable and if you are using a different event then paste there your event which is used on your server.

<figure><img src="https://4039149930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7v0UUR2mr3gc8OlYzKhO%2Fuploads%2FiZsIrf5OSm3hfTPFbEiS%2FK%C3%A9perny%C5%91k%C3%A9p%202024-03-03%20210541.png?alt=media&#x26;token=c320d17a-ed65-4f76-8933-67914ef7b8c9" alt=""><figcaption><p>client-core.lua</p></figcaption></figure>

***

## Checking the Config file

Please make sure that you go through the whole file during the installation and check everything. It is one of the most important things as if you miss this step the script might won't work propetly.

***

## Polyzone

Download this version from the polyzone in order to make the script work.

{% file src="<https://4039149930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7v0UUR2mr3gc8OlYzKhO%2Fuploads%2Fm5FBV022utazcmf9mCqe%2FPolyZone.zip?alt=media&token=a9760cb2-e2d6-4364-bb15-5a0fee8e3425>" %}

### Most important steps

The most important things always at the top of the config so pay the most attencion to these elements.

<details>

<summary>Setting the Core</summary>

Set your server's core wether it's using es\_extended or qb-core, other cores aren't supported .

</details>

<details>

<summary>Setting the Notify</summary>

If you are using the [<mark style="color:blue;">Brutal Notify</mark>](https://docs.brutalscripts.com/site/scripts/notify) then it is good news, you don't have to do anything.\
If you aren't then set the BrutalNotify value to false in the config and set up your own notify in the cl-utils.lua

</details>

<details>

<summary>Setting the TextUI or Target</summary>

Set the TextUI from the options which are commented out. If your server using an other TextUI  it is not a problem, you can set it up in the cl-utils.lua. If you want to use a target system then set the TextUI to false and set your target.

</details>

***

### Lockpicking Minigame

Download this script to use the lockpicking minigame in the gang tasks.

{% file src="<https://4039149930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7v0UUR2mr3gc8OlYzKhO%2Fuploads%2FMYfOUqBG7ZkOAKSULSSB%2Flockpick.zip?alt=media&token=a6ae85c2-fcc9-4a10-8f3d-25d31218dd52>" %}

***

## Setting up the core

{% hint style="warning" %}
To use this script you will have to make some changes in your core. These steps have to be done to make our asset work 100%.
{% endhint %}

{% tabs %}
{% tab title="ESX" %}

## You have to use minimum the es\_extended <mark style="color:red;">v1.7.5</mark>&#x20;

**If you have an older version you will have to create the gangs in the sql and you wont be able to create gangs in-game as there are missing functions for that in your core!**

***

### If you are using second job&#x20;

Go to the core/server-core.lua file and set the Config.EsxSecondJob to true. If you are experiencing any problems open a ticket on our discord server!
{% endtab %}

{% tab title="QBCORE" %}

* Navigate to **qb-core/server/commands.lua** and replace this command as you can see it on the image:

<figure><img src="https://4039149930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7v0UUR2mr3gc8OlYzKhO%2Fuploads%2Fz6tZ1OznOSEJfMl2Ks3r%2Fimage.png?alt=media&#x26;token=24b3982c-6590-4c50-b698-6875e24cd92f" alt=""><figcaption><p>qb-core/server/commands.lua</p></figcaption></figure>

```lua
QBCore.Commands.Add('setgang', Lang:t('command.setgang.help'), { { name = Lang:t('command.setgang.params.id.name'), help = Lang:t('command.setgang.params.id.help') }, { name = Lang:t('command.setgang.params.gang.name'), help = Lang:t('command.setgang.params.gang.help') }, { name = Lang:t('command.setgang.params.grade.name'), help = Lang:t('command.setgang.params.grade.help') } }, true, function(source, args)
    local Player = QBCore.Functions.GetPlayer(tonumber(args[1]))
    if Player then
        local newGang = {name = tostring(args[2]):lower()}
        local lastGang = json.encode(Player.PlayerData.gang)

        gang = tostring(args[2]):lower()
        grade = tostring(tonumber(args[3])) or '0'
        if not QBCore.Shared.Gangs[gang] then return false end
        Player.PlayerData.gang.name = gang
        Player.PlayerData.gang.label = QBCore.Shared.Gangs[gang].label
        if QBCore.Shared.Gangs[gang].grades[grade] then
            local ganggrade = QBCore.Shared.Gangs[gang].grades[grade]
            Player.PlayerData.gang.grade = {}
            Player.PlayerData.gang.grade.name = ganggrade.name
            Player.PlayerData.gang.grade.level = tonumber(grade)
            Player.PlayerData.gang.isboss = ganggrade.isboss or false
        else
            Player.PlayerData.gang.grade = {}
            Player.PlayerData.gang.grade.name = 'No Grades'
            Player.PlayerData.gang.grade.level = 0
            Player.PlayerData.gang.isboss = false
        end

        if not Player.Offline then
            Player.Functions.UpdatePlayerData()
            TriggerEvent('QBCore:Server:OnGangUpdate', Player.PlayerData.source, Player.PlayerData.gang)
            TriggerClientEvent('QBCore:Client:OnGangUpdate', Player.PlayerData.source, Player.PlayerData.gang)
            TriggerEvent('brutal_gangs:server:qbcore-gang-update', Player.PlayerData.source, newGang, json.decode(lastGang))
        end
    else
        TriggerClientEvent('QBCore:Notify', source, Lang:t('error.not_online'), 'error')
    end
end, 'admin')
```

Navigate to **qb-core/shared/gangs.lua** and replace this file to this:

```lua
QBShared = QBShared or {}
QBShared.Gangs = {
    none = { label = 'No Gang', grades = { ['0'] = { name = 'Unaffiliated' } } },
}
```

{% endtab %}

{% tab title="QBOX" %}

* Navigate to **qbx\_core/server/commands.lua** and replace this command as you can see it on the image:<br>

  <figure><img src="https://4039149930-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F7v0UUR2mr3gc8OlYzKhO%2Fuploads%2FW5fTwzCGHIDCToPwglZC%2Fimage.png?alt=media&#x26;token=6868ed57-7212-4be4-9263-b76e2bb1798b" alt=""><figcaption><p><strong>qbx_core/server/commands.lua</strong></p></figcaption></figure>

```lua
lib.addCommand('setgang', {
    help = locale('command.setgang.help'),
    params = {
        { name = locale('command.setgang.params.id.name'), help = locale('command.setgang.params.id.help'), type = 'playerId' },
        { name = locale('command.setgang.params.gang.name'), help = locale('command.setgang.params.gang.help'), type = 'string' },
        { name = locale('command.setgang.params.grade.name'), help = locale('command.setgang.params.grade.help'), type = 'number', optional = true }
    },
    restricted = 'group.admin'
}, function(source, args)
    local player = GetPlayer(args[locale('command.setgang.params.id.name')])
    if not player then
        Notify(source, locale('error.not_online'), 'error')
        return
    end

    local newGang = {name = args[locale('command.setgang.params.gang.name')]}
    local lastGang = json.encode(player.PlayerData.gang)

    local success, errorResult = player.Functions.SetGang(args[locale('command.setgang.params.gang.name')], args[locale('command.setgang.params.grade.name')] or 0)
    TriggerEvent('brutal_gangs:server:qbcore-gang-update', player.PlayerData.source, newGang, json.decode(lastGang))
    assert(success, json.encode(errorResult))
end)
```

* Navigate to **qbx\_core/shared/gangs.lua** and replace this file to this:

{% hint style="danger" %}
Before you do this step make sure that none of the players are in any gang in the sql&#x20;
{% endhint %}

```
return {
    ['none'] = {
        label = 'No Gang',
        grades = {
            [0] = {
                name = 'Unaffiliated'
            },
        },
    },
}
```

{% endtab %}
{% endtabs %}

***

{% hint style="danger" %}

## Remove the basic gang scripts from your server

If you have any other gang creation scripts or anything similar, you don't need them anymore.
{% endhint %}

## If you got any error

If you followed the installation guide and the script still don't work or you get any errors the please check the common errors, here in the docs and in our [<mark style="color:blue;">discord</mark> ](https://discord.gg/85u2u5c8q9)server, for more informations.
