> For the complete documentation index, see [llms.txt](https://brunx-mods.gitbook.io/brunx-mods-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://brunx-mods.gitbook.io/brunx-mods-docs/products/scripts/brunx-bridge/elevators.md).

# Elevators

The bridge has an elevator system built in. Players walk to a floor marker, press **E** and choose a floor in the elevator menu. Locked floors are shown with a lock, or hidden completely.

## How it works

1. A player presses **E** near a floor.
2. The server checks that the player is really near that elevator and builds the floor list with their job.
3. The player picks a floor. The server checks access again and starts a progress bar.
4. After the progress bar the server checks distance and access a third time, then teleports the player.

Floor locks never leave the server. A modified client cannot see which jobs open a floor, and cannot teleport from somewhere else on the map.

## General options

{% code title="shared/config.lua" %}

```lua
Config.Elevators = true       -- false disables the whole elevator system
Config.DrawDistance = 10.0    -- distance at which markers are drawn
Config.InteractDistance = 2.0 -- distance at which E opens the menu

Config.Marker = {
    enabled = true,
    type = 1,
    scale = vector3(1.0, 1.0, 0.5),
    color = { r = 0, g = 150, b = 255, a = 200 }
}

Config.ElevatorTextUI = {
    position = 'left-center',
    icon = 'elevator'
}

Config.ElevatorProgressDuration = 5000
Config.ElevatorProgressLabel = nil -- nil uses the translated text
```

{% endcode %}

## Adding elevators

There are two lists:

* `Config.GlobalElevators`: always active.
* `Config.MapElevators`: active only while the map resource (the key) is started. Stop the map and its elevators disappear.

{% code title="shared/config.lua" %}

```lua
Config.GlobalElevators = {
    {
        name = 'Apartments',
        showMarker = true,
        floors = {
            { label = 'Reception', coords = vector4(-478.42, -1040.02, 24.29, 0.0) },
            { label = 'Floor 1', coords = vector4(-491.85, -1048.67, 43.82, 0.0) },
            { label = 'Penthouse', coords = vector4(-491.76, -1048.89, 104.31, 357.17),
              jobLock = { jobs = { realestate = { minGrade = 3 } } } }
        }
    }
}

Config.MapElevators = {
    ['my_hospital_map'] = {
        {
            name = 'Hospital',
            showMarker = true,
            floors = {
                { label = 'Lobby', coords = vector4(298.6, -584.5, 43.3, 70.0) },
                { label = 'Roof', coords = vector4(338.5, -583.8, 74.2, 250.0),
                  jobLock = { jobs = { ambulance = true } } }
            }
        }
    }
}
```

{% endcode %}

{% hint style="info" %}
Use `vector4(x, y, z, heading)` with the coordinates from your coords command, standing where the player should appear. The marker is drawn 1 metre lower, on the floor.
{% endhint %}

### Elevator fields

| Field            | Type      | Description                                    |
| ---------------- | --------- | ---------------------------------------------- |
| `name`           | `string`  | Title of the elevator menu                     |
| `showMarker`     | `boolean` | Draw markers at the floors (default `true`)    |
| `floors`         | `table`   | List of floors, in menu order                  |
| `defaultJobLock` | `table?`  | Lock for every floor without its own `jobLock` |

### Floor fields

| Field     | Type      | Description                                                                                            |
| --------- | --------- | ------------------------------------------------------------------------------------------------------ |
| `label`   | `string`  | Name in the menu. Labels with a number show that number, labels with "parking" or "garage" show **P**. |
| `coords`  | `vector4` | Arrival position and heading                                                                           |
| `jobLock` | `table?`  | Who may go to this floor, see below                                                                    |

## Job locks

```lua
jobLock = {
    enabled = true,          -- optional, false switches the lock off
    hideIfNoAccess = false,  -- true hides the floor instead of showing it locked
    allowWithoutJob = false, -- true lets players without a job in
    jobs = {
        police = true,                              -- any grade
        sheriff = 2,                                -- grade 2 or higher
        ambulance = { minGrade = 3, dutyOnly = true },
        fib = { bossOnly = true }
    },
    jobTypes = {
        leo = true,          -- every job of type 'leo'
        ems = { minGrade = 2 }
    }
}
```

A player gets access when **either** their job **or** their job type matches. Job types come from Qbox and QBCore (`type` in the shared jobs), or from your own [`Config.CustomGetPlayerJob`](/brunx-mods-docs/products/scripts/brunx-bridge/configuration.md#custom-jobs).

| Rule value            | Meaning                                  |
| --------------------- | ---------------------------------------- |
| `true`                | Every grade                              |
| `3`                   | Grade 3 or higher                        |
| `{ minGrade = 3 }`    | Grade 3 or higher                        |
| `{ bossOnly = true }` | Boss grades only (`isboss` / ESX `boss`) |
| `{ dutyOnly = true }` | Only when on duty                        |

## Taking players along

When a player uses the elevator, the closest restrained player within range comes along. Useful for police and EMS bringing in suspects or patients.

{% code title="shared/config.lua" %}

```lua
Config.ElevatorCarryEnabled = true
Config.ElevatorCarryDistance = 3.0

-- true: only cuffed / escorted players come along.
-- false: the closest player always comes along.
Config.ElevatorCarryCuffedOnly = true

-- State bag keys (Player(src).state) that mark a player as restrained.
-- QBCore / Qbox handcuffs (metadata.ishandcuffed) are always checked.
Config.ElevatorCuffStateKeys = {
    'isCuffed', 'cuffed', 'handcuffed', 'isHandcuffed',
    'ziptied', 'isZiptied', 'restrained', 'isRestrained', 'isEscorted'
}
```

{% endcode %}

Using a police script that stores cuffs somewhere else? Decide yourself:

```lua
Config.ElevatorCanCarryPlayer = function(target)
    return exports.my_police:IsCuffed(target) -- true, false, or nil for the default check
end
```

{% hint style="warning" %}
Leave `Config.ElevatorCarryCuffedOnly` on `true` on public servers. With `false`, any player standing next to someone using the elevator is teleported along.
{% endhint %}

## Included maps

The config ships with elevators for these maps. They only activate when the map is started:

| Resource                   | Elevators                                         |
| -------------------------- | ------------------------------------------------- |
| `brnx_vinemedicalcenter`   | Vinewood Medical Center, with EMS / police floors |
| `brnx_sandyshoresservices` | Sandy medical center, helipad locked              |
| `brnx_generichotel`        | Hotel                                             |
| `brnx_courthouse`          | Courthouse (4 elevators)                          |
| `shmann_vpd_fivem`         | Vespucci police department                        |
| `Shmann_AirportV2`         | Airport                                           |
