> ## 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 files available for customization in the K4MB1 Laundromat Robbery resource

## opensource/client/client.lua

Each robbery step triggers the `projectx-laundromatrobbery-k4mb1:client:Minigames` callback with the step name. All default minigames use `bl_ui`.

```lua theme={null}
lib.callback.register('projectx-laundromatrobbery-k4mb1:client:Minigames', function(Step)
    local p = promise.new()
    if Step == "PlantEMP" then
        if not MinigameCheck("bl_ui") then p:resolve(false) return Citizen.Await(p) end
        local success = exports["bl_ui"]:WaveMatch(1, {duration = 30000})
        p:resolve(success)
    elseif Step == "Keypad" then
        if not MinigameCheck("bl_ui") then p:resolve(false) return Citizen.Await(p) end
        local success = exports["bl_ui"]:DigitDazzle(1, {length = 4, duration = 20000})
        p:resolve(success)
    end
    return Citizen.Await(p)
end)
```

<Info>
  You can return `true` unconditionally inside any step block to skip that minigame entirely.
</Info>

The default minigames per step are:

| Step             | Minigame Resource | Function         |
| ---------------- | ----------------- | ---------------- |
| `PlantEMP`       | `bl_ui`           | `WaveMatch`      |
| `Clothing`       | `bl_ui`           | `KeyCircle`      |
| `Key`            | `bl_ui`           | `CircleShake`    |
| `WashingMachine` | `bl_ui`           | `KeySpam`        |
| `Button`         | `bl_ui`           | `CircleProgress` |
| `Keypad`         | `bl_ui`           | `DigitDazzle`    |

***

## opensource/server/server.lua

### Hooks

<AccordionGroup>
  <Accordion title="SuccessfulStep(source, step)" icon="circle-check">
    Step names are listed in `Config.LaundromatSteps` inside `config/config.lua`.
  </Accordion>

  <Accordion title="FailedStep(source, step)" icon="circle-xmark">
    Called whenever a player fails a robbery step.
  </Accordion>

  <Accordion title="InitialCheck(Interaction)" icon="shield-check">
    Return `false` to block a player from starting the robbery.
  </Accordion>

  <Accordion title="RobberyResetHook()" icon="rotate">
    Called whenever the heist resets.
  </Accordion>
</AccordionGroup>
