# Creating Sets

Sets are themed collections of items for players to find. Configure them in `config/server.lua`.

## Example

```lua
sets = {
    my_set_name = {
        -- Display
        label = 'My Set Name',
        description = 'Find all the items in this set!',

        -- Object
        model = 'prop_box_wood01a',
        icon = 'my_icon.png',
        grounded = true,

        -- Pickup
        pickupType = 'target',
        pickupDistance = 2.5,

        -- State
        enabled = true,

        -- Hints
        hint = 'Look around the city...',

        -- Rewards
        rewards = {
            onCollect = { money = 100, moneyType = 'cash' },
            onComplete = { money = 5000, moneyType = 'bank' },
        },

        -- Locations
        items = {
            { coords = vec3(123.45, 678.90, 12.34) },
            { coords = vec3(234.56, 789.01, 23.45), hint = 'Near the bench' },
        },
    },
},
```

***

## Set Structure

Structure for set table.

* label: [`Label`](#display)
  * Display name for the set shown in the UI
* description: [`Description`](#display)
  * Description for the set shown in the UI
* model [`Model`](#object)
  * Model for the spawned collectable object
* icon: [`Icon`](#object)
  * Icon for stickers in UI (image path `'action-figure-pogo.png'`, or `'fa:icon-name'` for Font Awesome)
* grounded? [`Grounded`](#object)
  * Whether to snap the spawned object to the ground, (default: `true`)
* pickupType? [`PickupType`](#pickup)
  * How to collect the item, (default: `'target'`)
* pickupDistance? [`PickupDistance`](#pickup)
  * Distance to trigger pickup (default: `1.5`)
* enabled? [`Enabled`](#enabled)
  * Whether to enable this collectable set (default: `true`)
* collectSound? [`Sound`](#sound)
  * Play sound on collection (default: `true` for `'nearby'`, `false` for `'target'` and `'prompt'`)
* hint? [`Hint`](#hints)
  * Default hint for all items in set
* rewards? [`Rewards`](#rewards)
  * Rewards for collecting items and completing the set
* blip? [`Blip`](#blip)
  * Optional blip for all items
* animations? [`Animations`](#animations)
  * Animations to use for this set
* items [`Items`](#items-structure)
  * List of collectable items in this set

***

## Items Structure

Structure for items table.

* coords: `vector3`
  * Where to spawn the collectable object
* rotation?: `number`
  * Optional rotation of the collectable object
* grounded?: [`Grounded`](#object)
  * Optional toggle of snapping object to ground for this item
* model? [`Model`](#object)
  * Optional model for this item
* icon?: [`Icon`](#object)
  * Optional icon for this item
* hint? [`Hint`](#hints)
  * Optional hint for this item
* blip? [`Blip`](#blip)
  * Optional blip for this item
* animations? [`Animations`](#animations)
  * Optional animation for this item
* collectSound? [`Sound`](#sound)
  * Optional sound played when item is picked up for this item

***

## Set Options

### Display

| Option        | Type   | Description                 |
| ------------- | ------ | --------------------------- |
| `label`       | string | Name shown in the UI        |
| `description` | string | Description shown in the UI |

### Object

| Option     | Type    | Default  | Description                           |
| ---------- | ------- | -------- | ------------------------------------- |
| `model`    | string  | required | Prop model to spawn                   |
| `icon`     | string  | -        | Sticker image (filename or `fa:icon`) |
| `grounded` | boolean | `true`   | Snap object to ground                 |

### Pickup

| Option           | Type   | Default    | Description                                           |
| ---------------- | ------ | ---------- | ----------------------------------------------------- |
| `pickupType`     | string | `'target'` | How to collect: `'target'`, `'prompt'`, or `'nearby'` |
| `pickupDistance` | number | `1.5`      | Distance to trigger pickup                            |

**Pickup Types:**

* `'target'` - Requires target resource in bridge
* `'prompt'` - Shows TextUI prompt, press key to collect
* `'nearby'` - Auto-collects when player is within range

### Enabled

| Type    | Description                |
| ------- | -------------------------- |
| boolean | Whether to enable this set |

### Blip

| Option    | Type    | Default | Description                                                                                 |
| --------- | ------- | ------- | ------------------------------------------------------------------------------------------- |
| `enabled` | boolean | `true`  | Whether to enable the blip                                                                  |
| `sprite`  | number  | `57`    | [The sprite to use for the blip](https://docs.fivem.net/docs/game-references/blips/)        |
| `colour`  | number  | `1`     | [The colour to use for the blip sprite](https://docs.fivem.net/docs/game-references/blips/) |
| `title`   | string  | `nil`   | The name to use for the blip                                                                |

### Sound

| Option         | Type          | Default | Description         |
| -------------- | ------------- | ------- | ------------------- |
| `collectSound` | boolean/table | varies  | Sound on collection |

```lua
-- Use default sound
collectSound = true,

-- Disable sound
collectSound = false,

-- Custom sound
collectSound = {
    audioName = 'PLAYER_COLLECT', -- Name of the audio to play
    audioRef = 'DLC_PILOT_MP_HUD_SOUNDS', -- Audio reference/set to use
},
```

Default: `true` for `'nearby'` pickup type, `false` for others.

### Animations

| Option   | Type  | Default | Description                                                 |
| -------- | ----- | ------- | ----------------------------------------------------------- |
| `pickup` | table | `nil`   | Animation to play on the client when an object is collected |

```lua
animations = { -- Animations to use for this set
    pickup = { -- Pickup animation
       animDictionary = 'anim@move_m@trash', -- The animation dictionary
       animationName = 'pickup', -- The name of the animation within the dictionary
       animFlags = 0, -- Animation flag
       duration = 3000, -- Duration in milliseconds
    },
},
```

### Hints

| Option | Type   | Description                           |
| ------ | ------ | ------------------------------------- |
| `hint` | string | Default hint for all items in the set |

Individual items can override the set hint:

```lua
items = {
    { coords = vec3(123.45, 678.90, 12.34) },                    -- Uses set hint
    { coords = vec3(234.56, 789.01, 23.45), hint = 'Custom' },   -- Uses custom hint
},
```

### Rewards

```lua
rewards = {
    onCollect = {
        money = 100,
        moneyType = 'cash',  -- 'cash' or 'bank'
        item = { name = 'token', count = 1 },
    },
    onComplete = {
        money = 5000,
        moneyType = 'bank',
        item = { name = 'trophy', count = 1 },
    },
},
```

| Option       | Type   | Description                                 |
| ------------ | ------ | ------------------------------------------- |
| `onCollect`  | table  | Reward given each time an item is collected |
| `onComplete` | table  | Reward given when the set is completed      |
| `money`      | number | Amount of currency                          |
| `moneyType`  | string | `'cash'` or `'bank'`                        |
| `item`       | table  | Optional inventory item `{ name, count }`   |

### Full Example

```lua
example_set = { -- Unique set name
    label = 'Example Set', -- Display name for the set
    description = 'This is the set description shown in the UI', -- Description shown in UI
    model = 'xm3_prop_xm3_box_wood03a', -- Prop model to spawn
    icon = 'action-figure-pogo.png', -- Icon for stickers in UI (image path 'action-figure-pogo.png', or 'fa:icon-name' for Font Awesome)
    grounded = true, -- Place object on ground (default: true)
    pickupType = 'target', -- How to collect: 'target' | 'prompt' | 'nearby' (default: 'target')
    pickupDistance = 2.5, -- Distance to trigger pickup (default: 1.5)
    enabled = false, -- Enabled/disable the collectable set
    collectSound = { -- Play sound on collection: boolean|table (default: true for 'nearby', false for 'target' and 'prompt')
        audioName = 'PLAYER_COLLECT', -- Name of the audio to play
        audioRef = 'DLC_PILOT_MP_HUD_SOUNDS', -- Audio reference/set to use
    },
    hint = 'The hint for all the items', -- Default hint for all items in set
    rewards = { -- Rewards for collecting items and completing the set
        onCollect = { money = 100, moneyType = 'cash' }, -- Reward for each collected item
        onComplete = { -- Reward for completing the entire set
            money = 5000, -- Amount of money
            moneyType = 'bank', -- Money type to give ('cash', 'bank')
            item = { name = 'reward_trophy', count = 1 }, -- Item to give and amount
        },
    },
    blip = { -- Optional blip for all items (https://docs.fivem.net/docs/game-references/blips/)
        enabled = true, -- Enable/disable the blip (enabled by default)
        sprite = 478, -- Blip sprite
        colour = 1, -- Blip colour
        title = 'Example Collectable Item', -- Blip title
        scale = 0.5, -- Optional custom scale
    },
    animations = { -- Animations to use for this set
        pickup = { -- Pickup animation
            animDictionary = 'anim@move_m@trash', -- The animation dictionary
            animationName = 'pickup', -- The name of the animation within the dictionary
            animFlags = 0, -- Animation flag
            duration = 3000, -- Duration in milliseconds
        },
    },
    items = { -- List of collectable items in this set
        { coords = vec3(-140.39, -173.98, 93.70) }, -- With just coordinates
        { coords = vec3(-146.05, -166.42, 95.00), grounded = false }, -- With grounded override
        { coords = vec3(-133.97, -163.08, 93.70), model = 'prop_alien_egg_01' }, -- With model override
        { coords = vec3(-129.66, -163.58, 93.70), icon = 'fa star' }, -- With image override
        { coords = vec3(-138.27, -163.77, 93.70), hint = 'A hint just for this item' }, -- With hint override
        {
            coords = vec3(-140.48, -164.42, 93.70), -- With multiple overrides
            grounded = false,
            model = 'prop_box_ammo07a',
            icon = 'fa box-open',
            hint = 'This box looks different..',
        },
        {
            coords = vec3(-145.03, -170.40, 93.70), -- With optional blip
            blip = { -- Optional blip for this item
                sprite = 514, -- Blip sprite
                colour = 27, -- Blip colour
                title = 'Special Test Box', -- Blip title
                scale = 0.7, -- Optional custom scale
            },
        },
        {
            coords = vec3(-141.85, -166.10, 93.70), -- With animation override
            animations = { -- Animation only for this item
                pickup = { -- Pickup animation
                    animDictionary = 'anim@gangops@facility@servers@bodysearch@', -- The animation dictionary
                    animationName = 'player_search', -- The name of the animation within the dictionary
                    animFlags = 0, -- Animation flag
                    duration = 1500, -- Duration in milliseconds
                },
            },
        },
        {
            coords = vec3(-130.67, -168.78, 92.70), -- With collect sound override
            collectSound = {
                audioName = 'RANK_UP',
                audioRef = 'HUD_AWARDS',
            },
        },
    },
},
```

***

## Tips

* Use unique keys for each set (e.g., `action_figures`, `movie_posters`)
* The key is used internally; players see the `label`
* Set `enabled = false` to disable a set without removing it
* Use the [coordinate finder](https://madcap.gitbook.io/docs/premium-resources/mad_collectables/placing-new-items) to place items
* Test pickup distances in-game to find what feels right
* If an item you create is spawning inside another object, try using `grounded = false`, then manually adjust the `z` coordinate
