Quest System Guide
The quest system manages quest lifecycle, listens to event bus events, and tracks objective progress.
Architecture
UERPQuestBase (Abstract)
├── UERPSimpleQuest ← UERPSimpleQuestDefinition (DataAsset)
├── UERPBlueprintQuest (Blueprintable)
└── (Future: UERPGraphQuest)
The UERPQuestSubsystem manages all active quests and routes events to them. Each quest type implements its own ProcessEvent logic.
Quest Lifecycle
Inactive ──Activate()──► Active ──Complete()──► Completed
│
└──Fail()──► Failed
Simple Quests (DataAsset)
Creating a Definition
- Content Browser > Right-click > Miscellaneous > Data Asset
- Select
ERPSimpleQuestDefinition - Fill in the fields:
| Field | Description |
|---|---|
| Display Name | Shown in UI |
| Description | Detailed text for the journal |
| Quest Tags | GameplayTags for categorization |
| Tracked By Default | Show on HUD when activated |
| Sequential | Objectives unlock one by one (vs. all at once) |
| Objectives | List of FERPObjectiveDefinition |
| Completion Event Tag | Broadcast on the event bus when quest completes |
| Failure Event Tag | Broadcast on the event bus when quest fails |
Objective Definition
| Field | Description |
|---|---|
| ObjectiveId | Unique name within the quest |
| DisplayText | Shown in UI (e.g., "Kill 5 goblins") |
| EventTag | Which event bus tag progresses this objective |
| RequiredCount | How many events needed to complete |
Starting a Simple Quest
UERPQuestSubsystem* QS = GetWorld()->GetSubsystem<UERPQuestSubsystem>();
UERPQuestBase* Quest = QS->StartQuestFromDefinition(MyDefinition);
How Events Progress Objectives
- Game broadcasts
Enemy.Killedon the event bus - Quest subsystem routes the event to all active quests
UERPSimpleQuest::ProcessEventchecks each active objective- If the objective's
EventTagmatches, increment its counter - If counter reaches
RequiredCount, mark objective complete - If sequential, unlock the next locked objective
- If all objectives complete, auto-complete the quest
- Completion broadcasts the
CompletionEventTagon the bus
Blueprint Quests
For quests that need custom logic beyond simple event counting:
- Create a Blueprint child of
ERPBlueprintQuest - Override
ProcessEvent— handle events your way - Override
GetProgress— return 0.0-1.0 - Override
GetCurrentObjectives— return objective info for UI - Override
Activate/Complete/Failfor custom lifecycle
Example: Timed Quest
// In BP override of ProcessEvent:
// - Start a timer on Activate
// - Check timer in ProcessEvent
// - Auto-fail if time runs out
Starting a Blueprint Quest
UERPBlueprintQuest* Quest = NewObject<UERPBlueprintQuest>(this, MyBPQuestClass);
Quest->DisplayName = FText::FromString("Timed Challenge");
QS->StartQuest(Quest);
Quest Subsystem API
Queries
UERPQuestSubsystem* QS = GetWorld()->GetSubsystem<UERPQuestSubsystem>();
// Get all active quests
TArray<UERPQuestBase*> Active = QS->GetActiveQuests();
// Get tracked quests (for HUD)
TArray<UERPQuestBase*> Tracked = QS->GetTrackedQuests();
// Find a specific quest
UERPQuestBase* Quest = QS->FindQuest(QuestId);
// Get quests by state
TArray<UERPQuestBase*> Completed = QS->GetQuestsByState(EERPQuestState::Completed);
Management
// Fail a quest
QS->FailQuest(QuestId);
// Abandon (remove from tracking)
QS->AbandonQuest(QuestId);
// Toggle tracking
QS->SetQuestTracked(QuestId, true);
Events
// Any quest state change
QS->OnAnyQuestStateChanged.AddDynamic(this, &AMyClass::OnQuestChanged);
// void OnQuestChanged(UERPQuestBase* Quest, EERPQuestState NewState)
// Any objective progress
QS->OnAnyObjectiveProgressed.AddDynamic(this, &AMyClass::OnObjective);
// void OnObjective(UERPQuestBase* Quest, const FERPObjectiveInfo& Info)
Extending: Custom Quest Types
Create your own quest type by extending UERPQuestBase:
UCLASS(BlueprintType)
class UMyGraphQuest : public UERPQuestBase
{
GENERATED_BODY()
// Your node graph data...
UPROPERTY() TArray<UMyQuestNode*> Nodes;
virtual bool ProcessEvent_Implementation(FGameplayTag Tag, const FERPEventPayload& Payload) override
{
// Route event to your graph nodes
// Return true if the quest progressed
}
virtual float GetProgress_Implementation() const override
{
// Calculate progress from graph state
}
virtual TArray<FERPObjectiveInfo> GetCurrentObjectives_Implementation() const override
{
// Build objective list from current graph node
}
};
The quest subsystem doesn't know or care about the internal structure — it only calls the abstract interface.
Next Steps
- Event Bus Guide — Event system details
- Widget Guide — UI for quest display
- API Reference — Complete quest API