Quests give survivors a reason to go somewhere and a story to follow. In EndCore a quest has a giver (a survivor NPC), a list of steps done in order, optional requirements, and rewards. Progress is decided on the server from real game events, so players can't fake finishing a step.
This guide adds a farmer named Marla and a repeatable daily task for her.
1. Add the quest giver
Survivors are defined in en-quests/data/npcs.lua, keyed by id:
marla = {
name = 'Marla',
title = 'Grapeseed Farm',
model = 'a_f_m_farmer_01',
coords = vec4(2440.0, 4975.0, 46.8, 90.0),
scenario = 'WORLD_HUMAN_GARDENER_PLANT',
greeting = { 'Fields don\'t tend themselves.' },
},| Field | What it does |
|---|---|
name | Name shown in dialogue |
title | A short line under the name |
model | Ped model |
coords | vec4 position and heading |
scenario | Optional idle scenario |
greeting | Lines they say when they have nothing for you |
blip | true always shows them on the map. Otherwise they only show while they have something for you. |
2. Write the quest
Quests are defined in en-quests/data/quests.lua, keyed by quest id (up to 60 characters). This file stays on the server; players never see quest definitions.
cloth_for_marla = {
label = 'Rags to Riches',
type = 'task',
giver = 'marla',
cooldownHours = 12,
description = 'Marla patches tarps for the farm and always needs cloth.',
offer = { 'Bring me cloth and clear the walkers off the east field.' },
requires = { level = 2 },
steps = {
{ type = 'kill', count = 8, label = 'Clear the east field', coords = vec3(2470.0, 4990.0, 45.0) },
{ type = 'collect', item = 'cloth', count = 15, label = 'Gather cloth' },
{ type = 'deliver', npc = 'marla', item = 'cloth', count = 15, label = 'Bring Marla the cloth',
dialog = { 'That\'ll hold the rain off. Here.' } },
},
rewards = {
cash = 120,
xp = 100,
items = { { item = 'canned_beans', count = 2 } },
skills = { scavenging = 10 },
},
},Quest fields
| Field | What it does |
|---|---|
label | Name in the offer, tracker and journal |
description | Longer text in the journal |
type | story (once, often chained), side (once) or task (repeatable) |
giver | The npc id who offers it |
offer | Lines the giver says before offering it |
cooldownHours | Tasks only: hours before it can be taken again. Defaults to 24. |
requires | Any of level = n, skill = { name, level } and quests = { ids } |
rewards | Any of cash, xp (character XP), items = { { item, count } } and skills = { [skill] = xp } |
steps | Ordered list of steps |
Step types
Every step has a label for the tracker. Any step can also have a hint (a longer journal line) and coords (a waypoint players can set from the journal).
| Type | Fields | Done when |
|---|---|---|
talk | npc, dialog | The player talks to that survivor |
deliver | npc, item, count, dialog | The player hands the items over. They are taken. |
collect | item, count | The player is carrying them. They are kept. |
reach | coords (required), radius (default 10, 1 to 500) | The player gets there. The server re-checks the distance. |
kill | count, optional zombie type such as 'runner' | Enough zombies are killed |
search | count | Enough zombie corpses are searched |
craft | count, and recipe (an en-crafting recipe id) or item (the result item) | Enough are crafted |
With Config.partyCredit = true (the default), kills and searches also count for nearby party members on the same step.
Chaining quests
Use requires.quests to make a story chain. The shipped clean_water quest only unlocks after first_steps:
requires = { quests = { 'first_steps' } },3. Restart and test
Restart en-quests (or the server). Marla appears at the farm with a marker while she has something for you. Talk to her, accept the task, and press F5 to open the journal.
A few limits to keep in mind while testing:
- Players can have 3 quests active at once (
Config.maxActive). - Story and side quests can only be done once.
- Reward items that don't fit are reported as "No room for ..." and not given, so keep item rewards small.
To run a quest again on the same character, reset it:
/resetquest 1 cloth_for_marla4. Or build it in game
Both survivors and quests can be created live from the admin panel:
- Press F10, open the Build tab and choose Quest NPCs.
- Choose New, fill in the name, model and greeting, and press Use my position where they should stand. Save.
- Switch to Quests and choose New.
- Fill in the name, type, giver, offer lines, requirements and rewards.
- Add steps. Each step has a type, tracker label, hint, survivor, item, count and recipe field; fill in the ones that step type uses.
- Save. en-quests checks that the giver and every step's survivor exist before accepting it.
A placed quest or survivor with the same id as a config one replaces it, and deleting it restores the config version. Editing a quest keeps players' progress, clamped to the new number of steps.
5. Custom objectives from code
The built-in step types cover most quests. For anything else, your own resource can move a quest on with AdvanceQuest:
- On a
kill,searchorcraftstep, it addsamount(default 1) to the count. - On any other step type, it finishes the current step.
It always acts on the player's current step, so the safest pattern is a quest whose custom objective is its only step, or the step you know is current.
Here is a daily task where searching dumpsters (from the resource in Writing a resource) counts as searching:
-- en-quests/data/quests.lua
dumpster_diver = {
label = 'Dumpster Diver', type = 'task', giver = 'marla', cooldownHours = 20,
description = 'Marla wants to know what the town threw away.',
offer = { 'Check the dumpsters in Grapeseed. Five of them.' },
steps = {
{ type = 'search', count = 5, label = 'Search dumpsters', hint = 'Look at a dumpster and hold Alt.' },
},
rewards = { cash = 60, xp = 50 },
},-- my-scavenge/server/main.lua, after a successful dumpster search
if GetResourceState('en-quests') == 'started'
and exports['en-quests']:IsQuestActive(source, 'dumpster_diver') then
exports['en-quests']:AdvanceQuest(source, 'dumpster_diver', 1)
endZombie corpse searches still count toward this step too, because it is a search step.
Reacting to quest events
en-quests fires server events you can use for announcements, achievements or unlocking other content:
| Event | Payload |
|---|---|
en-quests:server:started | source, questId |
en-quests:server:stepChanged | source, questId, stepIndex |
en-quests:server:completed | source, questId |
AddEventHandler('en-quests:server:completed', function(source, questId)
if questId == 'first_steps' then
encore.notify(-1, {
title = 'Burton Checkpoint',
description = ('%s has been vouched for.'):format(exports['en-core']:GetCharacterName(source)),
})
end
end)Use exports['en-quests']:HasCompletedQuest(source, questId) to gate your own features on quest progress.
Related
- en-quests: full reference.
- Add an item: create quest items and rewards.
- en-crafting: recipe ids for
craftsteps.