> For the complete documentation index, see [llms.txt](https://dragon-heart-studios.gitbook.io/dragonheartstudios/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dragon-heart-studios.gitbook.io/dragonheartstudios/scripts/dhs-bankingsim/door-locking.md).

# Door Locking

## Door Locking & Bank Schedule

When a branch is closed — either outside business hours or manually toggled closed by the owner — the front doors can lock so players can only use ATMs. Doors unlock automatically when the branch opens. Clocked-in employees can always walk in during closed hours, and employees get a **"Toggle Front Doors"** target option on the door itself for the "lock up on your way out" flow.

***

### Do I Need a Doorlock Resource?

**No.** DHS-BankingSim ships with a built-in door locker that works out of the box. You do **not** need to install `ox_doorlock`, `qb-doorlock`, or anything else. If you already have one of those installed and prefer to keep all your doors managed in one place, you can hook into it instead.

***

### Choosing a Mode

Set `Config.Doorlock.Mode` in `config/config.lua`:

| Mode       | When to Use                                                                                 |
| ---------- | ------------------------------------------------------------------------------------------- |
| `'native'` | Default. Resource manages doors directly. Recommended for most servers.                     |
| `'bridge'` | You already run `ox_doorlock`, `qb-doorlock`, or `rcore_doorlock` and want DHS to use them. |
| `'custom'` | Your doorlock system isn't listed above, or you use a custom MLO door system.               |

***

### Option 1 — Built-In (native)

```lua
Config.Doorlock.Mode = 'native'
```

Fill in a `doors` list for each branch in `Config.Banks`. Each entry needs:

| Field     | What It Is                 | How to Find It                                                                                                                                                                                                        |
| --------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `model`   | The door's prop model hash | Wrap the model name in **backticks** (e.g. `` `v_ilev_fb_door2` ``) — Lua converts the name to its hash at load time. Use a dev menu (vMenu, qb-adminmenu) to aim at the door and read the model under the crosshair. |
| `coords`  | The door's world position  | Stand next to the door and copy coordinates from the dev menu, or use a `/pos` command. Within \~1m of the door is fine.                                                                                              |
| `heading` | Which way the door faces   | Same dev menu "heading" field. Used to orient the interaction.                                                                                                                                                        |

```lua
-- Inside each branch entry in Config.Banks:
doors = {
    { model = `v_ilev_fb_door2`, coords = vector3(149.50, -1042.18, 29.37), heading = 340.0 },
    { model = `v_ilev_fb_door3`, coords = vector3(149.10, -1042.50, 29.37), heading = 340.0 },
},
```

> **Important:** wrap the model name in backticks (`` ` ``), not quotes. Backticks tell Lua to convert the string to its hash at load time.

If a branch uses a custom MLO and you can't determine the door coordinates, leave `doors = {}` empty for that branch. The schedule system (teller ped hide, NPC gating, etc.) still works — that branch just won't have lockable doors.

***

### Option 2 — Existing Doorlock Resource (bridge)

```lua
Config.Doorlock.Mode = 'bridge'
```

DHS-BankingSim will tell your existing doorlock resource to lock/unlock the doors on schedule. You must first create the bank doors inside your doorlock resource, then paste their IDs into `externalDoorIds` per branch.

```lua
-- Inside each branch entry in Config.Banks:
doors = {},                        -- not used in bridge mode
externalDoorIds = { 12, 13 },      -- IDs from your doorlock resource
```

#### ox\_doorlock

ox\_doorlock assigns integer IDs to each door. Get the ID via the in-game door creator (`/doorlock` as admin) or by running `SELECT id, name FROM ox_doorlock;` in your database.

```lua
externalDoorIds = { 12, 13 },
```

#### qb-doorlock

qb-doorlock uses string names you define in its `config.lua`. Use the same key you chose:

```lua
-- qb-doorlock/config.lua:
--   Config.DoorList['fleeca_downtown_front'] = { objName = `v_ilev_fb_door2`, ... }

externalDoorIds = { 'fleeca_downtown_front', 'fleeca_downtown_side' },
```

#### rcore\_doorlock

rcore uses the `name` field you set when creating the door in rcore's editor:

```lua
externalDoorIds = { 'bank_downtown_front' },
```

> **Note:** In bridge mode, the "Toggle Front Doors" employee target option is **not** shown on the door — your existing doorlock resource owns the door UI. The automatic open/closed-hours locking still functions.

***

### Option 3 — Custom Doorlock (custom)

```lua
Config.Doorlock.Mode = 'custom'
```

If your doorlock system isn't supported above, implement it by editing two files that are not locked (you can edit them freely):

* `client/editable_functions_cl.lua`
* `server/editable_functions_sv.lua`

Both files contain empty hook functions. The resource calls them whenever a branch's doors should lock or unlock — fill in the body to call your own exports/events/MLO functions.

#### Client-Side Hooks (`client/editable_functions_cl.lua`)

```lua
-- Called when a branch's doors should lock or unlock.
-- bankId: numeric branch ID
-- locked: boolean (true = lock, false = unlock)
-- doors:  the branch's doors array from config (may be empty)
function EditableFunctions.CustomDoorlockApplyState(bankId, locked, doors)
    -- Example:
    -- for _, door in ipairs(doors or {}) do
    --     exports['my_doorlock']:SetDoorState(door.id, locked)
    -- end
end

-- Called once per branch on resource start to register doors.
function EditableFunctions.CustomDoorlockRegisterBranch(bankId, doors)
    -- Example:
    -- for _, door in ipairs(doors or {}) do
    --     exports['my_doorlock']:RegisterDoor(door)
    -- end
end

-- Called on resource stop to clean up any registered doors.
function EditableFunctions.CustomDoorlockCleanup()
    -- Example:
    -- exports['my_doorlock']:RemoveAllDHSDoors()
end
```

***

### Bank Schedule Configuration

Business hours and the schedule behaviour are set in `Config.BankSchedule`:

```lua
Config.BankSchedule = {
    Enabled              = true,   -- Master switch (false = doors never auto-lock)
    TimeSource           = 'game', -- 'game' = in-game clock, 'real' = real-world time
    DefaultOpen          = '08:00',-- Default open time when owner hasn't set hours
    DefaultClose         = '22:00',
    KeepOpenWhileStaffed = true,   -- Any clocked-in employee keeps doors unlocked
    HideTellerWhenClosed = true,   -- Teller ped disappears when closed
    StopNPCsWhenClosed   = true,   -- NPC customers stop spawning when closed
}
```

| Key                    | Default   | Description                                                            |
| ---------------------- | --------- | ---------------------------------------------------------------------- |
| `Enabled`              | `true`    | Master switch. `false` = doors never auto-lock.                        |
| `TimeSource`           | `'game'`  | `'game'` uses the GTA in-game clock; `'real'` uses real-world time.    |
| `DefaultOpen`          | `'08:00'` | Open time used when the bank owner hasn't set custom hours.            |
| `DefaultClose`         | `'22:00'` | Close time used when the bank owner hasn't set custom hours.           |
| `KeepOpenWhileStaffed` | `true`    | Any clocked-in employee keeps doors unlocked even during closed hours. |
| `HideTellerWhenClosed` | `true`    | The teller NPC ped is hidden when the bank is closed.                  |
| `StopNPCsWhenClosed`   | `true`    | NPC customer spawns are paused when the bank is closed.                |

> **Setting hours in-game:** The actual open/close times are managed by the bank owner through the management UI (Bank Control panel → hours fields). Server owners only need to touch `Config.BankSchedule` to change the global defaults or turn the feature off.

***

### Troubleshooting

**Front doors not locking/unlocking**

* Check `Config.BankSchedule.Enabled = true`.
* **Built-in mode:** confirm `doors = { ... }` is filled in for the branch (empty array = no managed doors). Verify model names are wrapped in **backticks**, not quotes.
* **Bridge mode:** confirm that doorlock resource is started, and that the IDs in `externalDoorIds` match your doorlock resource's database/config. Enable `Config.Doorlock.Debug = true` to log every lock/unlock attempt.

**"Toggle Front Doors" target option doesn't appear**

* Only shown to players who are **clocked in at that specific branch**.
* Only appears in `native` mode. In `bridge` mode, your existing doorlock resource owns the door UI.
* Duty status is cached for \~5 seconds — wait a moment after clocking in.

**Bank shows "Closed" unexpectedly**

* The bank owner may have manually toggled it closed. Open the management dashboard → Bank Control → toggle open.
* Check `TimeSource` — if set to `'game'`, the in-game clock must be within open hours.
