Documentation Index
Fetch the complete documentation index at: https://docs.cc-scripts.com/llms.txt
Use this file to discover all available pages before exploring further.
cc_heistcontracts doesn’t ship any heists — it just runs the marketplace, slot economy, and dashboard around them. Your heist resource registers itself by calling RegisterContract on the server.
The RegisterContract export
RegisterContract returns the contract id. Call it once per contract from your heist resource’s server boot — typically inside a delayed thread so dependencies are up first:
Field reference
| Field | Type | Default | Notes |
|---|---|---|---|
id | string | — | Stable key. Required unless you pass name (then id = name). Don’t change after release — players’ slot rows reference it. |
name | string | falls back to id | Legacy display field, kept for back-compat. |
title | string | falls back to name | Header shown in the dashboard. |
description | string | '' | One- or two-line pitch. |
difficulty | string | 'medium' | Free-form; the dashboard renders it as a chip. Common values: easy, medium, hard. |
levelRequired | int | 1 | Server enforces this on purchase. The dashboard greys out the buy button below the threshold. |
price | int | 0 | VICE cost to acquire a slot. |
crewSize | { min, max } | { min = 1, max = 4 } | Display-only today. Your entry point is responsible for enforcing actual crew size. |
duration | int (seconds) | 0 | Display-only. |
reward | { vice, cash, xp } | {} | Display-only. Your entry point is responsible for actually crediting the player on success — call back into Profile.AddVice / AddXp (see below). |
itemsRequired | array of { id, qty } | {} | Display-only. The dashboard shows whether the player has them in their inventory; nothing is consumed at start. |
locations | array of { id, label } | {} | Surfaced to the dashboard so the player can pick which variant of the heist to run. The chosen location is threaded into runtimeData.location. |
objectives | array of strings | {} | Display-only checklist in the dashboard. |
server/registry.lua:normalize for the full list.
What happens after registration
Rotation re-rolls
The first registration ever triggers a one-shot re-roll so dev runs see the contract immediately. Otherwise you wait for the next tick of the rotation timer —
config.rotation.intervalMs from boot.Player buys it
They open the dashboard, see your contract in the rotation, click buy. The server validates VICE balance, level, and slot availability, debits the price, fills a slot.
Granting rewards from your heist
reward = { vice, cash, xp } on the contract definition is display only. Your entry point is the one that actually credits the player when the heist completes. The recommended way:
_G.HeistProfile global is set by server/profile.lua and exposes the full mutator surface. Cash payouts use whatever your core’s money API is (e.g. cc_lib.Core or qbx_core directly) — cc_heistcontracts does not handle cash.
XP additions automatically advance the level if the new total crosses level thresholds. The dashboard reflects new XP / level on its next sync (the helper
_G.HeistSync.SendProfile(src) triggers an immediate push).The legacy StartContract export
/heist:test and /heist:test2 use it), but new integrations should use the dashboard-driven slot flow.
Picking up cross-resource events
A few server events are useful for cross-resource integration:| Event | When it fires | Use case |
|---|---|---|
cc_heistcontracts:rotationChanged | Server-local; fired right after the rotation re-rolls. | Notify a Discord webhook, refresh a separate UI, etc. |
Profile, which you can read at any time via _G.HeistProfile.GetBySrc(src).