> For the complete documentation index, see [llms.txt](https://buty-documentation.gitbook.io/home/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://buty-documentation.gitbook.io/home/guides/advanced-airplane/installation.md).

# INSTALLATION

Read very well and follow all the steps below. If you find any error or have any doubt open a ticket.

## 1. **DOWNLOAD**

The first step is to download the product we have just purchased. To do this we will go to our [KEYMASTER](https://keymaster.fivem.net/asset-grants) account and search for **"Buty-Airplane"**.

## 2. DEPENDENCIES AND INSTALLATION

To install it add the resource to your **scripts folder** and put the following in your **SERVER.CFG**:

```lua
ensure Buty-Airplane
```

**You will also need to install the SQL in your database before starting the script, in order to save the experience of each player.**

![](https://3526868747-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FeQWzokUSwvmD8VZ4PFkY%2Fuploads%2FjoDyAOIA3erWG4lNvLQe%2Fimage.png?alt=media\&token=3ae7cbaa-8345-4abf-93f4-7161f6222b6a)

## 3. CONFIG

#### The following will explain all the settings, one of the most important things that I recommend you spend a few minutes to understand in order to offer your users the best possible experience.

{% hint style="info" %}
To make it easier for you to configure, this script comes with several configuration files, each one for one thing. You can see it explained below:
{% endhint %}

{% tabs %}
{% tab title="CONFIG" %}
{% hint style="info" %}
Here you will only have to configure your **framework**, your **database** and some extra settings.

In **UseKeys, UseFuel, UseDeleteVehicle** you activate it in case you have filled some of the integrations in **functions.**
{% endhint %}

{% code lineNumbers="true" %}

```lua
Config = {}

Config.framework = "esx"   -- esx or qbcore

Config.ESX = 'es_extended'

Config.QB = 'qb-core'

Config.Mysql = "oxmysql" -- oxmysql, mysql-async or ghmattisql


Config.NeedWhitelist = false  -- Use "true" if you want only the players you add to be able to work.
Config.Identifier = 'license' -- license, steam, discord
Config.Players = {
    -- 'license:3132321ede12ed123213211e12332213hg21i3g1',
    -- 'license:3132321ede12ed123213211e12332213hg21i3g1',
    -- 'license:3132321ede12ed123213211e12332213hg21i3g1',
    -- 'license:3132321ede12ed123213211e12332213hg21i3g1',
}

Config.job = {
    needjob = false,
    jobname = 'pilot'
}

Config.BattlePass = {
    Active = false,
    xplegal = 1000,
    xpillegal = 1000
}

Config.Target = {UseTarget = false, TargetExport = 'qb-target', Coords = vector3(-941.4, -2954.64,13.96), Text = 'START JOB', Icon = 'fa fa-plane'}

Config.UseFuel = false

Config.UseKeys = false

Config.UseDeleteVehicle = false

Config.NPCHOME = {{x = -941.4, y = -2954.64, z = 13.96, h = 149.68}}

Config.NPCS = {
    ['home'] = {
        model = 'cs_floyd', --npc model (https://docs.fivem.net/docs/game-references/ped-models/)
        anim = 'WORLD_HUMAN_CLIPBOARD' --npc animation (https://wiki.rage.mp/index.php?title=Scenarios)
    }

}

Config.Transport = {
    ['legal'] = {
        createtruck = vector3(-1030.88, -3033.92, 13.96),
        gocoords = vector3(-971.08, -2998.16, 13.96),
        gocoordsnpc = vector3(-956.08, -2919.76, 13.96),
        vehicle = 'mammatus',
        requiredmoney = true,   -- requires money to be able to work.
        requiredmoneytype = 'cash',   -- cash, bank, black_money and item.
        requiredmoneyquantity = 2000,
        requiredmoneyquantityitem = 'crypto'  -- this is if you use " requiredmoneytype = 'item' ".
    },

    ['ilegal'] = {
        createtruck = vector3(-1030.88, -3033.92, 13.96),
        gocoords = vector3(-971.08, -2998.16, 13.96),
        gocoordsnpc = vector3(-956.08, -2919.76, 13.96),
        Probabilityenemies = 10,
        Probabilitycallpolice = 10,
        enemiesvehicle = 'sanchez',
        enemiesweapon = 'WEAPON_PISTOL',
        vehicle = 'mammatus',
        typemoney = 'crypto',  -- only use QB
        requiredmoney = true,   -- requires money to be able to work.
        requiredmoneytype = 'cash',
        requiredmoneyquantity = 2000,
        requiredmoneyquantityitem = 'crypto'
    }

}

Config.RoboCargamento = {
    ['Peds'] = {
        [1]={x = 2174.52, y = 4793.88, z = 41.2,h = 34.72, ped},
        [2]={x = 2170.72, y = 4787.12, z = 41.2, h = 34.72, ped},
        [3]={x = 2171.4, y = 4782.16, z = 41.16, h = 34.72,  ped}, 
    }         
}

Config.locationstransportlegal = {
    [1] = {x = -1275.84, y = -3386.8, z = 13.96},
    [2] = {x = -1654.68, y = -3148.44, z = 14.0},
    [3] = {x = -1238.72, y = -2297.44, z = 13.96},
    [4] = {x = -1266.6, y = -2599.0, z = 14.96}
}

Config.locationstransportilegal = {
    [1] = {x = -1275.84, y = -3386.8, z = 13.96},
    [2] = {x = -1654.68, y = -3148.44, z = 14.0},
    [3] = {x = -1238.72, y = -2297.44, z = 13.96},
    [4] = {x = -1266.6, y = -2599.0, z = 14.96}
}

Config.LegalPackagePoints = {

    totalpackage = 6,      -- if you add more packages, add the number of packages there are in total to pick up

    {x = 1739.56, y = 3321.52, z = 40.24},
    {x = 1739.96, y = 3319.56, z = 40.24},
    {x = 1740.6, y = 3316.8, z = 40.24},
    {x = 1741.24, y = 3314.28, z = 40.24},
    {x = 1719.88, y = 3310.96, z = 40.24},
    {x = 1720.32, y = 3308.68, z = 40.24}

}

Config.IlegalWeaponsPoints = {

    totalweapon = 6,       -- if you add more weapons, add the total number of weapons to collect

    {x = 2146.12, y = 4779.48, z = 39.96},
    {x = 2144.52, y = 4778.84, z = 39.96},
    {x = 2144.92, y = 4777.28, z = 39.96},
    {x = 2145.6, y = 4775.56, z = 40.0},
    {x = 2128.68, y = 4769.36, z = 39.96},
    {x = 2127.92, y = 4770.8, z = 39.96}

}


Config.Level = {
    ['legal'] = {
        [1] = {
            money = 100,        -- money that it will give you if you are at level 1
            exp = 10,           -- exp that it will give you if you are at level 1
            exprequired = 1000  -- exp required to level up (legal and ilegal)
        },
        [2] = {
            money = 200,
            exp = 20, 
            exprequired = 2000
        },
        [3] = {
            money = 300,
            exp = 30, 
            exprequired = 3000
        },
        [4] = {
            money = 400,
            exp = 40, 
            exprequired = 4000
        },
        [5] = {
            money = 500,
            exp = 50, 
            exprequired = 5000
        },
        [6] = {
            money = 600,
            exp = 60, 
            exprequired = 6000
        },
        [7] = {
            money = 700,
            exp = 70, 
            exprequired = 7000
        },
        [8] = {
            money = 800,
            exp = 80, 
            exprequired = 8000
        },
        [9] = {
            money = 900,
            exp = 90, 
            exprequired = 9000
        },
        [10] = {
            money = 1000,
            exp = 100, 
            exprequired = 100000 -- do not touch
        }
    },

    ['ilegal'] = {
        paywithitem = false,   -- will pay you with an item if it is set to "true".
        item = 'black_money',  -- item name.

        [1] = {
            money = 100,
            exp = 10, 
        },
        [2] = {
            money = 2000,
            exp = 20, 
        },
        [3] = {
            money = 3000,
            exp = 30, 
        },
        [4] = {
            money = 4000,
            exp = 40, 
        },
        [5] = {
            money = 5100,
            exp = 50, 
        },
        [6] = {
            money = 6100,
            exp = 60, 
        },
        [7] = {
            money = 7100,
            exp = 70, 
        },
        [8] = {
            money = 8100,
            exp = 80, 
        },
        [9] = {
            money = 9100,
            exp = 90, 
        },
        [10] = {
            money = 1100,
            exp = 100, 
        },
    }

}

Config.Translations = {

    ['language'] = "EN", --You can choose which language the notifications will be in. (EN, ES, FR)

    ['EN'] = {
        [1] = "Press ~b~E~w~ to open",
        [3] = "~r~[E]~s~ - pick up the package",
        [4] = "This was the last box, load it and go to the new location to unload",
        [5] = "~g~[E]~s~ - Open doors.",
        [6] = "~g~[E]~s~ - Close Doors | ~g~[G]~s~ - Put Package",
        [7] = "Packets: ~g~",
        [8] = "/6 ~s~",
        [9] = "You already have a job to do.",
        [10] = "You've been caught and the police have been called.",
        [11] = "They are making illegal charges, we have marked on your gps the area where you were last seen.",
        [12] = "~r~[E]~s~ - pick up the weapons.",
        [13] = "These were the last weapons, load them and go to the new location to unload them",
        [14] = "Weapons: ~g~.",
        [15] = "/6 ~s~",
        [16] = "A worker is on his way with the plane, wait for him to arrive.",
        [17] = "Now you have to go and pick up the goods, we have marked it on the gps.",
        [18] = "The gun owners have found out and they are after you, kill them.",
        [19] = "For this you have to have a job as an airplane driver.",
        [20] = "~r~[E]~s~ - deliver cargo",
        [21] = "You don't have enough money.",
        [22] = "You do not have permission to work here.",
    },

    ['ES'] = {
        [1] = "Pulsa ~b~E~w~ para abrir",
        [3] = "~r~[E]~s~ - recoger el paquete",
        [4] = "Esta era la última caja, cárgala y ve a la nueva ubicación para descargarla",
        [5] = "~g~[E]~s~ - Abrir puertas",
        [6] = "~g~[E]~s~ - Cerrar Puertas | ~g~[G]~s~ - Poner paquete",
        [7] = "Paquetes: ~g~",
        [8] = "/6 ~s~",
        [9] = "Ya tienes un trabajo que hacer",
        [10] = "Te han pillado y han llamado a la policía",
        [11] = "Están haciendo cargas ilegales, hemos marcado en su gps la zona donde fue visto por última vez",
        [12] = "~r~[E]~s~ - recoger las armas",
        [13] = "Estas fueron las últimas armas, cárgalas y ve a la nueva ubicación para descargarlas",
        [14] = "Armas: ~g~",
        [15] = "/6 ~s~",
        [16] = "Un trabajador está en camino con el avion, espere a que llegue.",
        [17] = "Ahora tienes que ir a recoger la mercancía, la hemos marcado en el gps.",
        [18] = "Los propietarios de armas se han enterado y van a por ti, mátalos.",
        [19] = "Para esto hay que tener un trabajo de conductor de avión.",
        [20] = "~r~[E]~s~ - entregar carga",
        [21] = "No tienes suficiente dinero.",
        [22] = "No puedes trabajar aqui",
    },

    ['FR'] = {        
        [1] = "Appuyez sur ~b~E~w~ pour ouvrir",
        [3] = "~r~[E]~s~ - ramasser le paquet",
        [4] = "C'était la dernière boîte, chargez-la et allez au nouvel emplacement pour la décharger",
        [5] = "~g~[E]~s~ - Ouvrir les portes.",
        [6] = "~g~[E]~s~ - Close Doors | ~g~[G]~s~ - Put Package",
        [7] = "Paquets : ~g~",
        [8] = "/6 ~s~",
        [9] = "Vous avez déjà un travail à faire",
        [10] = "Vous avez été pris et la police a été appelée.",
        [11] = "Ils font des accusations illégales, nous avons marqué sur votre GPS la zone où vous avez été vu pour la dernière fois",
        [12] = "~r~[E]~s~ - ramasse les armes.",
        [13] = "Ce sont les dernières armes, chargez-les et allez au nouvel emplacement pour les décharger",
        [14] = "Armes : ~g~.",
        [15] = "/6 ~s~",
        [16] = "Un ouvrier est en route avec l'avion, attendez qu'il arrive",
        [17] = "Maintenant vous devez aller chercher les marchandises, nous l'avons marqué sur le gps",
        [18] = "Les propriétaires d'armes l'ont découvert et sont après vous, tuez-les.",
        [19] = "Pour cela, vous devez avoir un emploi de chauffeur de ligne.",
        [20] = "~r~[E]~s~ - livrer les marchandises",
        [21] = "Vous n'avez pas assez d'argent",
        [22] = "Vous ne pouvez pas travailler ici",
    },


}
```

{% endcode %}
{% endtab %}

{% tab title="FUNCTION" %}
{% hint style="info" %}
Here are the important functions open. You will be able to set your **Key System**, **Fuel System**, **Blips**...
{% endhint %}

:thumbsup:You will have to know the **EXPORT** of your system (e.g. from your fuel script) and add it, **replacing the existing one**.

*For example if you don't use LegacyFuel and you use BitFuel, then replace `exports["LegacyFuel"]:SetFuel(fuelvehicle, 100)` with your BitFuel export.*

{% code lineNumbers="true" %}

```lua
if Config.UseFuel == true then
    function fuel()
        exports["LegacyFuel"]:SetFuel(vehicle, 100)
    end
    function fuel2()
        exports["LegacyFuel"]:SetFuel(vehicle2, 100)
    end
end

if Config.UseDeleteVehicle then
    function delete(vehicle)
        exports["AdvancedParking"]:DeleteVehicle(vehicle)
    end
    function delete2(vehicle2)
        exports["AdvancedParking"]:DeleteVehicle(vehicle2)
    end
end

if Config.BattlePass.Active then
    
    function battlepass()
        TriggerEvent("BattlePass-Server:AddXP",Config.BattlePass.xplegal ,"Airplane")
    end

    function battlepass2()
        TriggerEvent("BattlePass-Server:AddXP",Config.BattlePass.xpillegal ,"Airplane")
    end
end

if Config.UseKeys == true then
    function keys()
        TriggerEvent('cd_garage:AddKeys', exports['cd_garage']:GetPlate(vehicle))
    end

    function keys2()
        TriggerEvent('cd_garage:AddKeys', exports['cd_garage']:GetPlate(vehicle2))
    end

end


function hintToDisplay(text,coords)
	local dist = Vdist(coords.x,coords.y,coords.z,GetEntityCoords(PlayerPedId(-1)))
    if dist < 1.5 then
        DrawText3Ds(coords.x,coords.y,coords.z + 1.05,text, 0, 0.1, 0.1,255)
    else
        DrawText3Ds(coords.x,coords.y,coords.z + 1.05,text, 0, 0.1, 0.1,100)
    end
end

function DrawText3Ds(x, y, z, text)
	SetTextScale(0.35, 0.35)
    SetTextFont(4)
    SetTextProportional(1)
    SetTextColour(255, 255, 255, 215)
    SetTextEntry("STRING")
    SetTextCentre(true)
    AddTextComponentString(text)
    SetDrawOrigin(x,y,z, 0)
    DrawText(0.0, 0.0)
    ClearDrawOrigin()

end

-- Client notifications
function SendClientNotification(type, text, time)
    -- time = 10000
    -- if type == 'success' then
    --     exports["Venice-Notification"]:Notify(text, time, "check", options)
    -- elseif type == 'error' then
    --     exports["Venice-Notification"]:Notify(text, time, "error", options)
    -- elseif type == 'info' then
    --     exports["Venice-Notification"]:Notify(text, time, "info", options)
    -- end
    if Config.framework == 'esx' then

     ESX.ShowNotification(text)

    elseif Config.framework == 'qbcore' then

     QBCore.Functions.Notify(text)

    end
end

-- Server side notifications
function SendServerNotification(source, type, text, time)
    -- time = 10000
    -- if type == 'success' then
    --     TriggerClientEvent('codem-notification', source, text, time, 'check', options)
    -- elseif type == 'error' then
    --     TriggerClientEvent('codem-notification', source, text, time, 'error', options)
    -- elseif type == 'info' then
    --     TriggerClientEvent('codem-notification', source, text, time, 'info', options)
    -- end

    if Config.framework == 'esx' then

        TriggerClientEvent('esx:showNotification', source, text)

    elseif Config.framework == 'qbcore' then

        TriggerClientEvent('QBCore:Notify', source, text)

    end
end

--Blip Police
RegisterNetEvent("BCallpilot:polblip")
AddEventHandler("BCallpilot:polblip", function(ubi)

    blip = AddBlipForRadius(ubi.x, ubi.y, ubi.z , 50.0)
	SetBlipHighDetail(blip, true)
	SetBlipColour(blip, 1)
	SetBlipAlpha (blip, 128)
    
    Citizen.Wait(25000)

    RemoveBlip(blip)

end)

function home()
    local coords = Config.NPCHOME
    for k in pairs(coords) do
        bliphome = AddBlipForCoord(coords[k].x, coords[k].y, coords[k].z)
        SetBlipSprite(bliphome, 582)
        SetBlipColour(bliphome, 24)
        SetBlipScale(bliphome, 0.8)
        SetBlipAsShortRange(bliphome, true)
        BeginTextCommandSetBlipName("STRING")
        AddTextComponentSubstringPlayerName('Airplane Job')
        EndTextCommandSetBlipName(bliphome)
    end
end

function blip1()
    SetNewWaypoint(Point2.x, Point2.y, Point2.z)
    blipdescargar = AddBlipForCoord(Point2.x, Point2.y, Point2.z)
    SetBlipSprite(blipdescargar, 478)
    SetBlipColour(blipdescargar, 24)
    SetBlipScale(blipdescargar, 0.4)
    SetBlipAsShortRange(blipdescargar, true)
    BeginTextCommandSetBlipName("STRING")
    AddTextComponentSubstringPlayerName('transport')
    EndTextCommandSetBlipName(blipdescargar)
end


function blip2()
    SetNewWaypoint(Point2.x, Point2.y, Point2.z)
    blipdescargar = AddBlipForCoord(Point2.x, Point2.y, Point2.z)
    SetBlipSprite(blipdescargar, 478    )
    SetBlipColour(blipdescargar, 24)
    SetBlipScale(blipdescargar, 0.4)
    SetBlipAsShortRange(blipdescargar, true)
    BeginTextCommandSetBlipName("STRING")
    AddTextComponentSubstringPlayerName('transport')
    EndTextCommandSetBlipName(blipdescargar)
end

function creapackage()
    SetNewWaypoint(1735.04, 3296.32, 41.24)
    for i, v in ipairs(Config.LegalPackagePoints) do
        v.package2 = CreateObject(GetHashKey('prop_cs_cardbox_01'), v.x, v.y, v.z)
        FreezeEntityPosition(v.package2, true)
        v.blip = AddBlipForCoord(v.x, v.y, v.z)
        SetBlipSprite(v.blip, 1)
        SetBlipColour(v.blip, 24)
        SetBlipScale(v.blip, 0.4)
        SetBlipAsShortRange(v.blip, true)
        BeginTextCommandSetBlipName("STRING")
        AddTextComponentSubstringPlayerName('package')
        EndTextCommandSetBlipName(v.blip)
    end
end

function creapackage2()
    SetNewWaypoint(2130.84, 4787.68, 40.96)
    for i, v in ipairs(Config.IlegalWeaponsPoints) do
        v.package2 = CreateObject(GetHashKey('ex_office_swag_guns03'), v.x, v.y, v.z)
        FreezeEntityPosition(v.package2, true)
        v.blip = AddBlipForCoord(v.x, v.y, v.z)
        SetBlipSprite(v.blip, 1)
        SetBlipColour(v.blip, 24)
        SetBlipScale(v.blip, 0.4)
        SetBlipAsShortRange(v.blip, true)
        BeginTextCommandSetBlipName("STRING")
        AddTextComponentSubstringPlayerName('weapon')
        EndTextCommandSetBlipName(v.blip)
    end
end
```

{% endcode %}
{% endtab %}

{% tab title="POLICEALERT" %}
{% hint style="info" %}
Here you can configure if you want to use a **DISPATCH** or **police alert system** different from the one included in the script.

**You will have to find the documentation of the DISPATCH or SCRIPT you use and replace it here.**
{% endhint %}

```lua
RegisterServerEvent("BCallpilot:policecall")
AddEventHandler("BCallpilot:policecall", function()
    if Config.framework == 'esx' then

        local xPlayer  = ESX.GetPlayerFromId(source)
        local xPlayers = ESX.GetPlayers()
        local ubi = xPlayer.getCoords()
    
        for i=1, #xPlayers, 1 do
            local xPlayer = ESX.GetPlayerFromId(xPlayers[i])
            if xPlayer.job.name == 'police' then
                SendServerNotification(xPlayers[i], "info", Config.Translations[Config.Translations['language']][11], time)
                TriggerClientEvent('BCallpilot:polblip', xPlayers[i], ubi)
            end
        end

    elseif Config.framework == 'qbcore' then

        local src = source
        local get = GetPlayerPed(src)
        local coords = GetEntityCoords(get)
        local Player = QBCore.Functions.GetPlayer(src)
        local xPlayers = QBCore.Functions.GetPlayers()
        local ubi = GetEntityCoords(get, coords)
    
        for i=1, #xPlayers, 1 do
            local xPlayer = QBCore.Functions.GetPlayers(xPlayers[i])
            if Player.PlayerData.job.name == 'police' then
                SendServerNotification(xPlayers[i], "info", Config.Translations[Config.Translations['language']][11], time)
                TriggerClientEvent('BCallpilot:polblip', xPlayers[i], ubi)
            end
        end

    end

end)
```

{% endtab %}
{% endtabs %}
