Accueil › Documentation › Tâches et améliorations · origen_ilegalv2
Le Panneau d’organisation (OrgPanels) te permet de brancher n’importe quelle ressource externe (missions, braquages, vols) sur le tableau de progression du gang. Ta ressource enregistre des tâches et des améliorations ; origen_ilegalv2 gère la persistance, la validation, l’affichage NUI et les hooks.
| Concept | Ce que c’est |
|---|---|
| Tâche | Un jalon qu’un gang peut accomplir. Suit completed et times_completed. Peut être unique ou répétable. |
| Amélioration | Un déblocage permanent pour un gang. Nécessite d’accomplir une ou plusieurs tâches avant de pouvoir être activée. |
| Feature key | Un string stocké dans effect.feature d’une amélioration. Les ressources externes utilisent cette clé (et non la upgrade_key) pour vérifier l’accès. Elle découple ta ressource des noms des améliorations. |
Flux de données :
External resource registers task/upgrade on boot
↓
Gang members complete tasks in-game → your resource calls CompleteGangTask
↓
Leader unlocks upgrade from the gang panel (NUI) or your code calls UnlockGangUpgrade
↓
Other resources gate content behind IsGangFeatureUnlockedOrgPanels charge ses catalogues au démarrage de la ressource. Enregistre toujours dans onResourceStart pour garantir que le module est prêt :
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() ~= resourceName then return end
exports['origen_ilegalv2']:AddOrganizationTask({ ... })
exports['origen_ilegalv2']:AddOrganizationUpgrade({ ... })
end)Appeler ces exports au niveau supérieur (en dehors d’un événement) risque de provoquer une condition de concurrence si origen_ilegalv2 n’a pas encore fini de charger.
AddOrganizationTask(taskDef)exports['origen_ilegalv2']:AddOrganizationTask({
task_key = 'task_recon_north', -- unique key (snake_case recommended)
label = 'North Recon', -- displayed in the gang panel
description = 'Perform recon of the northern zone.',
category = 'heist', -- free-form category for NUI grouping
is_repeatable = false, -- true = can be completed multiple times
meta = { zone = 'north', reward_hint = 'Unlocks bank heist' },
})| Champ | Type | Obligatoire | Description |
|---|---|---|---|
task_key |
string | ✅ | Identifiant unique. Utilisé dans required_tasks des améliorations et dans tous les appels d’exports |
label |
string | ✅ | Nom affiché dans le panneau du gang |
description |
string | — | Description plus longue, affichée dans la NUI |
category |
string | — | Libellé libre servant à regrouper les tâches dans le panneau |
is_repeatable |
boolean | — | Avec true, la tâche peut être accomplie plusieurs fois (chaque appel incrémente times_completed). Par défaut : false |
meta |
table | — | Données arbitraires stockées en JSON. Lisibles par les hooks et GetGangTasks. Non utilisées par le système central |
enabled |
boolean | — | Mets-le à false pour masquer la tâche du panneau sans la supprimer. Par défaut : true |
Si task_key existe déjà dans la base de données, la ligne est mise à jour (upsert). On peut l’appeler sans risque à chaque démarrage.
AddOrganizationUpgrade(upgradeDef)exports['origen_ilegalv2']:AddOrganizationUpgrade({
upgrade_key = 'upgrade_robbery_tier2',
label = 'Access: Medium Heists',
description = 'Enables access to medium-tier heist jobs.',
type = 'robbery_unlock',
required_tasks = { 'task_recon_north' }, -- all must be completed before unlocking
effect = {
feature = 'robberies:tier2', -- key your resource checks
min_cops = 4, -- optional extra data
},
})| Champ | Type | Obligatoire | Description |
|---|---|---|---|
upgrade_key |
string | ✅ | Identifiant unique |
label |
string | ✅ | Nom affiché dans le panneau du gang |
description |
string | — | Description plus longue |
type |
string | — | Libellé de type libre pour le regroupement dans la NUI (p. ex. 'robbery_unlock', 'logistics', 'economy') |
required_tasks |
table ou string | — | Tableau de valeurs task_key qui doivent être accomplies. Accepte aussi un string CSV : 'task_a, task_b' |
effect |
table | — | Données arbitraires. effect.feature est la clé que les autres ressources interrogent via IsGangFeatureUnlocked |
enabled |
boolean | — | Par défaut : true |
required_tasks = {
'task_recon_north',
'task_supply_route',
'task_eliminate_rivals',
},Toutes les tâches listées doivent être accomplies avant que l’amélioration puisse être débloquée. La NUI montre au gang l’état de chaque tâche.
Appelle-le chaque fois qu’un membre du gang termine l’activité correspondante en jeu :
local function OnReconMissionComplete(source)
local gang = exports['origen_ilegalv2']:GetPlayerGangData(source)
if not gang then return end
local result = exports['origen_ilegalv2']:CompleteGangTask(
gang.id,
'task_recon_north',
{
completed_by = GetPlayerIdentifier(source), -- optional
progress = { duration_seconds = 320 }, -- optional meta, stored in DB
}
)
if result.ok then
print('Task completed. Times:', result.times_completed)
elseif result.error == 'already_completed' then
-- Non-repeatable task was already done — not an error, just a no-op
end
end| Champ | Type | Description |
|---|---|---|
ok |
boolean | true en cas de succès |
error |
string|nil | 'already_completed' / 'task_not_found' / 'invalid_gang' |
times_completed |
number | Nombre de fois où elle a été accomplie après cet appel |
IsGangTaskCompleted(gangId, taskKey) → booleanVérification synchrone en mémoire. Utilise-la dans les callbacks serveur avant d’autoriser une action :
lib.callback.register('myresource:server:canStartHeist', function(source)
local gang = exports['origen_ilegalv2']:GetPlayerGangData(source)
if not gang then return false end
return exports['origen_ilegalv2']:IsGangTaskCompleted(gang.id, 'task_recon_north')
end)Les améliorations sont normalement débloquées par le chef du gang, ou par un membre disposant de la permission de grade manage_org_upgrades, depuis la NUI. Tu peux aussi les débloquer par code, ce qui est utile pour des récompenses automatiques ou des événements serveur :
local result = exports['origen_ilegalv2']:UnlockGangUpgrade(
gangId,
'upgrade_robbery_tier2',
{
unlocked_by = 'system_auto', -- optional, stored in DB
meta = { source = 'event' }, -- optional
}
)
if result.ok then
-- success
elseif result.error == 'already_unlocked' then
-- idempotent, not a real error
elseif result.error == 'missing_dependencies' then
for _, t in ipairs(result.missing_tasks or {}) do
print('Missing task:', t.task_key, t.label)
end
end| Champ | Type | Description |
|---|---|---|
ok |
boolean | true en cas de succès |
error |
string|nil | 'already_unlocked' / 'missing_dependencies' / 'upgrade_not_found' / 'invalid_gang' |
missing_tasks |
{ task_key, label }[] |
Présent uniquement quand error == 'missing_dependencies' |
C’est le modèle recommandé. Ta ressource ne connaît pas la upgrade_key, seulement le string feature. Tu pourras renommer l’amélioration plus tard sans toucher aux autres ressources.
-- In origen_robberies or any external resource:
lib.callback.register('origen_robberies:server:getAvailable', function(source)
local gangId = exports['origen_ilegalv2']:GetPlayerGang(source)
if not gangId then return {} end
local hasTier2 = exports['origen_ilegalv2']:IsGangFeatureUnlocked(gangId, 'robberies:tier2')
local hasTier3 = exports['origen_ilegalv2']:IsGangFeatureUnlocked(gangId, 'robberies:tier3')
-- return only the heists the gang has unlocked
end)GetGangTasks(gangId) → table[]Renvoie le catalogue complet enrichi de la progression de chaque gang :
local tasks = exports['origen_ilegalv2']:GetGangTasks(gang.id)
-- tasks[i] = {
-- task_key, label, description, category,
-- is_repeatable, meta,
-- completed, -- boolean
-- times_completed, -- number
-- completed_at, -- datetime or nil
-- last_completed_at -- datetime or nil
-- }GetGangUpgrades(gangId) → table[]Renvoie le catalogue complet des améliorations avec l’état de déblocage et la résolution des dépendances :
local upgrades = exports['origen_ilegalv2']:GetGangUpgrades(gang.id)
-- upgrades[i] = {
-- upgrade_key, label, description, type,
-- required_tasks, -- [{ task_key, label, completed }]
-- deps_satisfied, -- boolean: all required tasks done
-- unlocked, -- boolean
-- }Le fichier de hooks se trouve dans custom/server/org_panels_hooks.lua. Il est chargé par la ressource et exécuté dans origen_ilegalv2, sans besoin de liaison entre ressources.
Modifie uniquement le corps de chaque fonction. Ne renomme ni les fonctions ni la table OrgPanelsHooks.
OrgPanelsHooks.onTaskCompleted(ctx)Se déclenche chaque fois qu’une tâche est marquée comme accomplie pour un gang, y compris les tâches répétables.
function OrgPanelsHooks.onTaskCompleted(ctx)
-- ctx.gangId → gang ID
-- ctx.taskKey → task key
-- ctx.taskDef → full task definition (label, category, is_repeatable, meta)
-- ctx.timesCompleted → total completions after this call
-- ctx.identifier → citizenid of who completed it (nil if automatic)
-- ctx.gangInstance → Gang object (members, ranks, addMoney, addLog, etc.)
-- Reward all online members
if ctx.gangInstance then
for identifier, _ in pairs(ctx.gangInstance.members) do
local src = GetPlayerByIdentifier(identifier)
if src then
NotifyPlayer(src, 'Task completed: ' .. ctx.taskDef.label, 'success')
end
end
end
-- Reward the member who completed it
if ctx.identifier then
local src = GetPlayerByIdentifier(ctx.identifier)
if src then
AddPlayerMoney(src, 'black_money', 5000)
end
end
endOrgPanelsHooks.onUpgradeUnlocked(ctx)Se déclenche exactement une fois par paire (gangId, upgradeKey), car les améliorations sont permanentes.
function OrgPanelsHooks.onUpgradeUnlocked(ctx)
-- ctx.gangId → gang ID
-- ctx.upgradeKey → upgrade key
-- ctx.upgradeDef → full definition (label, type, required_tasks, effect)
-- ctx.identifier → who unlocked it (nil if automatic)
-- ctx.gangInstance → Gang object
-- Notify all gang members
if ctx.gangInstance then
for identifier, _ in pairs(ctx.gangInstance.members) do
local src = GetPlayerByIdentifier(identifier)
if src then
TriggerClientEvent('myresource:client:upgradeUnlocked', src, {
upgradeKey = ctx.upgradeKey,
label = ctx.upgradeDef.label,
effect = ctx.upgradeDef.effect,
})
end
end
end
-- Branch by type
if ctx.upgradeDef.type == 'robbery_unlock' then
-- specific logic for heist unlocks
end
endOrgPanelsHooks.onUpgradeUnlockBlocked(ctx)Se déclenche quand quelqu’un tente de débloquer une amélioration alors que les tâches requises ne sont pas encore accomplies. Utile pour journaliser ou donner un retour supplémentaire.
function OrgPanelsHooks.onUpgradeUnlockBlocked(ctx)
-- ctx.gangId → gang ID
-- ctx.upgradeKey → upgrade that was attempted
-- ctx.upgradeDef → full upgrade definition
-- ctx.missingTasks → [{ task_key, label }] list of incomplete tasks
-- ctx.identifier → who attempted (nil if automatic)
-- ctx.source → player source if the attempt came from the NUI
if ctx.source then
local missing = {}
for _, t in ipairs(ctx.missingTasks) do
missing[#missing + 1] = t.label
end
NotifyPlayer(ctx.source, 'Complete first: ' .. table.concat(missing, ', '), 'error')
end
endVoici une version condensée de ce à quoi ressemble une intégration complète depuis une ressource externe :
-- 1. Register on boot
AddEventHandler('onResourceStart', function(resourceName)
if GetCurrentResourceName() ~= resourceName then return end
exports['origen_ilegalv2']:AddOrganizationTask({
task_key = 'mission_convoy_00',
label = 'Intercept Convoy',
description = 'Ambush and rob the supply convoy.',
category = 'mission',
is_repeatable = false,
})
exports['origen_ilegalv2']:AddOrganizationUpgrade({
upgrade_key = 'unlock_convoy_hard',
label = 'Hard Convoys',
description = 'Unlocks armored convoy missions.',
type = 'mission_unlock',
required_tasks = { 'mission_convoy_00' },
effect = { feature = 'missions:convoy_hard' },
})
end)
-- 2. Complete the task when mission ends
local function OnConvoySuccess(source)
local gang = exports['origen_ilegalv2']:GetPlayerGangData(source)
if not gang then return end
exports['origen_ilegalv2']:CompleteGangTask(gang.id, 'mission_convoy_00', {
completed_by = GetPlayerIdentifier(source),
})
end
-- 3. Gate hard missions behind the feature
lib.callback.register('my_missions:server:getMissions', function(source)
local gangId = exports['origen_ilegalv2']:GetPlayerGang(source)
local hasHard = gangId and exports['origen_ilegalv2']:IsGangFeatureUnlocked(gangId, 'missions:convoy_hard')
local missions = { { id = 'convoy_easy', label = 'Supply Convoy (Easy)' } }
if hasHard then
missions[#missions + 1] = { id = 'convoy_hard', label = 'Armored Convoy (Hard)' }
end
return missions
end)