Custom missions
Create a basic config template
Locate the config/missions.lua file and create a basic template (example bellow)
{
label = 'Custom Mission Example',
description = 'Your Custom Mission Example description for gang-activities.',
icon = 'assets/avatars/male_5.png',
reward = 100,
xpReward = 50,
difficulty = 'easy',
required_level = 1,
mission = 'custom_mission_exemple',
endMissionRespawn = false,
respawnRandomPos = {
vector3(-57.509113311768, -1079.9354248047, 26.964902877808),
vector3(377.14935302734, -1306.2001953125, 33.484718322754),
vector3(-823.34063720703, -1094.5144042969, 11.145439147949),
},
blip = { -- set blip = nil so you don't activate the blip menu
id = 119,
color = 4,
scale = 0.6,
coords = true,
name = 'Custom Mission Blip'
},
tasks = {
[1] = {
info = 'Custom singleplayer mission task 1',
completeFunction = function(tasksArgs)
local arg1 = tasksArgs[1]
return false;
end,
},
}
}, ['custom-multiplayer-mission'] = {
label = 'Custom multiplayer Mission',
description = 'Custom multiplayer Mission description',
icon = 'assets/avatars/default.png',
mission_color = 'green',
mission_background = 'store-robbery', -- .png file name from assets/missions-bg/
infos = {
'Info 1',
'Info 2',
'Info 3',
},
endMissionRespawn = false,
respawnRandomPos = {
vector3(-57.509113311768, -1079.9354248047, 26.964902877808),
vector3(377.14935302734, -1306.2001953125, 33.484718322754),
vector3(-823.34063720703, -1094.5144042969, 11.145439147949),
},
blip = { -- set blip = nil so you don't activate the blip menu
id = 59,
color = 1,
scale = 0.6,
coords = nil,
forEntity = true,
setRoute = true,
name = 'Custom Mission'
},
difficulty = 'easy',
required_level = 1,
xpReward = 60,
reward = 35000,
multiplayer = true, -- don't change
setVirtualWorld = false,
tasks = {
[1] = {
info = 'Custom Task 1',
completeFunction = function(tasksArgs)
local task1 = tasksArgs[1];
return task1
end,
},
}
},Create the server-side file for your mission.
Navigate to server/custom/missions/singleplayer/ or server/custom/missions/multiplayer/ and use the default template located there.
---@type string unique and same as client side
local missionId <const> = 'custom_mission_exemple';
---comment
---@param playerSource integer
---@param missionData table
---@return table?nil, table?nil
local missionFunction = function(playerSource, missionData)
if not missionData then return print('ERROR: MissionData is nil') end;
local extraData = {};
local entities = {};
-- custom singleplayer missions for server side;
-- insert all the entities in entities table with table.insert(entities, {entityData}), so after the mission is finished/failed or resource is restarted the entities will be deleted
-- extraData need to contain all the entities informations created in server side such as: networkId, weaponName for npc enemy, extra mission data such as selected location/house etc
-- even if you are not using extraData and entities make sure to let it an empty table, = {}
-- make sure to set entities in virtual world if the missionData.setVirtualWorld = true;
-- example:
local npc; -- npc entity after you create it;
local playerIdentifier = Framework.GetPlayerIdentifier(playerSource);
if missionData.setVirtualWorld then
local bucketId = 100 + playerSource;
SetEntityRoutingBucket(npc, bucketId);
end
return extraData, entities;
end
-- be sure to add this code line if you want to crete the mission;
-- exports['axr_gang-activities']:insertSingleMission(missionId, missionFunction);
---@type string unique and same as client side
local missionId <const> = 'custom_multiplayer_mission_exemple';
---comment
---@param playerSource integer -- leader indentifier
---@param missionData table
---@param lobbyData table
---@return table?nil, table?nil
local missionFunction = function(playerSource, missionData, lobbyData)
if not missionData then return print('ERROR: MissionData is nil') end;
local extraData = {};
local entities = {};
-- custom multiplayer missions for server side;
-- insert all the entities in entities table with table.insert(entities, {entityData}), so after the mission is finished/failed or resource is restarted the entities will be deleted
-- extraData need to contain all the entities informations created in server side such as: networkId, weaponName for npc enemy, extra mission data such as selected location/house etc
-- even if you are not using extraData and entities make sure to let it an empty table, = {}
-- make sure to set entities in virtual world if the missionData.setVirtualWorld = true;
-- example:
local npcEntity;
-- set entity in multiplayer mission virtual world;
-- lobbyData.bucket is generated on lobby created;
if missionData.setVirtualWorld then
local bucketId = lobbyData.bucket;
SetEntityRoutingBucket(npcEntity, bucketId);
else
SetEntityRoutingBucket(npcEntity, 0);
end
-- add this code lines to have all lobby memebers sources in client side;
extraData.missionPlayers = {};
for k, v in pairs(lobbyData.players) do
local playerSource = Framework.GetSourceFromIdentifier(v.identifier);
table.insert(extraData.missionPlayers, playerSource);
end
-- extraData.missionEvents is like the mission progress, for example extraData.missionEvents['event_1'] can be the task_1, task_2 or any condition to make progress in client side
extraData.missionEvents = {
['event_1'] = false,
}
-- extraInformations:
-- you can add custom RegisterServerEvents so you can sync missionEvents server side - client side for all players: example bellow
return extraData, entities;
end
RegisterServerEvent('axr_gang-activities:trySyncCustomMissionEvent_1', function(params)
local src = source;
local identifier = Framework.GetPlayerIdentifier(src);
if identifier then
local lobbyIndex = exports['axr_gang-activities']:getPlayerLobby(identifier);
if lobbyIndex and lobbies[lobbyIndex] then
if not lobbies[lobbyIndex].missionEvents then
lobbies[lobbyIndex].missionEvents = {};
end
if lobbies[lobbyIndex].missionEvents['event_1'] then
return;
end
lobbies[lobbyIndex].missionEvents['event_1'] = true;
TriggerClientEvent('axr_gang-activities:syncCustomMissionEvent_1', src); -- extra trigger event for client side
-- code exemple to update missionEvents for every lobby memeber;
for k, v in pairs(lobbies[lobbyIndex].players) do
local playerSource = Framework.GetSourceFromIdentifier(v.identifier);
TriggerClientEvent('axr_gang-activities:updateMissionEvents', playerSource, 'event_1', true);
end
end
end
end)
-- be sure to add this code line if you want to crete the mission;
-- exports['axr_gang-activities']:insertMultiplayerMission(missionId, missionFunction);
Create the client-side file for your mission.
Navigate to client/custom/missions/singleplayer/ or client/custom/missions/multiplayer/ and use the default template located there.
---@type string unique and same as server side
local missionId <const> = 'custom_mission_exemple';
---comment
---@param missionData table
---@param extraData table
local missionFunction = function(missionData, extraData)
if not missionData then return end;
if not extraData then return end;
-- custom singleplayer missions for client side;
-- use missionData and extraData from server side to take control of entities/ set multiple blips and make your mission as you want
inMissions = true -- need to set inMissions = true before creating mission overlay
-- create blip with createMissionBlip function
local blip;
local blipSetter = vector3(1834.9813232422,-1922.0208740234,149.18962097168); -- blip setter need to be entity or vector3 coord, set forEntity = true or coords = true in config/missions.lua for your mission as you want;
if missionData.blip then
blip = createMissionBlip(missionData.blip, blipSetter)
end
-- create and show mission overlay code:
local missionDataCopy = overlayFunctions.createMissionCopy(missionData);
overlayFunctions.createMissionOverlay(missionDataCopy);
overlayFunctions.createOverlaytoogleThread();
Citizen.CreateThread(function()
---@type table
local playerTempStats = {}
local condition = true;
local waiter = 1000;
local failed = false;
local failed_condition = false;
local taskParameter1, taskParameter2;
local condition_made_kill = false;
while condition do
Citizen.Wait(waiter);
-- add verification for mission tasks,
---@taskParameter1 any value you want (the logic for completing the task is made in config/missions.lua)
---@taskParameter2 any value you want (the logic for completing the task is made in config/missions.lua)
---@params count = mission tasks count
overlayFunctions.checkCompletedTasks(missionData, { taskParameter1, taskParameter2, });
if condition_made_kill then -- example to update player kills statistics. For more information check our documentation
playerTempStats['missions_kills'] = {
addValue = true,
value = 1
}
end
---@type boolean -- set failed_condition for your custom mission
if failed_condition then
failed = true;
end
-- break the mission and notify the player for failing it
if failed then
-- Notify(fail_message, notify_type)
break;
end
end
-- delete blips after mission failed/completed
if blip and missionData.blip then
RemoveBlip(blip)
end
inMissions = false -- be sure to set inMissions = false after mission failed/completed
-- respawn random player after failed/completed, coords can be added/edited in config/missions.lua
if missionData.endMissionRespawn then
respawnPlayerFromMission(missionData.respawnRandomPos, missionData.success)
end
-- destroy mission overlay;
overlayFunctions.destroyMissionOverlay();
-- be sure to add this TriggerServerEvent to update player statistics and give reward if missionData.success = true;
TriggerServerEvent('axr_gang-activities:finishMission', missionData, playerTempStats)
end)
end
-- be sure to add this code line if you want to crete the mission;
-- exports['axr_gang-activities']:insertSingleMission(missionId, missionFunction);
---@type string unique and same as server side
local missionId <const> = 'custom_multiplayer_mission_exemple';
---comment
---@param missionData table
---@param extraData table
---@param isLeader boolean
local missionFunction = function(missionData, extraData, isLeader)
if not missionData then return end;
if not extraData then return end;
-- custom singleplayer missions for client side;
-- use missionData and extraData from server side to take control of entities/ set multiple blips and make your mission as you want
-- use isLeader so you can take control of entities and edit them, example bellow
local netId;
local npcEntity;
if not netId then
return print("netId doesn't exist")
end
local timeout = GetGameTimer() + 5000
repeat
npcEntity = NetToPed(netId)
Wait(1)
until DoesEntityExist(npcEntity) or GetGameTimer() > timeout
if isLeader then
if not DoesEntityExist(npcEntity) then
print("❌ Error not exist in client-side")
return
end
SetPedCanRagdoll(npcEntity, true)
NetworkRequestControlOfEntity(npcEntity)
while not NetworkHasControlOfEntity(npcEntity) and GetGameTimer() < timeout do
Wait(10)
end
if not NetworkHasControlOfEntity(npcEntity) then
print("❌ Error getting entity control")
return
end
end
inMissions = true -- need to set inMissions = true before creating mission overlay
-- create blip with createMissionBlip function
local blip;
local blipSetter = vector3(1834.9813232422, -1922.0208740234, 149.18962097168); -- blip setter need to be entity or vector3 coord, set forEntity = true or coords = true in config/missions.lua for your mission as you want;
if missionData.blip then
blip = createMissionBlip(missionData.blip, blipSetter)
end
-- create and show mission overlay code:
local missionDataCopy = overlayFunctions.createMissionCopy(missionData);
overlayFunctions.createMissionOverlay(missionDataCopy);
overlayFunctions.createOverlaytoogleThread();
Citizen.CreateThread(function()
---@type table
local playerTempStats = {}
local condition = true;
local waiter = 1000;
local failed = false;
local failed_condition = false;
local taskParameter1, taskParameter2;
local condition_made_kill = false;
while condition do
Citizen.Wait(waiter);
-- add verification for mission tasks,
---@taskParameter1 any value you want (the logic for completing the task is made in config/missions.lua)
---@taskParameter2 any value you want (the logic for completing the task is made in config/missions.lua)
---@params count = mission tasks count
overlayFunctions.checkCompletedTasks(missionData, { taskParameter1, taskParameter2, });
if condition_made_kill then -- example to update player kills statistics. For more information check our documentation
playerTempStats['missions_kills'] = {
addValue = true,
value = 1
}
end
---@type boolean -- set failed_condition for your custom mission
if failed_condition then
failed = true;
end
-- break the mission and notify the player for failing it
if failed then
-- Notify(fail_message, notify_type)
break;
end
end
-- delete blips after mission failed/completed
if blip and missionData.blip then
RemoveBlip(blip)
end
inMissions = false -- be sure to set inMissions = false after mission failed/completed
-- respawn random player after failed/completed, coords can be added/edited in config/missions.lua
if missionData.endMissionRespawn then
respawnPlayerFromMission(missionData.respawnRandomPos, missionData.success)
end
-- destroy mission overlay;
overlayFunctions.destroyMissionOverlay();
-- be sure to add this TriggerServerEvent to update player statistics and give reward if missionData.success = true;
TriggerServerEvent('axr_gang-activities:finishMission', missionData, playerTempStats)
end)
end
-- be sure to add this code line if you want to crete the mission;
-- exports['axr_gang-activities']:insertMultiplayerMission(missionId, missionFunction);
Sync the logic between these files.
Now that you have created all three files, you need to implement the logic that will make the code behave like a mission.
Recommendation:
Store all mission data such as coordinates, rewards, ped/vehicle/prop codes inside the mission’s config table.
Create entities on the server-side.
Add entities to the global
entitiestable usingtable.insert(entities, entity).Return all necessary mission information inside the
extraDatatable so it can be used later on the client-side.On the client-side, ensure that entity control is assigned to a single client.
Use boolean parameters for tasks, or apply simple checks inside the task’s
completeFunction.Follow the existing templates to avoid issues with blip creation, mission overlay handling (start/stop), etc.
Use logical expressions to detect whether the mission has failed or not.
At the end of the mission, make sure to remove temporary blips, destroy the mission overlay, and clean up client-side entities. (On the server-side, entities are automatically removed.)
There is no need to manually set XP, level, rewards, or statistics at the end of a mission. Instead, use the default templates provided within the script or documentation and follow the corresponding instructions.
Last updated
Was this helpful?