Per-task countdown chips
TaskUI objectives now carry an optional timer alongside the existing counter chip. The chip renders next to the task text inMM:SS, ticks at 1 Hz server-side, and uses the same neutral styling as the counter chip.New API (server)
cc.TaskUI.SetTaskTimer(id, taskId, seconds)— arm or replace a per-task countdown.cc.TaskUI.ClearTaskTimer(id, taskId)— remove the chip without firing the expiry callback.cc.TaskUI.AddTaskTime(id, taskId, seconds)/DeductTaskTime(id, taskId, seconds)— adjust a running timer.cc.TaskUI.GetTaskTime(id, taskId)— read remaining seconds.cc.TaskUI.SetTaskTimerFrozen(id, taskId, frozen)/IsTaskTimerFrozen(id, taskId)— pause a running countdown without clearing it. The chip turns red and slowly flashes while frozen.- New
onTaskTimerEnd(listId, taskId)callback onCreate— fires once when a per-task timer hits 0. Status is not auto-changed; callers decide whether expiry means fail, advance, or something else. - Initial
objectives[].timer = { timeLeft = N, frozen = true }is supported onCreateandAddTask.
Behavior notes
- The chip is only visible while the task is the active one (same as the counter chip).
- Calling
SetTaskTimeron a running timer atomically replaces it via a generation token — no stale ticker threads. SetTaskTimer(id, taskId, 0)is a clear, not a fire.
Docs
- New Library (cc_lib) section with Introduction, Installation, TaskUI, and Module reference.
- First documentation pass — previously cc_lib was only referenced indirectly through
cc_heistcontractspages.
Drip marketplace, active heists, give-up flow
Marketplace
- Replaced batched rotation (
intervalMs+size) with a drip system. New listings appear one at a time onconfig.rotation.dripIntervalMs, up tomaxListings. Old listings get culled afterlistingExpiryMs. See Configuration. - Added per-contract
weightfor biased random picks. Higher weight = more common in the marketplace drip. - Each listing is now a unique instance with its own
listingId. The same contract template can be listed multiple times in parallel.
Active heist tracking
- Starting a slot no longer consumes it — it marks the slot active. The slot is consumed when the heist ends.
- One heist at a time per player. The dashboard disables Start/Discard/Transfer on the other slots, and crew invites, while a heist is active.
- The dashboard renders an
ActiveHeistPanelfor the running slot, with an elapsed-time counter and a two-stage Give Up button.
Integration API
- The whole integration lives in a single
RegisterContractcall — no separate exports on the heist resource. opts.cancelcallback inRegisterContractopts: fires when a player presses Give Up. cc_heistcontracts auto-finishes every group member’s slot after the callback returns. The Give Up button is hidden when this callback isn’t provided. See Registering contracts.opts.resetcallback is unchanged; documented alongsidecancelso the distinction is clear.- New
exports.cc_heistcontracts:FinishHeist(groupName, success)— group-aware convenience that loops members and finishes each slot in one call.FinishContract(src, success)stays for single-player use. See Registering contracts. - Added a worked example for integrating an escrowed third-party heist in one wrapper file.
Other
- Friendlier toast messages for buy / start failures.
- Random location pick when a heist has multiple
locationsand the caller doesn’t specify one. - Bootstrap payload now includes a
contractsmap (full registry) so the UI can resolve owned-slot contract ids. - Removed the seed test contracts from
server/main.lua— bundled heist resources (Fleeca, Paleto, Pacific) register themselves. /heist:test3added for the Pacific heist.
Documentation site launched
- Initial public docs covering cc_minigames and cc_heistcontracts.
- Welcome page, support contacts, refund and terms links.
- This changelog.
Initial release
- Public
RegisterContractexport so any heist resource can plug in. - Dashboard NUI on
F6//heist— alias gating, contracts, slots, ledger, crew, marketplace, training. - Server-authoritative VICE economy with a 50-entry per-player ledger.
- Rotation engine rolling
config.rotation.sizecontracts every 20 minutes (configurable). - Marketplace with VICE checkout, server-rolled pickup locations, ox_target “Knock” interaction, time-windowed expiry.
- Training sandbox with one-time access fee + per-minigame unlocks gated by player level.
- Crew layer wrapping
cc_lib.Groupswith invites and disband-on-leader-leave. - Inter-player contract transfers with auto-expiring invites.
- SQL migrations 001–003 (heist_profiles, alias, training).
- Admin command
/heist:grantxp <alias> <amount>(ACE-gated).
Initial release
- 31 minigames across terminal, bare, strip, and screen-4x3 variants.
- Difficulty tiers (
easy/medium/hard) with tuned defaults; every individual knob overridable per call. - Blocking exports: each minigame yields the calling coroutine until the player passes, fails, or escapes.
- Schematic Control Panel for heist resources to render persistent door/camera UIs.
- DUI session helper so any minigame can be projected onto an in-world prop texture (CRTs, monitors).
- Frequency — server-authoritative two-player tuning game; the only minigame that requires the server.
/minigametest command for previewing every game with arbitrary args.