> For the complete documentation index, see [llms.txt](https://tg-dev.gitbook.io/tg-dev-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tg-dev.gitbook.io/tg-dev-docs/tg-cornerselling/config.md).

# Config

### Configuration Guide

The main customer-facing settings are in:

```
config/config.lua
config/bridge.lua
```

`config/shared.lua` contains internal clamps, cache intervals, security limits, and runtime constants. It should not normally be edited for gameplay balancing.

Most config changes require a resource restart. The in-game price editor is the exception because it applies prices live.

#### `Config.General`

| Setting            | Description                                                       |
| ------------------ | ----------------------------------------------------------------- |
| `Lang`             | Active interface language                                         |
| `Currency`         | Currency symbol or text shown by the UI                           |
| `ItemImagePath`    | Image URL template; `%s` is replaced with the item name           |
| `KvpKeys`          | Persistent keys used for HUD, buyer pool, and demand data         |
| `Commands`         | Player and admin command names                                    |
| `AdminPermissions` | Admin menu permission mode, framework groups, and ACE permissions |
| `Restrictions`     | Job, ACE, police job, and minimum police rules                    |
| `Payment.Account`  | Framework account that receives sale payments                     |

Supported language values:

```
en, tr, de, fr, es, pt, pl, ru, ar, zh
```

Currency accepts symbols or text:

```lua
Currency = '$'
Currency = '€'
Currency = 'TRY'
Currency = 'EUR'
```

Text currencies receive automatic spacing where required.

**Item images**

`%s` is replaced with the item name:

```lua
ItemImagePath = 'https://cfx-nui-ox_inventory/web/images/%s.png'
```

Set it to an empty string to use the image returned by the inventory bridge:

```lua
ItemImagePath = ''
```

**KVP keys**

```lua
KvpKeys = {
    HudSettings = 'tg-cornerselling:hud-settings',
    BuyerPools = 'tg-cornerselling:buyer-pools',
    Demand = 'tg-cornerselling:demand'
}
```

Changing one of these keys starts that system with a separate saved dataset. Do not rename them on a live server unless you intentionally want to reset or separate the saved KVP data.

#### Admin permission settings

See Admin permissions for the four access modes and complete configuration examples. Permission changes require a resource restart.

#### Restrictions

Default open-access behavior:

```lua
Restrictions = {
    JobOnly = false,
    ACEOnly = false,
    AllowedJobs = {},
    ACEPermission = 'tg-cornerselling.use',
    BlockedJobs = {
        police = true,
        ambulance = true
    },
    PoliceJobs = {
        police = true,
        sheriff = true
    },
    MinimumPolice = 0
}
```

**Job-only access**

```lua
JobOnly = true,

AllowedJobs = {
    dealer = true,
    gang = true
}
```

**ACE-only access**

```lua
ACEOnly = true,
ACEPermission = 'tg-cornerselling.use',
```

Example `server.cfg` permission:

```cfg
add_ace identifier.license:YOUR_LICENSE tg-cornerselling.use allow
```

If `JobOnly` and `ACEOnly` are both enabled, the player must meet both requirements. `BlockedJobs` always takes priority.

Players without access cannot open the player profile, create a database profile, start selling, or enter the rankings.

#### `Config.Interaction`

```lua
Config.Interaction = {
    UseTarget = false,
    Control = 38
}
```

* `UseTarget = false` uses the configured FiveM control.
* `UseTarget = true` uses the target system selected in `config/bridge.lua`.
* Control `38` is the default `E` interaction.

#### `Config.BuyerPool`

| Setting              | Description                                              |
| -------------------- | -------------------------------------------------------- |
| `RefreshThreshold`   | Remaining buyer count that starts the area refresh timer |
| `Cooldown`           | Buyer pool refresh time in seconds                       |
| `StolenLootLifetime` | Maximum stolen-goods state lifetime                      |
| `CorpseLootLifetime` | How long a dead stolen-goods buyer can be looted         |
| `RecoveryCleanup`    | Cleanup window after a recovery state ends               |
| `RunawayBlipEnabled` | Shows the stolen-goods buyer on the owner's map          |

#### `Config.Progression`

| Setting            | Description                               |
| ------------------ | ----------------------------------------- |
| `MaxLevel`         | Maximum player level                      |
| `HeatDecayAmount`  | Heat removed each decay step              |
| `HeatDecaySeconds` | Seconds between Heat decay steps          |
| `RespecBaseCost`   | Base Connection respec price              |
| `RespecPerPoint`   | Additional respec price per spent point   |
| `Milestones`       | One-time long-term Connection Point goals |

Milestone fields:

```lua
{
    id = 'career_sales_100',
    metric = 'sales',
    label = 'challenge_sales',
    target = 100,
    rewardPoints = 1
}
```

Keep milestone IDs unique.

#### `Config.Crew`

**Membership**

| Setting                     | Description                                                                      |
| --------------------------- | -------------------------------------------------------------------------------- |
| `MaxMembers`                | Maximum members including the Boss                                               |
| `MembershipCooldownSeconds` | Wait before creating or joining another crew after applicable membership actions |

**Progression**

Controls maximum crew level, XP earned from sales, Crew Credits earned from payouts, level XP requirements, perk point frequency, and perk respec cost/cooldown.

**Contracts**

* `Count` controls how many weekly crew contracts are selected.
* `MinimumContributors` controls how many different members must contribute before a completed contract can reward the crew.
* Each task defines its metric, target, XP, and Crew Credit reward.

**Perks**

Each perk can define:

* Branch
* Maximum rank
* Point cost
* Crew levels required for each rank
* Another perk requirement
* Gameplay effect per rank

**Momentum**

Controls gains, contributor window, diversity reward, decay timing, minimum contributors, and the bonuses unlocked at each score tier.

**Boosts**

Each boost defines its duration, Crew Credit cost, and effect. Only one temporary boost can be active at a time.

#### `Config.Demand`

| Setting                  | Description                                    |
| ------------------------ | ---------------------------------------------- |
| `Enabled`                | Enables or disables demand calculations        |
| `StartingLevel`          | Random starting range for every area/item pair |
| `TargetLevel`            | Range used for natural market targets          |
| `TargetRefreshMinutes`   | How often a new target can be selected         |
| `RecoveryMinutes`        | Time between demand recovery steps             |
| `RecoveryAmount`         | Amount moved toward the current target         |
| `SaleImpactPerItem`      | Demand removed per sold item                   |
| `MinimumPriceMultiplier` | Price multiplier at minimum demand             |
| `MaximumPriceMultiplier` | Price multiplier at maximum demand             |

**Demand events**

```lua
Events = {
    Enabled = true,
    DelayMinutes = { 60, 90 },
    List = {
        -- event definitions
    }
}
```

Common event fields:

| Field                   | Description                      |
| ----------------------- | -------------------------------- |
| `id`                    | Unique event ID                  |
| `label` / `description` | Locale keys shown in the UI      |
| `weight`                | Relative selection weight        |
| `durationMinutes`       | Random duration range            |
| `activeHours`           | Optional eligible in-game hours  |
| `demandTarget`          | Temporary target adjustment      |
| `payout`                | Payout percentage adjustment     |
| `amount`                | Requested item amount adjustment |
| `negotiation`           | Negotiation chance adjustment    |
| `dispatch`              | Dispatch chance adjustment       |
| `heatMultiplier`        | Heat multiplier                  |

#### `Config.Challenges`

| Setting          | Description                                        |
| ---------------- | -------------------------------------------------- |
| `Enabled`        | Enables daily and weekly challenges                |
| `ResetHourUTC`   | UTC hour used for daily and weekly resets          |
| `EndgameRewards` | Converts unusable capped rewards into limited cash |
| `Daily.Count`    | Number of daily tasks selected                     |
| `Weekly.Count`   | Number of weekly tasks selected                    |

Challenge task example:

```lua
{
    id = 'daily_sales',
    metric = 'sales',
    label = 'challenge_sales',
    target = 6,
    rewards = {
        xp = 40,
        rep = 3
    }
}
```

Keep the existing metric and label values unless you also update the related code and locale entries.

#### `Config.Outcomes`

Defines the starting outcome weights:

```lua
Base = {
    accept = 70,
    refuse = 14,
    spooked = 8,
    steal = 5,
    inform = 3
}
```

Keep the base total at `100` for easier balancing. These are starting weights, not guaranteed final percentages. Reputation, Heat, item risk, skills, crew bonuses, buyer personality, negotiation, and market conditions can modify the final server-side calculation.

`DispatchOnSpooked` and `DispatchOnAccept` define the base dispatch chances for those outcomes.

#### `Config.Negotiation`

| Setting                  | Description                                      |
| ------------------------ | ------------------------------------------------ |
| `Enabled`                | Enables higher-price offers                      |
| `BaseAcceptChance`       | Starting negotiation acceptance chance           |
| `AggressiveRejectChance` | Chance that a rejected option becomes aggressive |
| `RejectedReputationLoss` | Reputation lost after an aggressive rejection    |
| `RejectedHeatGain`       | Heat gained after an aggressive rejection        |
| `Options`                | Available negotiation choices                    |

Option fields:

| Field          | Description                   |
| -------------- | ----------------------------- |
| `pricePercent` | Requested payout increase     |
| `amount`       | Additional requested items    |
| `chance`       | Acceptance chance modifier    |
| `aggressive`   | Aggressive rejection modifier |
| `patience`     | Patience consumed             |
| `tone`         | UI color/risk style           |

#### `Config.BuyerPersonalities`

* `Enabled` toggles personality effects.
* `weight` controls relative selection frequency.
* `patience` controls available negotiation patience.
* Other optional fields adjust payout, amount, negotiation, aggression, dispatch, Heat, and outcomes.

Personality IDs must be unique.

#### `Config.Dispatch`

```lua
Config.Dispatch = {
    Enabled = true,
    System = 'auto',
    Code = '10-66',
    Jobs = { 'police', 'sheriff' },
    Message = 'Suspicious street sale reported. Location added to the map.',
    NotificationDuration = 8000,
    Blip = {
        Enabled = true,
        Name = 'Suspicious Street Sale',
        Sprite = 51,
        Color = 1,
        Scale = 1.10,
        Duration = 90000,
        Flash = true,
        Route = false
    }
}
```

Available systems:

```
auto, built-in, client, server, custom, bub-mdt, cd_dispatch,
emergencydispatch, fd_dispatch, kartik-mdt, lb-tablet,
linden_outlawalert, origen_police, piotreq_gpt, ps-dispatch,
qs_dispatch, redutzu-mdt, tk_dispatch, wasabi_mdt
```

* `auto` uses the dispatch detected by `community_bridge`.
* If `auto` cannot find a supported dispatch, it falls back to the built-in dispatch.
* `built-in` notifies the jobs in `Jobs` and creates the configured temporary blip.
* `client` or `custom` calls `Config.Dispatch.Custom.Client`.
* `server` calls `Config.Dispatch.Custom.Server`.

Custom dispatch data contains:

```lua
{
    source = source,
    coords = coords,
    code = Config.Dispatch.Code,
    jobs = Config.Dispatch.Jobs,
    message = Config.Dispatch.Message,
    notificationDuration = Config.Dispatch.NotificationDuration,
    blip = Config.Dispatch.Blip
}
```

#### `Config.Areas`

Every area has its own center, radius, buyers, items, buyer blip setting, and optional main map blip.

```lua
Config.Areas.example = {
    label = 'Example Area',
    coords = vector3(100.0, 200.0, 30.0),
    radius = 250.0,

    Buyers = {
        {
            id = 'example_001',
            coords = vector4(110.0, 205.0, 30.0, 180.0),
            model = 'a_m_m_soucent_01'
        }
    },

    items = {
        'watch',
        'ring'
    },

    BuyerBlips = true,

    blip = {
        enabled = false,
        name = 'Example Corner Selling',
        sprite = 365,
        color = 26,
        scale = 0.7
    }
}
```

Important rules:

* The area key must be unique.
* Every buyer ID must be unique inside its area.
* Buyer coordinates use `vector4(x, y, z, heading)`.
* Items must exist in both `Config.Items` and the inventory.
* `BuyerBlips` only controls individual buyer locations while selling.
* `blip.enabled` controls the area's permanent map blip.

#### `Config.Items`

```lua
Config.Items.watch = {
    label = 'Watch',
    price = { 65, 79 },
    amount = { 1, 3 },
    minLevel = 1,
    minRep = 0,
    xp = 18,
    rep = 4,
    heat = 2,
    risk = 1.0
}
```

| Field      | Description                                |
| ---------- | ------------------------------------------ |
| `label`    | Display name                               |
| `price`    | Random base price range per item           |
| `amount`   | Random requested quantity range            |
| `minLevel` | Required player level                      |
| `minRep`   | Required reputation                        |
| `xp`       | XP granted per sold item                   |
| `rep`      | Reputation granted by the sale calculation |
| `heat`     | Base Heat generated                        |
| `risk`     | Risk modifier used by deal calculations    |

Locked items are not selected for players who do not meet their level or reputation requirement.

#### `Config.Skills`

Skills are grouped into `profit`, `influence`, and `safety`.

```lua
{
    id = 'bulk_orders',
    name = 'skill_bulk_orders',
    description = 'skill_bulk_orders_desc',
    maxRank = 5,
    effect = 1,
    requires = {
        id = 'better_deals',
        rank = 3
    }
}
```

* `id` must be unique.
* `name` and `description` are locale keys.
* `maxRank` controls the number of purchasable ranks.
* `effect` is the effect per rank.
* `requires` optionally locks the skill behind another skill and rank.

#### `Config.Logs`

Available systems:

```
none, console, discord, fivemanage, custom
```

Enable or disable categories independently:

```lua
Events = {
    Sale = true,
    Crew = true,
    Progression = true,
    Admin = true,
    System = true
}
```

**Discord**

```lua
Config.Logs.Enabled = true
Config.Logs.System = 'discord'
```

Keep the webhook out of shared config:

```cfg
set tg_cornerselling_discord_webhook "https://discord.com/api/webhooks/..."
```

**FiveManage**

```lua
Config.Logs.Enabled = true
Config.Logs.System = 'fivemanage'
```

Configure the FiveManage API key and start `fmsdk` before this resource:

```cfg
set FIVEMANAGE_LOGS_API_KEY "YOUR_API_KEY"
ensure fmsdk
ensure tg-cornerselling
```

The in-game administration log is stored separately from optional external logs. Old administration activity entries are automatically removed after the internal retention period.

### Bridge Configuration

Only edit `TGBridge.Settings` at the top of `config/bridge.lua`. Runtime code begins below the following comment and should not normally be changed:

```lua
-- Internal runtime starts here. All user-editable settings are above this line.
```

#### Core

```
auto, es_extended, qb-core, qbx_core, custom
```

The Core section controls identifiers, character names, jobs, police lookup, money, custom framework permission lookup, and player-loaded state. Customer-facing admin access rules remain under `Config.General.AdminPermissions`.

`MoneyAccounts` maps the account names used by this resource to the account names expected by your framework. The selected value in `Config.General.Payment.Account` must have a valid mapping.

#### Inventory

The Inventory section controls item counts, item removal, item recovery, and item information.

#### Target

```
auto, ox_target, qb-target, sleepless_interact, custom
```

The selected target is used only when `Config.Interaction.UseTarget = true`.

When a system is set to `custom`, complete the short custom function provided in the same bridge section.
