How to Structure a Quest System Using “Switch on Int” Across Multiple Blueprints (BP_NPC, BP_OpenDoor, BP_GetItem)?

I’m working on a simple narrative quest system using “Switch on Int” in Blueprints. It’s not an adventure game—just small task-based quests like shopping errands.

Here’s a simplified example of the task order I want:

  1. Talk to an NPC (BP_NPC) to receive the quest
  2. Open the front door (BP_OpenDoor)
  3. Interact with an item in a shop (BP_GetItem)
  4. Return and open the front door again

These tasks should only be completed in sequence. If the player tries to open the door before talking to the NPC, or get the item before opening the door, it should not be allowed.

My current approach:

  • I’m using a Switch on Int node to control quest progression.
  • Each task corresponds to a case/pin on the switch (e.g., 1 = BP_NPC, 2 = BP_OpenDoor, etc.).
  • After completing one task, I increment an integer variable (CurrentQuestStep), and the next case becomes available.

My main questions:

  1. Where should I manage the “Switch on Int” logic and CurrentQuestStep variable?
    Should it be in the player, GameMode, or a QuestManager Blueprint?
  2. How can I cleanly communicate between Blueprints like BP_NPC, BP_OpenDoor, and BP_GetItem?
    They are separate actors and do not inherit from each other, so casting isn’t ideal.
    I know using “Get All Actors of Class” can be performance-heavy, so I want to avoid that.
  3. I tried using Blueprint Interfaces (BPI), but I’m confused about how to get the correct target reference.
    For example, from BP_OpenDoor, how do I notify BP_GetItem that the door has been opened and it can now be interacted with?

I’m looking for the most modular and performance-friendly way to manage quest steps across multiple actor Blueprints, while ensuring the correct task order is enforced.

Any tips on structure, best practices, or communication patterns would be greatly appreciated!

Hi there,

If this is a system that will have non linear progression, linear gates and so on there would be much more needed.

However approach wise its fundamentally right direction you are.

1- I would recommend its own class, preferable a game instance subsystems as UQuestDirectorSubsystem, that can have additional modules and easier to talk with overarching systems in your game.

2-All these systems can call specific functions or events on your subsystem. Simply you can have an interacted function to call from your actors with reference and maybe some enums. Subsystem->CallObjectUpdate->Door(Interacted/Sleeping/Disabled)

3- Yes there will be many updates and events through your architecture. It can get complex in no time, like you would want to know what door opened with what item. You can have a struct to pass payloads to your subsytem for that or instigator to know if its player A or B for a multiplayer game, can be more. Use subsytem also an interface if you prefer with generic evens and functions. Actor reference and status, maybe payload.

However couple of things to mention. Interactions fundamentally is another system that can live encapsulated.
Ex: Door Interactions with Key doesn’t have to know quest state but you can require door to know quest state (as you described). If there is a valid key then door can open. —> Upon opening door can inform quest subsystem of the status change. —> When status changed of that quest in the subsyems couple of things can happen

A: Finish quest - > UI updates, experience etc.
B: Progress → New objective, UI updates etc.

After saying all of above
In your system;

Door → CanOpenFunction()


Function CanOpen(Player):

    Subsystem = GetQuestDirectorSubsystem(UQuestDirectorSubsystem)

    If Subsystem.CanDoorBeOpened(thisDoor) == false:
        Return false

    If Player.HasItem(RequiredKey) == false:
        Return false

    OpenDoor()

    // I would recommend doing notify or call function after interaction turns success though not in door but interactions system however its below.

    Subsystem.NotifyDoorOpened(thisDoor)

    Return true

In that terms door checks key and quest status and UQuestDirectorSubsystem is the bookkeeper. However i would also recommend a data table for each quest for ease of access and designer friendly structures.

Also would be easier to track of your data tables as, current quests, current stage, completed quests, uncompleted, locked and unlocked quests etc. That would be crucial to save game system and general playability of player experience.

Hope it helps and let me know.

An additional description of how gameplay systems should talk to each other with this architecture in mind on high level design.

  • NPC Interacted (Subsystem ->CallObjectUpdate(NPC, Interacted) → Quest Substems Steps (1/4)
  • Door Interacted - > Open ->Subsystem ->CallObjectUpdate(Door, Interacted) → Quest Substems Steps (2/4)
  • Item Interacted - > Inventory Add-> Subsystem ->CallObjectUpdate(Item, Interacted/Picked)-> Quest Substems Steps (3/4)
  • Reach Position- > Distance Lower than X - Event-> Subsystem ->CallObjectUpdate(Player, Interacted)-> Quest Substems Steps (4/4)

On each step :

  • NPC Interacted (Subsystem ->CallObjectUpdate(NPC, Interacted) →
    Subsystem

If Actor == NPC and QuestStep == 1 → Step++
If Actor == Door and QuestStep == 2 → Step++
If Actor == Item and QuestStep == 3 → Step++
If Actor == Position and QuestStep == 4 → Step++

simply on update quest subsystem asks if this is
current quest step?
current actor?
valid → go next

a manager class is a good idea (Subsystem, GameState Component, or even a spawned Actor/UObject)
GameState Component is probably the easiest place to start.

the manager shouldnt handle the quests though, it should handle creating/destroying quests by class as say a UObject and communication between them.

ie
static GetQuestByClass(subclass)
{
GetGameState->GetManagerComponent->FindOrCreateQuest(subclass)
}

then the class itself handles the logic which really depends on your game.

so in your example OnTalkToNPC ->GetQuestByClass()->if (QuestProgress=0)->Progress++.
on OpenDoor->GetQuestByClass()->if (QuestProgress=1)->Progress++ etc.

using a class based quest progress makes it easy to save/load and add UI information such as quest progress

Yes agreed, that would make general architecture more robust and more extendable.

Most of the narrative driven games and plugins use this approach, generally other objects that handles the progression. This type of approach is extendable into node based designs and story graph quest systems.

However if you are not going for those and deeper logic (just a simple system as you mentioned) it is not strictly necessary for now, can be extended into that architecture when you need.

Still even its a smaller system, you need to think around how save game will work in a data driven quests as mentioned.