Am I using Quest State Listener and Persistent Active Data redundantly?

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
gewl
Posts: 5
Joined: Mon Sep 14, 2020 7:03 pm

Am I using Quest State Listener and Persistent Active Data redundantly?

Post by gewl »

Hi,

I'm using Dialogue System and populating dialogue & quest content from Articy. I'm trying to keep as much logic out of Lua and inspector strings as possible for my own sanity; my current structure is that I make heavy use of Dialogue System's eventing & observer components to handle state changes, and use my own coroutines, callbacks, etc., to handle sequencing. I'm just now really digging into Dialogue System's components, though, and I want to make sure I'm not misusing them.

Also, sorry in advance for this being a little hairy—it's a hard thing to put concisely!

Let's say I have the following sequence of events in my game:
  1. Player interacts with Object, which turns Quest A from Active to Success.
  2. NPC becomes active next to the player.
  3. When the player and NPC are done talking, NPC runs away.
  4. When NPC is out of sight, they are deactivated, and Quest B is changed from Unassigned to Active.
  5. If the game or scene is loaded while Quest A is Successful and Quest B is Unassigned, NPC should be active. Otherwise, they should be inactive.
Here is how I'm handling each of those things, respectively:
  1. Player interacts with Object, which turns Quest A from Active to Success: Object has a DialogueSystemTrigger. Trigger: OnUse, Action: Set Quest A state to Success.
  2. NPC becomes active next to the player: A separate object has a Quest State Listener. When Quest A is set to Success, this Listener sets NPC to Active.
  3. When the player and NPC are done talking, NPC runs away: NPC has a Dialogue Actor component and a DialogueSystemTrigger. Trigger: OnConversationEnd, Action: Begin my 'run away' coroutine.
  4. When NPC is out of sight, they are deactivated, and Quest B is changed from Unassigned to Active: Exposed UnityAction callback is invoked at the end of my 'run away' coroutine. This calls an OnUse DialogueSystemTrigger, which sets QuestB to Active and deactivates NPC.
  5. If the game or scene is loaded while Quest A is Successful and Quest B is Unassigned, NPC should be active. Otherwise, they should be inactive: A separate object has a PersistentActiveData component pointing at NPC. Conditions: Quest A state = Success, Quest B state =Active
If anything about this seems wrong I'd love to know, but what I'm specifically interested in is:

(Should NPC be active) is equal to eval of (Quest A == Success && Quest B == Active).

In (2), I have a QuestStateListener that is listening for (Quest A == Success), but only on quest state change.
In (4), I have a DialogueSystemTrigger that is setting my NPC inactive 'arbitrarily'—it's at the same time as it sets (Quest B = Active), but not tied to the quest logic.
In (5), I have a PersistentActiveData that is listening for (Quest A == Success && Quest B == Active), but only on scene/game load.

To me, it seems like this could be simplified if there were one component that were listening to quest state change and scene/game load, and would set NPC.SetActive(Quest A == Success && Quest B == Active). Is there a way of doing that, or a better way of paring down my logic?

Thanks!
User avatar
Tony Li
Posts: 22154
Joined: Thu Jul 18, 2013 1:27 pm

Re: Am I using Quest State Listener and Persistent Active Data redundantly?

Post by Tony Li »

Hi,

That should work, but I have some suggestions:

If you're using the Dialogue System's full save system, I recommend using an Active Saver instead of a Persistent Active Data component. The Persistent*Data components are the "older" style components that work directly with the Dialogue System's Persistent Data Manager. If you're using the full save system, the PersistentDataManager and Persistent*Data components have been rolled into the save system.

I don't think you're covering the case where you save the game while the NPC has started to run away but hasn't disappeared yet. When you reload the game at that point, the NPC should teleport to the position it was in when you saved the game, and it should resume its run-away coroutine. You could write a custom saver component to save the NPC's state. (Start by duplicating SaverTemplate.cs.)

Using a Quest State Listener is fine for what you're doing. If you don't want to use a Quest State Listener, you could add a Dialogue System Events component to the Dialogue Manager GameObject. Then write a script that registers a method with the Dialogue Manager's DialogueSystemEvents.questEvents.onQuestStateChange. Something like:

Code: Select all

[QuestPopup] public string questA;
[QuestPopup] public string questB;

void OnEnable()
{
    var dsEvents = DialogueManager.instance.GetComponent<DialogueSystemEventS>();
    dsEvents.questEvents.onQuestStateChange.AddListener(CheckQuests);
}

void OnEnable()
{
    var dsEvents = DialogueManager.instance.GetComponent<DialogueSystemEventS>();
    dsEvents.questEvents.onQuestStateChange.RemoveListener(CheckQuests);
}

void HandleQuestChange(string questName)
{
    if (questName == questA && QuestLog.IsQuestActive(questA))
    {
        ActivateNPC();
    } etc...
}
Post Reply