mirror of
https://github.com/cliffe/BreakEscape.git
synced 2026-02-21 11:18:08 +00:00
feat: Add comprehensive Objectives and Tasks Guide with examples and best practices
This commit is contained in:
360
docs/OBJECTIVES_AND_TASKS_GUIDE.md
Normal file
360
docs/OBJECTIVES_AND_TASKS_GUIDE.md
Normal file
@@ -0,0 +1,360 @@
|
||||
# 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
|
||||
|
||||
```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:
|
||||
|
||||
```ink
|
||||
=== 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```json
|
||||
{
|
||||
"globalVariables": {
|
||||
"alice_talked": false,
|
||||
"bob_talked": false,
|
||||
"secret_revealed": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In Ink files, declare and use these variables:
|
||||
|
||||
```ink
|
||||
// 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
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
```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:
|
||||
|
||||
```ink
|
||||
=== 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:
|
||||
|
||||
```ink
|
||||
// ✅ 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:
|
||||
|
||||
```ink
|
||||
=== 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:
|
||||
|
||||
```ink
|
||||
=== 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:
|
||||
|
||||
```ink
|
||||
=== 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
|
||||
|
||||
1. **Check browser console** for objective-related logs:
|
||||
- `🎯 Task completed: task_id`
|
||||
- `🔓 Task unlocked: task_id`
|
||||
- `🔓 Aim unlocked: aim_id`
|
||||
|
||||
2. **Verify global variables** are declared in all Ink files that use them
|
||||
|
||||
3. **Test event triggers** by watching for:
|
||||
- `📡 Emitting event: objective_task_completed:task_id`
|
||||
- `⚡ Event-triggered conversation: jumping to knot`
|
||||
|
||||
4. **Use the objectives panel** (press `O` in-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 |
|
||||
Reference in New Issue
Block a user