Developer
Overview
Integration uses server exports for quest state and XP, handler hooks in open/handlers_server.lua and open/handlers_client.lua for quest flow control, and a server event for quest completion.
Server Exports
Quest State
1local quest = exports.ml_missions:GetActiveQuest(source)
2local inQuest = exports.ml_missions:IsPlayerInQuest(source)GetActiveQuest(source): Returns the active quest data table, ornilIsPlayerInQuest(source): Returnstrueif the player has an active quest
XP / Reputation
Per-NPC reputation tracked in the ml_missions_xp table.
1local xp = exports.ml_missions:getXP(source, npcId)
2exports.ml_missions:setXP(source, npcId, 100)
3exports.ml_missions:addXP(source, npcId, 25)
4exports.ml_missions:removeXP(source, npcId, 10)getXP(source, npcId): Returns current XP valuesetXP(source, npcId, amount): Sets XP to a specific amount (min 0)addXP(source, npcId, amount): Adds XPremoveXP(source, npcId, amount): Removes XP (cannot go below 0)
Server Events
1AddEventHandler('ml_missions:server:questCompleted', function(source, questId, squadMembers)
2 -- squadMembers is a table of source IDs (nil if solo)
3end)Fires when any quest is completed, after rewards are distributed.
Server Handlers
Located in open/handlers_server.lua.
Quest Flow
1function Handlers.IsPlayerDead(source)
2 local ped = GetPlayerPed(source)
3 if not ped or ped == 0 then return false end
4 return GetEntityHealth(ped) <= 0
5end
6
7function Handlers.CanPlayerStartQuest(source, questId, questConfig)
8 return true, nil -- return false, 'reason' to block
9end
10
11function Handlers.ModifyRewards(source, questId, moneyData, itemsData)
12 return moneyData, itemsData
13endIsPlayerDead: Override to integrate custom death/ambulance scriptsCanPlayerStartQuest: Returnfalse+ reason string to block quest startModifyRewards: Intercept and modify money/item arrays before distribution
Quest Lifecycle
1function Handlers.OnQuestComplete(source, questId, questConfig, rewardData)
2end
3
4function Handlers.OnQuestFailed(source, questId, reason)
5end
6
7function Handlers.OnObjectiveComplete(source, questId, objectiveId, objectiveConfig)
8endOnQuestComplete: Fires after rewards are distributed.rewardDatacontainsrewards,rewardConfig, andreputationPoints.OnQuestFailed: Fires when a quest fails (timeout, death, manual cancel)OnObjectiveComplete: Fires when a single objective is completed
Vehicle Garage Hook
When a GIVE_VEHICLE objective has keepOnComplete = true, ml_missions registers the vehicle natively (qbx_vehicles / player_vehicles / owned_vehicles). Override this hook to route it to a custom garage.
1function Handlers.OnVehicleKeptForPlayer(source, payload)
2 -- payload = { netId, model, plate, colors, damage, questId }
3 return nil -- nil/false = run native handler ; true = you handled the save
4endOnVehicleKeptForPlayer: Returntrueto take over the save and skip the native handler. Destination garage is set viaConfig.Settings.KeepOnComplete.
Permission Hooks
Both hooks resolve through Bridge.HasPermission against the tiers in Config.Permissions.
1Handlers.HasCreatorPermission = function(source) ... end
2Handlers.HasLivePermission = function(source) ... endHasCreatorPermission(source): Gates/missioncreator, mission/NPC editing and the Live Missions tab.HasLivePermission(source): Gates force-complete / force-fail / teleport in the Live Missions tab. Falls back toHasCreatorPermissionwhenConfig.Permissions.LiveActionsis nil.
Client Handlers
Located in open/handlers_client.lua.
Interaction
1function Handlers.CanInteractWithNPC(npcId, npcData)
2 return true -- return false to hide target
3end
4
5function Handlers.BeforeOpenUI(uiName)
6 return true -- return false to block UI
7endCanInteractWithNPC: Gate NPC target visibility. Returnfalseto hide.BeforeOpenUI: Block UI opening. Returnfalseto cancel.
Mission Lifecycle
1function Handlers.OnMissionStart(questId, questConfig)
2end
3
4function Handlers.OnMissionComplete(questId, questConfig)
5end
6
7function Handlers.OnMissionFailed(questId, reason)
8end
9
10function Handlers.OnObjectiveComplete(objectiveIndex, objectiveConfig)
11endOnMissionStart: Fires when a quest starts on the clientOnMissionComplete: Fires when a quest is completedOnMissionFailed: Fires when a quest failsOnObjectiveComplete: Fires when an objective is completed
Objective Types
The mission creator supports these objective types:
GOTO_COORDS: Navigate to one or more locationsKILL_PEDS: Eliminate enemy NPCs (supports zombie mode)DEFEND_AREA: Defend a location against waves of enemiesESCORT: Escort an NPC to a destinationTAKE_VEHICLE: Pick up or deliver vehiclesINTERACT_PROGRESS: Interact with props using progress bars, minigames, or door unlocksRETRIEVE_ITEM: Collect specific items from the player's inventoryCHECK_ITEM: Verify the player owns a specific itemHEIST_LOOT: Scripted grab points driven by heist presets, with synced animations, optional minigame and per-point rewardsGATHER_REWARD: Collect reward points at specific locationsINTERACTION_TALK: NPC dialogue interaction with optional TTSTURN_IN: Auto-generated return-to-NPC objective
Objective Dependencies
Objectives can be linked together:
activateOnStart: Activate this objective when another objective startsactivateOnEvent: Activate on a specific event (format:"objectiveId:eventName")pauseUntilComplete: Pause this objective until a dependency completes
Dispatch Integration
Each objective can trigger a police dispatch notification:
dispatch.enabled: Enable dispatch for this objectivedispatch.chance: Trigger probability (0-100)dispatch.jobs: Comma-separated job list (default:'police')dispatch.message: Custom dispatch message
Heist Presets
Each HEIST_LOOT point references a preset from shared/heist_presets.lua. A preset defines the target prop spawned in the world, an optional prop swap once the loot is taken, and the phased grab animation with attached props, synced for every player nearby.
cash_trolley,gold_trolley: bank trolleys emptied into a duffel bagsafe_crack: floor safe with an open-door swapcash_stack,gold_stack,cocaine_stack,weed_stack: table grabsjewel_case: display case smashlaptop_hack: laptop grabbolt_cutters,container_grind,crate_crowbar: tool entries for chains, containers and crates
Add your own presets in the same file: copy an entry and change the props and animation phases.
Waypoints and Markers
Every objective location can enable an overhead 3D waypoint and a ground marker, together or separately, set per objective in the creator (fields waypoint and marker3d).
Quest Options
Configurable per-quest in the creator:
requiredXp: Minimum NPC reputation to startrequiredJob: Comma-separated list of jobs or gangs allowed to start the quest. Matching one entry is enoughrequiredJobsOnline: Array of{ job, count }entries. Requires a minimum number of online players per job before the quest can start. Example:{ { job = 'police', count = 2 }, { job = 'bcso', count = 1 } }requiredItemName/requiredItemCount: Item prerequisitesremoveItemOnStart: Consume required item on quest startcooldown: Seconds before the quest can be retakenisPersonalCooldown:true= per-player cooldown,false= global cooldownisOneTimeOnly: Quest can only be completed once per playerreturnToNpc: Player must return to NPC for turn-intimeLimit: Seconds to complete (0 = no limit)reputationPoints: XP awarded on completionxpPenaltyOnFail: XP deducted on failuresquadOptions.enabled: Enable squad modesquadOptions.minMembers: Minimum squad members to startrequiredSkills: Array of ml_skills entries the player must have unlocked before startingrequiredCategories: Array of{ category, minLevel }checks against ml_skills category levelsunlockSkills: Skills granted to the player when the quest completesxpAmount/xpCategory: Skill XP awarded on completion and the category it lands in, capped byConfig.Skills.MaxXpPerQuestvoice: Briefing audio:{ enableTTS, audioType = 'elevenlabs' | 'custom', voiceId, customAudioFile }showAllObjectives: Show the full objective list in the HUD instead of revealing steps one at a time
NPC Configuration
ped.coords: Main spawn position (vector4)ped.positions: Optional array of additional spawn positions for multi-location NPCs. Each entry:{ coords = { x, y, z, w } }. The same NPC spawns at all positions, shares quests and reputation, but the turn-in always routes back to the specific position where the player accepted the quest.
Reward System
Rewards are configured per-quest in the creator. Two formats:
Fixed Loots
Guaranteed drops from a defined pool of items.
Probability Loots
Percentage-based drops with configurable loop count. Each loop rolls against the drop chance independently.
Money
Random amount between a min and max threshold, to a specific account (cash or bank).
Squad Bonuses
Configurable per squad size. Applies a multiplier to money and item rewards when completing as a squad.
Examples
1local eventActive = false
2
3Handlers.CanPlayerStartQuest = function(source, questId, questConfig)
4 if eventActive then
5 return false, 'Missions are disabled during events'
6 end
7 return true
8end1Handlers.ModifyRewards = function(source, questId, moneyData, itemsData)
2 local job = Bridge.GetJob(source)
3 if job and job.name == 'vip' then
4 for i, money in ipairs(moneyData) do
5 moneyData[i].amount = money.amount * 2
6 end
7 end
8 return moneyData, itemsData
9end1Handlers.CanInteractWithNPC = function(npcId, npcData)
2 local job = Bridge.GetPlayerData()?.job?.name
3 if npcId == 'police_chief' and job ~= 'police' then
4 return false
5 end
6 return true
7end1Handlers.OnQuestComplete = function(source, questId, questConfig, rewardData)
2 if questConfig.category == 'combat' then
3 exports.ml_skills:AddXp('personal', 50, source)
4 end
5end