> ## Documentation Index
> Fetch the complete documentation index at: https://docs.projectx.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Open Source

> Open source customization for the K4MB1 Casino Heist resource

Most core logic runs through the bridge and encrypted scripts. Open source files let you customize minigames, hooks, and integrations without editing escrow.

## opensource/client/client.lua

Handles zones, drawtext, evidence, stress, and the minigame callback. Edit minigames in the `projectx-casinoheist-k4mb1:client:Minigames` callback.

### Minigame Callback

Each step name is passed as `Step`. Replace the export inside the matching `elseif`, or return `true` to skip a step.

```lua theme={null}
lib.callback.register('projectx-casinoheist-k4mb1:client:Minigames', function(Step)
    local p = promise.new()
    if Step == "Cashier" then
        p:resolve(true)
    elseif Step == "KeypadStairsAccess" then
        if not exports['projectx-bridge']:MinigameCheck("utk_fingerprint") then p:resolve(false) return Citizen.Await(p) end
        TriggerEvent("utk_fingerprint:Start", 4, 6, 2, function(success) p:resolve(success) end)
    elseif Step == "KeypadCashier" then
        if not exports['projectx-bridge']:MinigameCheck("pure-minigames") then p:resolve(false) return Citizen.Await(p) end
        local gameData = {totalNumbers = 20, seconds = 20, timesToChangeNumbers = 4, amountOfGames = 1, incrementByAmount = 5}
        p:resolve(exports['pure-minigames']:numberCounter(gameData))
    elseif Step == "FuseboxVault" then
        if not exports['projectx-bridge']:MinigameCheck("boii_minigames") then p:resolve(false) return Citizen.Await(p) end
        exports['boii_minigames']:wire_cut({style = 'default', timer = 60000}, function(success) p:resolve(success) end)
    else
        p:resolve(false)
    end
    return Citizen.Await(p)
end)
```

> [!NOTE]
>
> Return `true` from any branch to skip that minigame (for testing or custom automation).

### Default minigame assignments

| Step | Resource | Function |
| - | - | - |
| `Cashier` | — | skipped (`true`) |
| `KeypadStairsAccess` | `utk_fingerprint` | `Start` (event) |
| `KeypadCashier` | `pure-minigames` | `numberCounter` |
| `StaircaseCashier` | `bl_ui` | `CircleProgress` |
| `Receptionist` | — | skipped (`true`) |
| `ComputerSideOffice` | `bl_ui` | `PathFind` |
| `KeypadMainOffice` | `bl_ui` | `DigitDazzle` |
| `SafeMainOfficeFingerprint` | `bl_ui` | `PrintLock` |
| `SafeMainOffice` | `pd-safe` | `createSafe` |
| `LaptopMainOffice` | `bl_ui` | `KeySpam` |
| `SmokeSecurity` | `lightsout` | `StartLightsOut` |
| `ButtonSecurity` | — | skipped (`true`) |
| `FuseboxGarage` | `SN-Hacking` | `MemoryCards` |
| `DrawerSecurity` | `ox_lib` | `skillCheck` |
| `TopElevator` | `SN-Hacking` | `SkillBar` |
| `BottomElevator` | `SN-Hacking` | `SkillBar` |
| `LaptopVaultPutDown` | `bl_ui` | `KeySpam` |
| `LaptopVault` | `bl_ui` | `WordWiz` |
| `PlantJammer` | `bl_ui` | `WaveMatch` |
| `FuseboxVault` | `boii_minigames` | `wire_cut` |
| `ComputerVault` | `boii_minigames` | `chip_hack` |
| `ComputerPuzzle` | `SN-Hacking` | `ColorPicker` |
| `Drilling` | `bl_ui` | `CircleShake` |
| `C4` | `bl_ui` | `MineSweeper` |
| `Penthouse` | `boii_minigames` | `pincode` |
| `Prop` | `bl_ui` | `CircleProgress` |
| `Fusebox1` | `SN-Hacking` | `SkillBar` |
| `Fusebox2` | `bl_ui` | `KeySpam` |
| `Fusebox3` | `bl_ui` | `Progress` |
| `Fusebox4` | `SN-Hacking` | `Thermite` |
| `Fusebox5` | `bl_ui` | `RapidLines` |
| `Fusebox6` | `bl_ui` | `WaveMatch` |
| `Fusebox7` | `boii_minigames` | `wire_cut` |
| `Fusebox8` | `boii_minigames` | `wire_cut` |

Step names match entries in `config/config.lua` (for example `Config.CasinoSteps`).

***

## opensource/server/server.lua

Dispatch, items, money, logging, admin reset command, and hooks.

### Hooks

> [accordion] SuccessfulStep(source, step)
>
> Called when a player completes a robbery step. Use for XP, logging, or custom rewards.
>
> ```lua theme={null}
> function SuccessfulStep(source, step)
>     if step == "KeypadMainOffice" then
>         -- exports['projectx-bridge']:AddExperience(source, 'criminal', 10)
>     end
> end
> ```

> [accordion] FailedStep(source, step)
>
> Called when a player fails a step. Use for penalties or item removal.
>
> ```lua theme={null}
> function FailedStep(source, step)
>     -- Custom logic per step
> end
> ```

> [accordion] InitialCheck(source, Interaction)
>
> Called before the heist can start. Return `false` to block the player.
>
> ```lua theme={null}
> function InitialCheck(source, Interaction)
>     return true
> end
> ```

> [accordion] RobberyResetHook()
>
> Called when the heist resets (timer, admin command, or export).
>
> ```lua theme={null}
> function RobberyResetHook()
>     -- Update scoreboards or external state
> end
> ```

Admin command permissions use `CheckPerms` from the bridge:

```lua theme={null}
function CheckPerms(source)
    return exports['projectx-bridge']:CheckPerms(source, GetCurrentResourceName())
end
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.