Search Unity

[RELEASED] Dialogue System for Unity - easy conversations, quests, and more!

Discussion in 'Assets and Asset Store' started by TonyLi, Oct 12, 2013.

  1. nichjaim

    nichjaim

    Joined:
    Apr 23, 2020
    Posts:
    40
    I need options for skipping/speeding through dialogues, how is this usually handled and what's the best way to go about it with this system when certain dialogue nodes need to be shown (for like needed player choice or something). Like does this system have any built-in way to either speed through dialogue and stop at certain nodes? or just straight up skip to certain nodes? Sorry for so many questions, I looked in the docs but couldn't find exactly what I was looking for.
     
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi @nichjaim - The free Visual Novel Starter Framework available on the Dialogue System Extras page has a ConversationControl script. Enough people have asked for this functionality that it's been moved into the core Dialogue System release in the upcoming version 2.2.19. Here's an advance copy. To use it, add the ConversationControl script to your dialogue UI.
    • To toggle auto-play (i.e., don't wait for continue button), call the ToggleAutoPlay() method (e.g., in a UI Button's OnClick() event).
    • To skip all text until the next player response menu, call SkipAll().
     

    Attached Files:

    nichjaim likes this.
  3. SOSolacex

    SOSolacex

    Joined:
    Jan 10, 2018
    Posts:
    120
    Hey, looks like the cache barking lines was the culprit; ticking that option works for any kind of other barks, but it doesn't for bark on idle it seems. Unticking it allowed it to work.

    Small other, very noob at C# question...

    There's the SaveSystemManagerNoDisk class derived from SaveSystemManager (UIS). I'd like to reference that in the SaveMenu.cs to replace it with the SaveSystemManager (As I want to use the pixelcrusher's saving system while using the UIS save menu) but I am generally only decent at scripting some basic stuff / intermediate stuff that doesn't really have anything to do with assemblies, namespaces etc.

    I've been trying to wrap my head around it a little but to no luck.

    So basically I've replaced this:


    Code (CSharp):
    1. namespace Opsive.UltimateInventorySystem.UI.Panels.Save
    2. {
    3.     using Opsive.Shared.Utility;
    4.     using Opsive.UltimateInventorySystem.ItemActions;
    5.     using Opsive.UltimateInventorySystem.SaveSystem;
    6.     using Opsive.UltimateInventorySystem.UI.Grid;
    7.     using Opsive.UltimateInventorySystem.UI.Panels.ActionPanels;
    8.     using UnityEngine;
    9.  
    10.     /// <summary>
    11.     /// The Grid UI used for the save menu.
    12.     /// </summary>
    13.     public class SaveGrid : GridGeneric<SaveData>
    14.     {
    15.         [Tooltip("The action panel.")]
    16.         [SerializeField] protected SettableActionPanel m_ActionPanel;
    17.         [Tooltip("The confirmation pop up.")]
    18.         [SerializeField] protected ConfirmationPopUp m_ConfirmationPopUp;
    19.  
    20.         protected ResizableArray<SaveData> m_SaveDatas;
    21.         protected SettableActionElement[] m_SettableActions;
    22.  
    23.         private int m_SelectedIndex;
    24.         private SaveData m_SelectedSaveData;
    25.  
    26.         /// <summary>
    27.         /// Initialize the components.
    28.         /// </summary>
    29.         public override void Initialize(bool force)
    30.         {
    31.             if (m_IsInitialized && force == false) { return; }
    32.  
    33.             base.Initialize(force);
    34.  
    35.             m_SaveDatas = new ResizableArray<SaveData>();
    36.  
    37.             m_SettableActions = new SettableActionElement[3];
    38.             m_SettableActions[0] = new SettableActionElement("Save",
    39.                 () =>
    40.                 {
    41.                     if (m_SelectedIndex > SaveSystemManager.MaxSaves) {
    42.                         Debug.LogWarning($"The max saves data '{SaveSystemManager.MaxSaves}' is smaller than the selected index {m_SelectedIndex}. Please set a higher max saves amount.");
    43.                         return;
    44.                     }
    45.  
    46.                     if (m_SaveDatas[m_SelectedIndex] == null) {
    47.                         SaveSystemManager.Save(m_SelectedIndex);
    48.                         Refresh();
    49.                         return;
    50.                     }
    51.  
    52.                     m_ConfirmationPopUp.SetTitle("Are you sure you want to overwrite this save file?");
    53.                     m_ConfirmationPopUp.SetConfirmAction(() =>
    54.                     {
    55.                         SaveSystemManager.Save(m_SelectedIndex);
    56.                         Refresh();
    57.                     });
    58.                     m_ConfirmationPopUp.Open(m_ParentPanel, m_GridEventSystem.GetSelectedButton());
    59.  
    60.                 }, () => true);
    61.             m_SettableActions[1] = new SettableActionElement("Load",
    62.                 () =>
    63.                 {
    64.                     m_ConfirmationPopUp.SetTitle("Are you sure you want to load this file?");
    65.                     m_ConfirmationPopUp.SetConfirmAction(
    66.                         () =>
    67.                         {
    68.                             SaveSystemManager.Load(m_SelectedIndex);
    69.                             Refresh();
    70.                         });
    71.                     m_ConfirmationPopUp.Open(m_ParentPanel, m_GridEventSystem.GetSelectedButton());
    72.                 }, () => m_SelectedSaveData != null);
    73.             m_SettableActions[2] = new SettableActionElement("Delete",
    74.                 () =>
    75.                 {
    76.                     m_ConfirmationPopUp.SetTitle("Are you sure you want to delete this save file?");
    77.                     m_ConfirmationPopUp.SetConfirmAction(
    78.                         () =>
    79.                         {
    80.                             SaveSystemManager.DeleteSave(m_SelectedIndex);
    81.                             Refresh();
    82.                         });
    83.                     m_ConfirmationPopUp.Open(m_ParentPanel, m_GridEventSystem.GetSelectedButton());
    84.                 }, () => m_SelectedSaveData != null);
    85.  
    86.             m_ActionPanel.AssignActions(m_SettableActions);
    87.  
    88.             if (m_ActionPanel != null) {
    89.                 m_ActionPanel.Close();
    90.             }
    91.  
    92.             OnElementClicked += OnSaveElementButtonClick;
    93.             OnEmptyClicked += OnEmptyButtonClicked;
    94.         }
    95.  
    96.         /// <summary>
    97.         /// Refresh the view.
    98.         /// </summary>
    99.         public override void Refresh()
    100.         {
    101.             m_SaveDatas.Clear();
    102.             m_SaveDatas.AddRange(SaveSystemManager.GetSaves());
    103.             if (m_SaveDatas.Count < SaveSystemManager.MaxSaves) {
    104.                 for (int i = m_SaveDatas.Count; i < SaveSystemManager.MaxSaves; i++) {
    105.                     m_SaveDatas.Add(null);
    106.                 }
    107.             }
    108.             SetElements(m_SaveDatas);
    109.  
    110.             base.Refresh();
    111.         }
    112.  
    113.         /// <summary>
    114.         /// Click a button in the grid.
    115.         /// </summary>
    116.         /// <param name="saveData">The save data.</param>
    117.         /// <param name="index">The index.</param>
    118.         private void OnSaveElementButtonClick(SaveData saveData, int index)
    119.         {
    120.             m_SelectedIndex = index + m_StartIndex;
    121.             m_SelectedSaveData = saveData;
    122.             m_ActionPanel.Open(m_ParentPanel, GetButton(index));
    123.         }
    124.  
    125.         /// <summary>
    126.         /// Click an empty button in the grid.
    127.         /// </summary>
    128.         /// <param name="index">The index.</param>
    129.         private void OnEmptyButtonClicked(int index)
    130.         {
    131.             m_SelectedIndex = index;
    132.             m_SelectedSaveData = null;
    133.             m_ActionPanel.Open(m_ParentPanel, GetButton(index));
    134.         }
    135.     }
    136. }
    With this so far
    Code (CSharp):
    1. namespace Opsive.UltimateInventorySystem.UI.Panels.Save
    2. {
    3.     using Opsive.Shared.Utility;
    4.     using Opsive.UltimateInventorySystem.ItemActions;
    5.     using Opsive.UltimateInventorySystem.SaveSystem;
    6.     using Opsive.UltimateInventorySystem.UI.Grid;
    7.     using Opsive.UltimateInventorySystem.UI.Panels.ActionPanels;
    8.     using UnityEngine;
    9.     using PixelCrushers;
    10.  
    11.     /// <summary>
    12.     /// The Grid UI used for the save menu.
    13.     /// </summary>
    14.     public class PixSaveGrid : GridGeneric<SaveData>
    15.     {
    16.         [Tooltip("The action panel.")]
    17.         [SerializeField] protected SettableActionPanel m_ActionPanel;
    18.         [Tooltip("The confirmation pop up.")]
    19.         [SerializeField] protected ConfirmationPopUp m_ConfirmationPopUp;
    20.  
    21.         protected ResizableArray<SaveData> m_SaveDatas;
    22.         protected SettableActionElement[] m_SettableActions;
    23.  
    24.         private int m_SelectedIndex;
    25.         private SaveData m_SelectedSaveData;
    26.  
    27.         /// <summary>
    28.         /// Initialize the components.
    29.         /// </summary>
    30.         public override void Initialize(bool force)
    31.         {
    32.             if (m_IsInitialized && force == false) { return; }
    33.  
    34.             base.Initialize(force);
    35.  
    36.             m_SaveDatas = new ResizableArray<SaveData>();
    37.  
    38.             m_SettableActions = new SettableActionElement[3];
    39.             m_SettableActions[0] = new SettableActionElement("Save",
    40.                 () =>
    41.                 {
    42.                     if (m_SelectedIndex > SaveSystemManager.MaxSaves) {
    43.                         Debug.LogWarning($"The max saves data '{SaveSystemManager.MaxSaves}' is smaller than the selected index {m_SelectedIndex}. Please set a higher max saves amount.");
    44.                         return;
    45.                     }
    46.  
    47.                     if (m_SaveDatas[m_SelectedIndex] == null) {
    48.                         SaveSystem.SaveToSlot(m_SelectedIndex);
    49.                         Refresh();
    50.                         return;
    51.                     }
    52.  
    53.                     m_ConfirmationPopUp.SetTitle("Are you sure you want to overwrite this save file?");
    54.                     m_ConfirmationPopUp.SetConfirmAction(() =>
    55.                     {
    56.                         SaveSystem.SaveToSlot(m_SelectedIndex);
    57.                         Refresh();
    58.                     });
    59.                     m_ConfirmationPopUp.Open(m_ParentPanel, m_GridEventSystem.GetSelectedButton());
    60.  
    61.                 }, () => true);
    62.             m_SettableActions[1] = new SettableActionElement("Load",
    63.                 () =>
    64.                 {
    65.                     m_ConfirmationPopUp.SetTitle("Are you sure you want to load this file?");
    66.                     m_ConfirmationPopUp.SetConfirmAction(
    67.                         () =>
    68.                         {
    69.                             SaveSystem.LoadFromSlot(m_SelectedIndex);
    70.                             Refresh();
    71.                         });
    72.                     m_ConfirmationPopUp.Open(m_ParentPanel, m_GridEventSystem.GetSelectedButton());
    73.                 }, () => m_SelectedSaveData != null);
    74.             m_SettableActions[2] = new SettableActionElement("Delete",
    75.                 () =>
    76.                 {
    77.                     m_ConfirmationPopUp.SetTitle("Are you sure you want to delete this save file?");
    78.                     m_ConfirmationPopUp.SetConfirmAction(
    79.                         () =>
    80.                         {
    81.                             SaveSystem.DeleteSavedGameInSlot(m_SelectedIndex);
    82.                             Refresh();
    83.                         });
    84.                     m_ConfirmationPopUp.Open(m_ParentPanel, m_GridEventSystem.GetSelectedButton());
    85.                 }, () => m_SelectedSaveData != null);
    86.  
    87.             m_ActionPanel.AssignActions(m_SettableActions);
    88.  
    89.             if (m_ActionPanel != null) {
    90.                 m_ActionPanel.Close();
    91.             }
    92.  
    93.             OnElementClicked += OnSaveElementButtonClick;
    94.             OnEmptyClicked += OnEmptyButtonClicked;
    95.         }
    96.  
    97.         /// <summary>
    98.         /// Refresh the view.
    99.         /// </summary>
    100.         public override void Refresh()
    101.         {
    102.             m_SaveDatas.Clear();
    103.             m_SaveDatas.AddRange(SaveSystemManager.GetSaves());
    104.             if (m_SaveDatas.Count < SaveSystemManager.MaxSaves) {
    105.                 for (int i = m_SaveDatas.Count; i < SaveSystemManager.MaxSaves; i++) {
    106.                     m_SaveDatas.Add(null);
    107.                 }
    108.             }
    109.             SetElements(m_SaveDatas);
    110.  
    111.             base.Refresh();
    112.         }
    113.  
    114.         /// <summary>
    115.         /// Click a button in the grid.
    116.         /// </summary>
    117.         /// <param name="saveData">The save data.</param>
    118.         /// <param name="index">The index.</param>
    119.         private void OnSaveElementButtonClick(SaveData saveData, int index)
    120.         {
    121.             m_SelectedIndex = index + m_StartIndex;
    122.             m_SelectedSaveData = saveData;
    123.             m_ActionPanel.Open(m_ParentPanel, GetButton(index));
    124.         }
    125.  
    126.         /// <summary>
    127.         /// Click an empty button in the grid.
    128.         /// </summary>
    129.         /// <param name="index">The index.</param>
    130.         private void OnEmptyButtonClicked(int index)
    131.         {
    132.             m_SelectedIndex = index;
    133.             m_SelectedSaveData = null;
    134.             m_ActionPanel.Open(m_ParentPanel, GetButton(index));
    135.         }
    136.     }
    137. }
    Loading and saving works.. but unfortunately the save list doesn't work properly in regards to viewing the save slots. All slots end up having the same date, same data etc, so I figured I had to replace SaveSystemManager with SaveSystemManagerNoDisk.. but yeah I'm having some trouble with that. :oops:
     
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    @SOSolacex - You're almost there. Just replace the Refresh() method.

    The original Refresh() method populates the script's internal m_SaveDatas list, which is a list of SaveData objects, with UIS's saved games.

    Instead, you'll want to create a list of empty SaveData objects representing the Dialogue System's saved games. Something like this, if you're using the DiskSavedGameDataStorer:

    Code (csharp):
    1. public override void Refresh()
    2. {
    3.     m_SaveDatas.Clear();
    4.  
    5.     // Add info about saved games:
    6.     diskStorer = SaveSystem.storer as DiskSavedGameDataStorer;
    7.     for (int i = 0; i < SaveSystemManager.MaxSaves; i++)
    8.     {
    9.         if (diskStorer.HasDataInSlot(i))
    10.         {
    11.             SaveData saveData = new SaveData();
    12.             saveData.SetDateTime(System.IO.File.GetLastWriteTime(diskStorer.GetSaveGameFilename(i)));
    13.             m_SaveDatas.Add(saveData);
    14.         }
    15.     }
    16.  
    17.     // Pad out list with empty slots:
    18.     if (m_SaveDatas.Count < SaveSystemManager.MaxSaves) {
    19.         for (int i = m_SaveDatas.Count; i < SaveSystemManager.MaxSaves; i++) {
    20.             m_SaveDatas.Add(null);
    21.         }
    22.     }
    23.     SetElements(m_SaveDatas);
    24.     base.Refresh();
    25. }
     
    SOSolacex likes this.
  5. nichjaim

    nichjaim

    Joined:
    Apr 23, 2020
    Posts:
    40
    Calling the SkipAll() just seems to go to the next dialogue node rather than skipping to the next player choice node, any idea what might be causing this? Also, does skipping also call all the commands attached to the in-between nodes (such as some nodes that may call functions that add things to the player inventory) and if not is there an easy way to have it do that? Sorry for piling on more questions.
     
  6. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi @nichjaim - I've attached an example scene and an updated ConversationControl that allows 'required' sequencer commands to run when skipping. Script fields will always run. This update also allows sequencer commands that are preceded by the keyword required to also run. In the example scene, I put the Auto Play and Skip All buttons in the NPC Subtitle Panel. The ConversationControl script is on the dialogue UI.
     

    Attached Files:

    nichjaim likes this.
  7. SOSolacex

    SOSolacex

    Joined:
    Jan 10, 2018
    Posts:
    120
    You're a champ. Thanks a bunch!
    By the way, I use SendMessage quite often, but I reckon that every time I use it, it needs to find the object I'm trying to send a message to. Is it perhaps possible to cache objects into the dialogue system so I can use them later?
    Or would you say that it's not impactful enough in terms of performance to actually put the effort into it?
     
  8. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Intermittent SendMessage's are absolutely fine, especially in non-time-critical instances such as conversations. Don't do it every frame, though, of course.
     
    SOSolacex likes this.
  9. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
  10. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Extra 50% Off - Quest Machine

    Tip: If you've already bought a Dialogue System license, you can get Quest Machine at an "upgrade" price of 50% off.

    Since the Dialogue System and Love/Hate are both currently 50% off, that means you can get all three assets for 50% off.
     
  11. gamemakerdre

    gamemakerdre

    Joined:
    Nov 25, 2014
    Posts:
    40
    Im having a difficult time trying to use dialogue system with obsive third person controller. Are there up to date instructions anywhere on this?
     
  12. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi @gamemakerdre - Yes, please see Opsive Character Controller Integration. If you have any questions about setting it up, just let me know.
     
  13. gamemakerdre

    gamemakerdre

    Joined:
    Nov 25, 2014
    Posts:
    40
    I've followed the above post, however I am not able to add the conversing preset to the unity input (step 3) as I get a message from unity saying the preset is not the same type. As i continued on to the remaining steps this did not work for me, so yes any help would be greatly appreciated.
     
  14. gamemakerdre

    gamemakerdre

    Joined:
    Nov 25, 2014
    Posts:
    40
    Ive tried again with no luck. And I noticed your opsive demo scene does not seem to work either, as I am not able to do anything in the scene except press the escape menu and choose the options. Seems to be out of date. I am a paying customer and I would like some up to date tutorial or help on setting this up.
     
  15. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi @gamemakerdre - The example scene is made for UCC, not TPC. Here's a TPC example scene:

    DS_TPC_DemoScene_2021-08-07.unitypackage

    Let's go through the steps one by one.

    1. Create a new, empty project. Import the Dialogue System and Opsive Third Person Controller.

    2. Select menu item Tools > Opsive > Ultimate Character Controller > Main Manager. Click on Setup > Project. Click Update Buttons and Update Layers.

    3. Click Integrations. Download and import the Dialogue System integration.

    4. Open the scene Assets > Opsive > UltimateCharacterController > Demo > ThirdPersonControllerDemo. Add the Dialogue Manager prefab:

    upload_2021-8-7_8-29-30.png

    Assign a dialogue database such as Demo Database to the Initial Database field.

    5. Add the Converse ability to the player's UltimateCharacterLocomotion component:

    upload_2021-8-7_8-33-40.png

    6. Add an Interact ability to the player. Configure it to be able to detect whatever you want to talk with:

    upload_2021-8-7_8-35-59.png

    This ability uses Opsive TPC's standard interaction system, so refer to their documentation on how to set up interactions. You may want to set the Ability Message Text to "Talk" or something like that so you get a prompt when targeting an interactable NPC. Note that I moved the Interact ability pretty high in the list so it's not superceded by other abilities that are now below it in the list.

    7. Add the ConversingUnityInputPreset to the UnityInput component. It looks like TPC v2.3.5 broke connections to existing input presets, so I've included a new one in the example scene unitypackage. I'm also sending it to Opsive to update the integration download. Or you can just create it yourself, if you even want it. It just shows the cursor during conversations. It only has one property:

    upload_2021-8-7_8-42-54.png

    upload_2021-8-7_8-44-34.png

    8. Set up an NPC to talk to. Add Interactable and DialogueSystemTriggerInteractableTarget components. Assign the DialogueSystemTriggerInteractableTarget to the Interactable's Targets list. Configure the DialogueSystemTriggerInteractableTarget to start a conversation (Add Actions > Start Conversation). The quickest way to test this is to copy "Private Hart" from the Opsive UCC Dialogue Example scene and paste it into your scene. Make sure you've assigned Demo Database to the Dialogue Manager's Initial Database field.
     
  16. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    50% Off Dialogue System for Unity - Last Chance

    upload_2021-8-9_10-0-59.png

    The Asset Store's Summer Sale ends today. It's your last chance to get the Dialogue System for Unity and Love/Hate for 50% off. As seen in Disco Elysium, Lake, Jenny LeClue, The Last Door, and many more games.
     
  17. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Black Book Released On Steam & Consoles

    Black Book, a Slavic myth-inspired RPG with unique deck-building combat (and made with the Dialogue System for Unity) is now out on Steam and consoles. Congratulations to developer Morteshka!

     
  18. ch1ky3n

    ch1ky3n

    Joined:
    Oct 26, 2017
    Posts:
    40
    Hi Tony,

    I have a problem with Animated Portrait.
    I'm only using IDLE animation on each actor, so I don't change the mood or pose.
    My problem is the animation keeps restarting back to frame 1 on each dialogue, so it looks weird when the player skipping the dialogue.

    Is there any way to make the animation looping seamlessly without restarting on every new dialogue entry?

    Thank you for this "Beast" Asset man!
     
  19. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi @ch1ky3n - The animation will continue to play uninterrupted (i.e., loop) unless the subtitle panel is being deactivated and reactivated -- for example, if you've set its Visibility to Only During Content -- or if the animator is being re-used for a different character. Try setting the panel's Visibility to Always From Start or Always Once Shown.
     
  20. ch1ky3n

    ch1ky3n

    Joined:
    Oct 26, 2017
    Posts:
    40
    Awesome, It works now !!!
     
  21. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Glad to help! :)
     
  22. Stickeyd

    Stickeyd

    Joined:
    Mar 26, 2017
    Posts:
    151
    Hey. For some reason at some point of my gameplay(I can't really figure out how to reproduce this bug exactly) something breaks and when I start any next dialogues, your script DialogueSystemTrigger breaks on line 639 with null reference exception. What could it be? It breaks so that next line doesn't even start afterwards.

    UPDATE: Ok, I figured out that it happens because onExecute is null. What does it mean? How could it be so?
     
    Last edited: Aug 14, 2021
  23. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    It is possible that whatever you've connected to the OnExecute() UnityEvent is null, and not onExecute itself? onExecute is initialized to a valid value in its declaration:
    public GameObjectUnityEvent onExecute = new GameObjectUnityEvent();
    so it won't be null unless something external to the Dialogue System has set it to null.

    Can you update to the latest version of the Dialogue System? Or, if you can't update the Dialogue System, can you import just the DialogueSystemTrigger.cs script from it? (Either way, back up your project first just to be on the safe side.) In version 2.2.18, onExecute.Invoke() is on line 698. This will allow us to refer to the same thing when we're talking about line numbers.

    p.s. - Did you receive my PM with the patch that adds an option to sort dialogue entry IDs in the order you wanted?
     
  24. Stickeyd

    Stickeyd

    Joined:
    Mar 26, 2017
    Posts:
    151
    This trigger doesn't have any onExecute stuff and I have no idea what on Earth could be setting this to null. Maybe when I load the game I ruin something, but it's happening not after every saveload I do so I have no idea what exactly breaks it.

    Can I just create a condition - if(onExecute != null){ xxx }?

    Yeah, I received your message. Thanks.
     
  25. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Sure. Try that and see if it fixes your issue. If it does, please let me know.
     
  26. gamemakerdre

    gamemakerdre

    Joined:
    Nov 25, 2014
    Posts:
    40
    I tried several times, but I was not able to get this to work following your instructions. However, I was able to get it working by adding a "DialogueSystemTrigger", and a "Usable component" to the NPC, while adding the "interact" and and "converse abilities" to my player and this setup worked. Adding the "DialogueSystemTriggerInteractableTarget" and linking it with the "interactable component" on the npc, which you mentioned in your previous steps, as well as I think they are on your website, did not work for me. However I did learn how to create those presets from your steps above. Im good to go now, I was dying to get this working and it is now. Thank you. This is a great product.
     
    TonyLi likes this.
  27. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    I'm glad you got it working. I assume the demo scene in the package I attached worked also. Maybe there was a small discrepancy in the scene that you were setting up. Anyway, great to hear it's working now. Have fun adding dialogue!
     
  28. gamemakerdre

    gamemakerdre

    Joined:
    Nov 25, 2014
    Posts:
    40
    Hey one more question? I have some other UI elements on screen that are not apart of the Opsive UI elements. Is there any easy way to disable those items during conversations?
     
  29. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    If the UI elements survive scene changes, add a Dialogue System Events component to the Dialogue Manager GameObject. Configure its OnConversationStart() event to disable the UI elements and OnConversationEnd() to re-enable them.

    If the UI elements only exist in a specific scene and you want to hide them when the player is involved in a conversation, you can add a Dialogue System Events component to the player GameObject.
     
  30. ch1ky3n

    ch1ky3n

    Joined:
    Oct 26, 2017
    Posts:
    40
    Hey Toni, I got some weird scenario

    I setup a dialogue Entry with [var=NoVarComment] [var=WithVarComent]

    NoVarComment = You've died. <no variables>
    WithVarComment = Your current life is [var=life]

    The first entry works well when I setup the entry with " [var=NoVarCommentt] [var=WithVarComment] " combined
    It says " You've died. Your current life is 4"

    second entry where I put [var=WithVarComment]
    It says "Your current life is [var=life]" < yes instead of the value

    So here's the summary:

    1. if I just enter directly "Your current life is [var=life]" inside the dialogue box, without using variable WithVarComment, it works.
    2. if I combine both "[var=NoVarCommentt] [var=WithVarComment]", it also work
    3. If I'm just using [var=WithVarComment], it doesn't work

    Can you give me an idea, how to set up an entry with just [var=WithVarComment] to work?

    Thank You!


    EDIT: I used a temporary solution by making a variable named blank
    and I enter [var=blank] [var=WithVarComment] and it works.
     
  31. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi @ch1ky3n - Dialogue entries don't process nested [var=variable] tags, so it's just coincidence that the first one works. To make it work properly, you'll want to run an additional pass to process nested [var=variable] tags. Add a script to the Dialogue Manager that has an OnConversationLine method similar to this:
    Code (csharp):
    1. using UnityEngine;
    2. using PixelCrushers.DialogueSystem;
    3. public class ProcessNestedVarTags : MonoBehaviour
    4. {
    5.     public void OnConversationLine(Subtitle subtitle)
    6.     {
    7.         int safeguard = 0; // Infinite loop should never happen, but add defensive safeguard anyways.
    8.         while (subtitle.formattedText.text.Contains("[var=") && safeguard++ < 10) // Note: Max 10 levels deep
    9.         {
    10.             subtitle.formattedText.text = FormattedText.ParseCode(subtitle.formattedText.text);
    11.         }
    12.     }
    13. }
     
  32. ch1ky3n

    ch1ky3n

    Joined:
    Oct 26, 2017
    Posts:
    40
    omg it works, thanks Tony,
     
  33. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Happy to help!
     
  34. gamemakerdre

    gamemakerdre

    Joined:
    Nov 25, 2014
    Posts:
    40
    That worked like a charm. Thanks!
     
    TonyLi likes this.
  35. Jakuri_F

    Jakuri_F

    Joined:
    Mar 9, 2020
    Posts:
    15
    Hi Tony,
    I modified the JRPG UI template, changed background color of portrait image to trasparent, then I found the portrait image of the character spoke before is still last on the screen. Can you help me to fix this?
    Thank you!
    dialogue1.png
     
  36. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi - Did you add another subtitle panel or portrait image? The JRPG template only has one portrait image, one subtitle panel, and one menu panel. The subtitle panel and menu panel point to the same portrait image:

    upload_2021-8-26_14-54-3.png

    If you added a separate portrait image for the menu panel, set the subtitle panel's Visibility to Only During Content.

    If you added another subtitle panel, set the subtitle panels' Visibility to Until Superceded.

    If that doesn't help, can you send a reproduction project to tony (at) pixelcrushers.com?
     
  37. i32gg7ar

    i32gg7ar

    Joined:
    Jan 3, 2021
    Posts:
    9
    Hi Tony,

    First of all, thanks for making this plugin! It has saved me a ton of time.

    I'm trying to add some custom behavior in the system. To give some context, I have a custom UI that shows some dialogue lines to the player in groups, think of it like "repeating" certain lines that characters have said. Here's how I implemented this:
    - Custom Lua function
    MarkEntryToShow()
    : when it runs, it should get the current dialogue entry and save it to a list.
    - Custom Lua function
    ShowMarkedEntries()
    : when it runs, it should take all dialogue entries that are in that list, show their lines to the player through the custom UI, then clear the list (so I can show the next "group").

    Here's how I'm grabbing the current dialogue entry on
    MarkEntryToShow()
    :

    Code (CSharp):
    1. void MarkEntryToShow()
    2. {
    3.     var currentConversationEntry = DialogueManager.currentConversationState.subtitle.dialogueEntry;
    4.     markedEntries.Add(currentConversationEntry);
    5. }
    I'm facing a problem with this implementation: the actual entry being added to the list is the previous entry. It looks like when the script of a dialogue entry runs, that dialogue entry isn't yet updated in
     DialogueManager.currentConversationState
    .

    Is this behavior intended? Is it a bug? Is there any way that I can accomplish what I'm looking for?

    Thank you!
     
  38. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi @i32gg7ar - That's correct; running a dialogue entry's Script is part of preparing the conversation state, so DialogueManager.currentConversationState won't be valid yet.

    Instead, you can use an OnConversationLine method. In MarkEntryToShow() ,just set a flag to indicate that the upcoming line should be saved to the list. Example:
    Code (csharp):
    1. public void MarkEntryToShow() { addLineToList = true; }
    In OnConversationLine, add the line to the list. Example:
    Code (csharp):
    1. public void OnConversationLine(Subtitle subtitle)
    2. {
    3.     if (addLineToList)
    4.     {
    5.         YourList.Add(subtitle.formattedText.text);
    6.         addLineToList = false;
    7.     }
    8. }
     
  39. i32gg7ar

    i32gg7ar

    Joined:
    Jan 3, 2021
    Posts:
    9
    Thank you, that worked well!
     
    TonyLi likes this.
  40. Jakuri_F

    Jakuri_F

    Joined:
    Mar 9, 2020
    Posts:
    15
    Hi Tony,
    I'm sorry neither of the solutions worked, but I found this bug only appears when I set the dialogue trigger to On Start. Cause I won't set any trigger to On Start in the release version of my game, so it affects nothing currently. Thanks for your reply!
     
  41. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    It shouldn't happen at all, even in On Start. If you want investigate further at any time, just let me know.
     
    Jakuri_F likes this.
  42. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Dialogue System 2.2.19 Released

    Version 2.2.19 is now live on the Asset Store! This update is packed with many improvements and bug fixes.

    The upcoming version 2.2.20 will feature the beta release of CeltX integration. We've worked with Celtx to provide a robust, easy workflow to bring your Celtx projects into Unity.

    Release Notes:

    Core:
    • Added: ConversationControl component (Skip All and Toggle Auto Play).
    • Added: Dialogue Database base ID setting for working with multiple databases.
    • Improved: Added alternate method to reorder conversation nodes.
    • Improved: Dialogue Editor > Database Merge feature now has option to merge emphasis settings.
    • Improved: Dialogue Editor > Language Text export now includes each character only once.
    • Improved: Added Camera & Cutscene Settings > Keep Camera Position At Conversation End checkbox.
    • Improved: Added Selector option Distance From - Actor Transform.
    • Improved: Selector now has workaround for new Input System IsPointerOverGameObject() bug; fixed issue with Rewired integration and Select At mouse position.
    • Improved: All versions of DialogueManager.LoadAsset() can load Addressables. If you enable Addressables support, you must use Addressables version 1.17.4+.
    • Improved: Timeline Start Conversation & Bark clips now have option to specify dialogue database.
    • Improved: Added public properties Sequencer.shortcuts and Sequencer.shortcutStack.
    • Improved: IncrementOnDestroy methods are now virtual.
    • Improved: StandardUISubtitlePanel.animator is now virtual.
    • Improved: StandardUIContinueButtonFastForward.runtimeDialogueUI is now virtual.
    • Improved: Sequencer now checks for completed active sequencer commands in LateUpdate instead of Update to improve timing.
    • Improved: Added UILocalizationManager checkbox to set TextTable.useDefaultLanguageForBlankTranslations.
    • Improved: LocalizeUI will use default translation if current language setting is invalid.
    • Fixed: Timeline Bark clip with specific entry ID didn't execute entry's Script field.
    • Fixed: CinemachinePriority() sequencer command doesn't overwrite its own blend mode change.
    • Fixed: Bug in StandardUISubtitleControls.SetActorSubtitlePanelNumber().
    • Fixed: If Unique ID Tool EditorPrefs key was invalid, couldn't open window.
    • Fixed: SMS Dialogue UI incorrectly showed empty bubble for blank subtitles.
    • Fixed: Quest log window and tracker HUD now show quests in Return To NPC state same as Active state.
    • Fixed: Subtitle panels set to Until Superceded and Wait For Close would not wait for previous panels to close before showing new panel.
    • Fixed: Standard Dialogue UI main panel Wait For Close waits for subtitle/menu panels to close before starting to close.
    • Fixed: Some Dialogue Editor inspector fields would not mark the database dirty for saving.
    • Fixed: Disabled domain reload issue with StandardUISelectorElements.
    • Fixed: SelectorFollowTarget now accommodates tag/layer-specific selector images.
    • Fixed: CheckInputManagerSettings error in Unity 2021.b
    • Fixed: Dialogue System startup checks language on UILocalizationManager if present.
    • Fixed: Dialogue Editor conversations selection popup would occasionally appear blank.
    • Fixed: PersistentDataManager now sanitizes Pictures field.
    • Save System: Saver components now show warning if GameObject has multiple savers and Key values are blank.
    • Save System: Added SaveSystemMethods.ResetGameState().
    • Save System: No longer adds JsonDataSerializer or PlayerPrefsSavedGameDataStorer if application is quitting.
    • Save System: Fixed bug with AnimatorSaver when using BinaryDataSerializer.
    Third Party Support:
    • Corgi: Added Pause While Talking checkbox to ConversationZone.
    • i2 Localization: Now sanitizes characters '/\[]' in terms.
    • Ink: Fixed issue with sequences on player responses; {Sequence()} external function allows [[x]] to specify shortcut x instead of {{x}}.
    • Opsive Controllers: Updated for 2.3.5; added TPC demo scene; fixed player control issue with one player conversation starting on same frame that another player conversation ended.
    • SALSA: Updated TextSync integration; added StopTextSync() sequencer command.
    • Text Animator: Added Clear Text On Open checkbox.
    • TopDown Engine: Improved PauseTopDownDuringConversations cursor and input handling; health bar UI is now updated when loading saved game character data.
    • Twine: If link connects to a node whose text is exactly same as link, import will treated them as single node.
     
  43. Jakuri_F

    Jakuri_F

    Joined:
    Mar 9, 2020
    Posts:
    15
    Hi Tony,
    I'm trying to switch an actor's expression, then I find I can set multiple portrait textures to one actor, but I can't find anywere to choose the index. Am I supposed to create multiple actors like char1_smile, char1_angry ?
    ss3.png
     
  44. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi - Use the [pic=#] markup tag in your dialogue text. For example, to show the 3rd expression:
    • Dialogue Text: "Hmm, that's interesting. [pic=3]"

    Or, to switch expressions permanently for the rest of the conversation, use the SetPortrait() sequencer command. Example:
    • Dialogue Text: "I will use this expression from now on."
    • Sequence: {{default}}; SetPortrait(Jakuri, pic=3)
     
    Jakuri_F likes this.
  45. Fira-Soft

    Fira-Soft

    Joined:
    Sep 9, 2014
    Posts:
    15
    Hi there,
    Is it possible to add a custom variable type to be used by the dialogsystem?

    In case, I'm using Unity Atoms, and some of my variables will also be used by the Dialog System. The Atoms architecture is based on data variables being saved on atomic scriptable objects. As I don't want to have duplicated variables, It would be awesome if I can extend the Dialog System to handle (show and set) them. I know about the Lua.RegisterFunction option, but this doesn't allow me neither see this variables in the dialog system tab nor reference them in the DialogSystem.

    1) All in all I want to know if there is some kind of support to add extra types of variables or if there is a known path to follow.

    2) Also, on TemplateCustomLua.cs is stated that you can use a static class instead of a monobehaviour for registering you functions. But the code

    Lua.RegisterFunction("DebugLog", this, SymbolExtensions.GetMethodInfo(() => DebugLog(string.Empty)));


    doesn't work for static classes as this isn't valid. What is the correct way to call RegisterFuncion with static classes?

    edit: I don't think I'll be using the static class to register on this case, but would like to known the intended way of using it
     
    Last edited: Aug 31, 2021
  46. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Hi - No, dialogue database variables use primitive values (string, bool, etc.). You can define custom "types," but the backing data is always a string, so it might not be what you're looking for. (Details: Custom Field Types.) However, some games do use that backing string to identify the name of an asset in a Resources folder, or a GUID in a database, etc., and use a custom field drawer to show it as a designer-friendly dropdown.

    Instead, I think in your case Lua functions will be the best fit. You can view their realtime values in the Dialogue Editor's Watches section. For example, say you've registered a C# method GetHealth("name") that returns the current HP of a character. You can add a watch like this:

    upload_2021-8-31_14-25-3.png


    For static classes, pass null instead of this.
     
    Fira-Soft likes this.
  47. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
  48. Fira-Soft

    Fira-Soft

    Joined:
    Sep 9, 2014
    Posts:
    15
    Both ideias seems interesting. I'm messing around with Custom Field Types, and if I use them in a condition, is it possible to customize de condition "right hand" box to be a custom enum?

    Other than that, thx for the support, for what I see, your code seems well organized and meaningful, although the high complexity of the system.
     
  49. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    No, there's no provision for that. It will be a freeform text field.

    Thanks! :)
     
    Fira-Soft likes this.
  50. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    11,599
    Disco Elysium Earns #1 Spot in PC Gamer's Top 100 List Second Year In a Row

    Congratulations to Studio ZAUM! For the second year in a row, PC Gamer just ranked Disco Elysium, made with the Dialogue System for Unity, as their top game of all time again in their 2021 Top 100 List. The breakout indie hit and masterwork of dialogue writing is available on all the consoles and PC stores.

    upload_2021-9-1_8-16-52.png
     
unityunity