Skip to main content

Quest System

A general quest pipeline built from Kill -> Talk -> Collect steps. It tracks progress through gameplay events and works for RPGs, casual games, and mission systems.

Structure

QuestSystem (pure C# instance)
- Manages active quests and routes events

QuestDefinition (ScriptableObject)
- Title, description, rewards
[SerializeReference] List<QuestStep>

QuestInstance (runtime)
- Current step index and completion state

QuestStep (abstract, [Serializable])
├── KillQuestStep - Kill N enemies of a type
├── TalkQuestStep - Talk to a specific NPC
└── CollectQuestStep - Collect N items of a type

Quick Start

1. Create a QuestDefinition

Create -> AchUtils/Quest/Quest Definition

QuestId : "MainQuest_01"
Title : "Slime Hunt"

Steps:
[0] KillQuestStep
EnemyType : "Slime"
RequiredCount : 5
[1] TalkQuestStep
NpcId : "GuardNPC"
[2] CollectQuestStep
ItemId : "SlimeGel"
RequiredCount : 3

Rewards:
[0] QuestReward { RewardId: "Gold", Amount: 500 }
[1] QuestReward { RewardId: "Exp", Amount: 200 }

2. Create a QuestSystem Instance

QuestSystem is a pure C# class that only owns quest state. Create it from the object that owns the quest flow.

3. Start a Quest

using AchUtils.Quest;

private readonly QuestSystem questSystem = new();

[SerializeField] QuestDefinition mainQuest01;

var instance = questSystem.StartQuest(mainQuest01);

instance.OnStepCompleted += step =>
Debug.Log($"Step {step} completed");

instance.OnQuestCompleted += () =>
GiveRewards(mainQuest01.Rewards);

4. Publish Events

Call Progress from anywhere in the game. Every active quest receives the event.

questSystem.Progress("Kill", "Slime");
questSystem.Progress("Talk", "GuardNPC");
questSystem.Progress("Collect", "SlimeGel");

Event Key Rules

Keydata argumentStep
"Kill"Enemy type stringKillQuestStep
"Talk"NPC ID stringTalkQuestStep
"Collect"Item ID stringCollectQuestStep

API

QuestSystem

QuestInstance StartQuest(QuestDefinition definition)

void Progress(string eventKey, object data = null)

bool IsCompleted(string questId)
bool IsActive(string questId)
QuestInstance GetActive(string questId)
List<QuestInstance> GetAllActive()

event Action<QuestInstance> OnQuestStarted
event Action<QuestInstance> OnQuestCompleted
event Action<QuestInstance, int> OnQuestStepCompleted

QuestInstance

QuestDefinition Definition
int CurrentStepIndex
bool IsCompleted
QuestStep CurrentStep

event Action<int> OnStepCompleted
event Action OnQuestCompleted

Custom Steps

[Serializable]
public class ReachLocationStep : QuestStep
{
public string LocationId;
private bool _reached;

public override bool IsComplete => _reached;

public override void OnProgress(string eventKey, object data)
{
if (eventKey == "ReachLocation" && data is string loc && loc == LocationId)
_reached = true;
}

public override void OnStart() => _reached = false;
}
questSystem.Progress("ReachLocation", "DungeonEntrance");

Duplicate Start Guard

The same QuestId cannot be started twice. Completed quests are not started again.

questSystem.StartQuest(mainQuest01);
questSystem.StartQuest(mainQuest01); // Ignored