8.0 KiB
Objectives and Tasks Guide
This guide covers how to add achievements and tasks to Break Escape scenarios using the objectives system.
Overview
The objectives system allows you to:
- Define Aims (high-level goals) containing multiple Tasks
- Track player progress through dialogue-triggered tags
- Lock/unlock aims and tasks dynamically via NPC conversations
- Trigger NPC conversations when objectives are completed
- Sync progress with the server for persistence
Quick Start
1. Define Objectives in scenario.json
{
"objectives": [
{
"id": "main_mission",
"title": "Primary Mission",
"description": "Complete the main objectives",
"status": "active",
"aims": [
{
"id": "gather_intel",
"title": "Gather Intelligence",
"status": "active",
"tasks": [
{
"id": "talk_to_alice",
"title": "Talk to Alice",
"status": "active"
},
{
"id": "talk_to_bob",
"title": "Talk to Bob",
"status": "locked"
}
]
},
{
"id": "secret_mission",
"title": "Secret Mission",
"status": "locked",
"tasks": [
{
"id": "secret_task_1",
"title": "Complete secret objective",
"status": "locked"
}
]
}
]
}
]
}
2. Control Objectives from Ink Dialogue
Use these Ink tags in your .ink files:
=== first_meeting ===
Great to meet you! This task is now complete.
#complete_task:talk_to_alice
You should go talk to Bob next - I just unlocked that task.
#unlock_task:talk_to_bob
-> hub
=== reveal_secret ===
I'll let you in on a secret mission...
#unlock_aim:secret_mission
The first task is now available.
#unlock_task:secret_task_1
-> hub
Ink Tags Reference
| Tag | Description | Example |
|---|---|---|
#complete_task:task_id |
Marks a task as completed | #complete_task:talk_to_alice |
#unlock_task:task_id |
Unlocks a locked task | #unlock_task:secret_task_1 |
#unlock_aim:aim_id |
Unlocks an entire aim | #unlock_aim:secret_mission |
Task Statuses
| Status | Description |
|---|---|
active |
Task is visible and can be completed |
locked |
Task is hidden until unlocked |
completed |
Task has been finished |
Event-Triggered Conversations
NPCs can automatically start conversations when objectives are completed:
{
"id": "alice",
"displayName": "Alice",
"storyPath": "scenarios/my_scenario/alice.json",
"eventMappings": [
{
"eventPattern": "objective_aim_completed:secret_mission",
"targetKnot": "final_debrief",
"autoTrigger": true,
"background": "assets/backgrounds/office.png"
}
]
}
Event Patterns
| Pattern | Fires When |
|---|---|
objective_aim_completed:aim_id |
Specific aim is completed |
objective_task_completed:task_id |
Specific task is completed |
objective_aim_completed |
Any aim is completed |
objective_task_completed |
Any task is completed |
Global Variables for Cross-NPC State
Define variables that sync across all NPC conversations:
{
"globalVariables": {
"alice_talked": false,
"bob_talked": false,
"secret_revealed": false
}
}
In Ink files, declare and use these variables:
// alice.ink
VAR alice_talked = false
VAR bob_talked = false
=== hub ===
+ {not alice_talked} [Nice to meet you]
-> first_meeting
+ {alice_talked and bob_talked} [What's next?]
-> next_steps
Important: Declare global variables in BOTH Ink files that use them.
Complete Example
scenario.json.erb
{
"scenario_brief": "Investigate the facility",
"startRoom": "lobby",
"globalVariables": {
"alice_talked": false,
"mission_complete": false
},
"objectives": [
{
"id": "investigation",
"title": "Investigation",
"status": "active",
"aims": [
{
"id": "gather_info",
"title": "Gather Information",
"status": "active",
"tasks": [
{
"id": "talk_to_alice",
"title": "Speak with Alice",
"status": "active"
},
{
"id": "find_evidence",
"title": "Find the evidence",
"status": "locked"
}
]
}
]
}
],
"rooms": {
"lobby": {
"type": "room_office",
"npcs": [
{
"id": "alice",
"displayName": "Alice",
"npcType": "person",
"position": { "x": 5, "y": 5 },
"storyPath": "scenarios/my_scenario/alice.json",
"eventMappings": [
{
"eventPattern": "objective_task_completed:find_evidence",
"targetKnot": "evidence_found",
"autoTrigger": true
}
]
}
]
}
}
}
alice.ink
VAR alice_talked = false
=== start ===
Hello there! Welcome to the facility.
-> hub
=== hub ===
+ {not alice_talked} [I need your help]
-> first_meeting
+ {alice_talked} [Any updates?]
-> check_progress
+ [I need to go]
See you later!
#exit_conversation
-> hub
=== first_meeting ===
Of course! Let me tell you what I know...
#complete_task:talk_to_alice
~ alice_talked = true
There's evidence hidden in the server room. I've unlocked that task for you.
#unlock_task:find_evidence
-> hub
=== check_progress ===
Have you found the evidence yet? Keep looking!
-> hub
=== evidence_found ===
// Triggered automatically when find_evidence task is completed
You found it! Excellent work, agent.
~ mission_complete = true
The investigation is complete.
#exit_conversation
-> hub
Best Practices
1. Use the Hub Pattern
Never use -> END in NPC dialogues. Always return to a hub:
=== hub ===
+ [Option 1] -> do_thing_1
+ [Option 2] -> do_thing_2
+ [Goodbye]
See you!
#exit_conversation
-> hub
2. Place Tags After Dialogue
Put objective tags after the dialogue line they relate to:
// ✅ Good - tag fires after player sees the text
Great work completing that task!
#complete_task:my_task
// ❌ Avoid - tag fires before text displays
#complete_task:my_task
Great work completing that task!
3. Chain Tasks Logically
Unlock the next task when completing the current one:
=== complete_first_task ===
You've finished the first part!
#complete_task:task_1
#unlock_task:task_2
Now you can move on to the next step.
-> hub
4. Use Conditional Choices
Show different options based on task status using global variables:
=== hub ===
+ {not task_1_done} [Start the mission]
-> begin_mission
+ {task_1_done and not task_2_done} [Continue the mission]
-> continue_mission
+ {task_2_done} [Finish up]
-> wrap_up
5. Provide Feedback
Always give the player clear feedback when objectives change:
=== unlock_secret ===
I've got something special for you...
#unlock_aim:secret_mission
Check your objectives - a new mission has appeared!
#unlock_task:secret_task_1
The first task is ready. Good luck!
-> hub
Debugging Tips
-
Check browser console for objective-related logs:
🎯 Task completed: task_id🔓 Task unlocked: task_id🔓 Aim unlocked: aim_id
-
Verify global variables are declared in all Ink files that use them
-
Test event triggers by watching for:
📡 Emitting event: objective_task_completed:task_id⚡ Event-triggered conversation: jumping to knot
-
Use the objectives panel (press
Oin-game) to see current status
Files Reference
| File | Purpose |
|---|---|
js/systems/objectives-manager.js |
Core objectives logic |
js/minigames/helpers/chat-helpers.js |
Tag processing |
js/systems/npc-conversation-state.js |
Global variable sync |
docs/GLOBAL_VARIABLES.md |
Global variables documentation |