Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

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

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

  1. booyagrandmma

    booyagrandmma

    Joined:
    Mar 26, 2012
    Posts:
    11
    Sorry if repeating any questions on this thread, i haven't gone back and caught up on everything. First I should say thank you for releasing this framework. It's saved me a huge amount of time. Just a few questions.

    First one is simple. Is there an easy way to disable portraits.

    Second, I wrote a simple sequence command which tells a specific actor to go to a specific location and i just wanted to ask if there was a more efficient way of doing this.

    SetDestination(NavMeshActor, GameObjectTargetLocation)

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.AI;
    3. using System;
    4. using System.Collections;
    5. using PixelCrushers.DialogueSystem;
    6.  
    7. namespace PixelCrushers.DialogueSystem.SequencerCommands {
    8.  
    9.     public class SequencerCommandSetDestination: SequencerCommand {
    10.        
    11.         public void Start() {
    12.             GameObject m_Agent = GameObject.Find (GetParameter (0));
    13.             NavMeshAgent m_NavMeshAgent = m_Agent.GetComponent<NavMeshAgent> ();
    14.             if (m_NavMeshAgent != null) {
    15.                 string m_DestName = GetParameter (1);
    16.                 GameObject m_DestObject = GameObject.Find (m_DestName);
    17.                 if (m_DestObject != null) {
    18.                     m_NavMeshAgent.SetDestination (m_DestObject.transform.position);
    19.                 }
    20.             }
    21.             Stop ();
    22.         }
    23.     }
    24. }
     
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @booyagrandmma - Thanks! To disable portraits, deactivate or remove the portrait UI elements from your dialogue UI, and then unassign the Portrait Image fields in your Dialogue UI component (e.g., Dialogue Manager > Canvas > Generic Unity UI Dialogue UI).

    That looks pretty good. Here are a couple tiny suggestions for the Start() method:
    Code (csharp):
    1.         public void Start() {
    2.             Transform m_Agent = GetSubject(0); //<-- Also handles 'speaker' & 'listener' keywords.
    3.             // (Should also check that m_Agent isn't null. I omitted this for brevity.)
    4.             NavMeshAgent m_NavMeshAgent = m_Agent.GetComponent<NavMeshAgent> ();
    5.             if (m_NavMeshAgent != null) {
    6.                 Transform m_DestTransform = GetSubject(1);
    7.                 if (m_DestTransform != null) {
    8.                     m_NavMeshAgent.SetDestination (m_DestTransform.position);
    9.                 }
    10.             }
    11.             Stop ();
    12.         }
    It just uses SequencerCommand's GetSubject() method to simplify things a bit.
     
  3. longroadhwy

    longroadhwy

    Joined:
    May 4, 2014
    Posts:
    1,548
    @TonyLi

    Just started looking at your Dialogue System integration for Realistic FPS. You really have a large number of posts in the Realistic FPS thread so you must know it forwards and backwards.
     
  4. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    I have a certain fondness for RFPS due to history. It was the first integration in which I worked closely with some teams to really make sure it did everything they needed end-to-end for their games, including menu systems, missions, save/load, inventory, etc. I've since then had the opportunity to do the same with other frameworks, but RFPS was my first. :)
     
  5. longroadhwy

    longroadhwy

    Joined:
    May 4, 2014
    Posts:
    1,548
    Thanks for the clarification.
     
  6. longroadhwy

    longroadhwy

    Joined:
    May 4, 2014
    Posts:
    1,548
    @TonyLi

    Integration questions:
    Unity 5.5.0f3 (windows 64-bit)
    Rewired 1.0.0.110
    Realistic FPS v1.24
    Dialogue System for Unity 1.6.7
    ==========

    The question is how to disable the dialogue system interaction system and let Realistic FPS input handle it all?

    My issue is slightly differently problem because I also switched out the Realistic FPS input system to use Rewired input system instead. This is defined in this Realistic FPS prefab forum message https://forum.unity3d.com/threads/realistic-fps-prefab-released.176985/page-69#post-2921727

    (1) Created a new project with dialog system, rewired and realistic fps prefab.
    (2) Loaded the Realistic FPS sandbox example scene
    (3) Loaded the Dialog System's realistic integration package (defined in the third party folder)
    (3) Added the Rewired input manager
    (4) Replaced InputControl.cs (as defined in the Realistic FPS prefab forum message above to use Rewired).

    These are the steps I am following come from this URL.

    http://pixelcrushers.com/dialogue_system/manual/html/realisticfps.html

    This is the particular step that is where my question is (since I am using Rewired and not the Unity Input system).

    Optional: Select the FPS Camera > Main Camera GameObject. Then select Component > Dialogue System > Actor > Player > Selector. This will add a selector that you can use to interact with Dialogue System usable objects. If you plan to use RFPS's interaction system instead, you can skip this step.
    • If you want to be able to interact with NPCs, set the Layer Mask to "Default, NPCs".
    • Set Use Key to a key not reserved by RFPS, such as "N".
    • Set the Use Button to a button defined in the Unity input manager. (Note: RFPS's input settings don't define Fire2.)
    • Change the Default Use Message to reflect your key/button choices.
     
  7. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @longroadhwy - To let RFPS input handle it all, just don't add a Selector. For an example of how to configure an NPC to start a conversation using RFPS input, open the example scene and examine the GameObject Dialogue System Stuff > Happy Robot > Dialogue AI.
     
  8. Mazak

    Mazak

    Joined:
    Mar 24, 2013
    Posts:
    226
    Tony,
    Workflow - I am frustrated with the workflow I have created and I would like some perspective.

    We are working on the quick start tutorial using ChatMapper.

    We have multiple scenes Main menu, Planet, Dry dock, Trading post, Normal Space, Hyper Space with conditions such as in combat or not etc...

    Currently I have 8 conversations, 2 c# scripts, and one quest (expanded to 5 entries). Its really getting to be a pain to keep track of it all and this is only the tutorial and we hope to create many quests in the near future.

    Would it be better to have a single large branching conversation that matches the quest and that is controlled by a single c# script? or ?

    Any guidance would be very helpful.

    Thanks
     
  9. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @Mazak,

    I'm not completely familiar with your game's setup, but my instinct is usually to write a conversation for each major subject that the NPC talks about. I then use a "hub" conversation and branch from the hub to the appropriate conversation based on the current states of quests and variables.

    I prefer to handle all of the conversation branching in Chat Mapper (or the Dialogue Editor for other readers who use the Dialogue System's built-in editor) with a single entry point from Unity (i.e., that hub conversation). I'll use a traditional fantasy RPG quest giver NPC as an example since again I don't know the details of your game.

    Let's say the NPC is named Boudica, and she offers three successive quests: "Scout the Enemy Camp", "Steal the Plans", and "Lead the Attack".

    In Chat Mapper, I'd write, say, five conversations:
    1. "Celts/Boudica/Hub"
    2. "Celts/Boudica/Scout Enemy Camp"
    3. "Celts/Boudica/Steal Plans"
    4. "Celts/Boudica/Lead Attack"
    5. "Celts/Boudica/Chat"
    Note that I used forward slashes ( / ) in the conversation titles. For me, this helps group the conversations. And those forward slashes turn into submenus in Unity, which make it handy to select conversations from a large list.

    In "Celts/Boudica/Hub", I'd check the states of the quests and link to the appropriate quest-specific conversation. In fact, this conversation might only have the START node, with links to the other conversations coming right off START. The "Celts/Boudica/Chat" conversation is just a fallback to use if the player has completed all the quests.

    In Unity, I'd add a single Conversation Trigger to Boudica and select the conversation "Celts/Boudica/Hub".


    If that doesn't help, what kind of workflow issues are you running into?

    [EDIT: Group nodes might also be helpful, depending on what workflow issues are causing headaches. You can use them to cut down on the number of links, which is something I kind of wish Unity would add to Mecanim.]

    I was about to suggest an alternative of splitting your content into multiple Chat Mapper files. (The Dialogue System can work with multiple dialogue databases.) But I have a feeling that this would just exacerbate the complexity, not simplify it.
    Chat Mapper
     
    Last edited: Jan 22, 2017
  10. Mazak

    Mazak

    Joined:
    Mar 24, 2013
    Posts:
    226
    I think is the key that I need. The hub would also allow me to jump quickly between nodes.

    I see how this could help, good idea.

    I was thinking along the same lines, each major quest theme could go into its own chat mapper file. Thanks for confirming my thoughts.
     
  11. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Here are the pro's and con's of multiple Chat Mapper files as I see them:

    Pro's
    • Content is split into different files by subject.
    • Easier for multiple authors to work on Chat Mapper content at the same time.
    Con's
    • Content is split into different files by subject. ;) There are more files to keep track of, and your dialogue databases can get out of sync if you convert one Chat Mapper file and forget to convert another it depends on.
    • Each Chat Mapper file starts its internal ID numbering at 1. When you bring all the files into Unity, their IDs will probably conflict. You'll have to use the Unique ID Tool or merge them into one database to resolve the conflicts.
    • Harder to link in Unity. You may find it easier in this case to use multiple Conversation Triggers with their Condition sections configured to run only one conversation at a time.
    This isn't to say it can't work. At least one large project had a primary database that was always loaded, and then an additional database that was loaded only for each scene (zone, planet, village, whatever you want to call it). You can read more tips about multiple databases on this page: How to Use Multiple Databases.
     
    Mazak likes this.
  12. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Updated Support Package for S-Inventory Available

    The Dialogue System Extras page has an updated support package for S-Inventory. It fixes a bug with persistent vendors & item groups when changing scenes.
     
  13. Mazak

    Mazak

    Joined:
    Mar 24, 2013
    Posts:
    226
    Tony,
    We put everything for the tutorial into one conversation and it appears to have solved our issues. Its at 111 nodes but it helps with simulation and all the variables and items are always being set correctly.

    Thanks for the advice

    David
     
    TonyLi likes this.
  14. Muralidaran

    Muralidaran

    Joined:
    May 2, 2014
    Posts:
    93
    Hi Tony,

    I was just hoping to get your input on something. I was just wondering whether it is better to use multiple conversations of one long conversation that starts at different points depending on what the player has completed. For example, my first npc gives you a quest, then after you finish it he tells you where to go for the next one and so on. Some of the npcs in my game have a lot to say and offer many quest.

    Does that all make sense? Let me now.

    Thanks,
    Mura
     
  15. booyagrandmma

    booyagrandmma

    Joined:
    Mar 26, 2012
    Posts:
    11
    Hello Tony, thanks for your quick response and help earlier.

    My next question. I have a custom full screen GUI that pops up and needs to cover the screen entirely. Unfortunately i can't figure out how to have it render on top of the "'usable" actor labels that pop up. Also is there somewhere you can point me to start customizing how that label behaves and what it looks like exactly. I was hoping to add images for button press indications instead of literally saying "press x" or "press space"
     
  16. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @Muralidaran - I prefer to use multiple conversations (one for each quest) with a single "hub conversation" entry point. The hub conversation contains cross-conversation links to the quest-specific conversations.

    Cross-Conversation Links

    Configure your NPC's Conversation Trigger to play the hub conversation, and configure the Conditions fields on the quest conversations to specify which cross-conversation link to follow.

    Here's an example of the hub conversation:


    (For organization, I use forward slashes [ "/" ] to put each NPC's conversations in their own submenu.)

    Here's an example of how to add cross-conversation links:




    Group Nodes

    Alternatively (or even in combination), use Group nodes. To make a dialogue entry node into a Group node, tick its Group checkbox. Group nodes will check their Conditions fields. If true, they will run their Script fields and then immediately pass through to their children without showing any subtitle text. Group nodes allow you to reduce the number of links between nodes, which may make it more manageable to keep all your content in a single conversation if you prefer to do that.

    Here's an example that uses Group nodes:




    Multiple Conversation Triggers

    Both of the examples above keep all of the branching inside the dialogue database. Another approach is to write independent conversations in the dialogue database, and branch in Unity by using multiple Conversation Triggers. Set each Conversation Trigger's Condition so only one will be true at any given time. I personally don't like this because it puts the branching logic in two different places. I prefer to keep all the branching logic in the dialogue database. But YMMV.


    Hi @booyagrandmma - The "press x" text comes from the Selector (or Proximity Selector) component. By default, the Selector uses legacy Unity GUI, which works independently from Unity UI. (I'm assuming your custom full screen GUI uses Unity UI.) This is probably why it shows up on top of your full screen GUI. Here are my recommendations:

    1. Use Set Component Enabled On Dialogue Event to automatically disable the Selector during conversations. This is what the Feature Demo does. Examine the Player GameObject to see how it's set up.

    2. Or, if you want to keep the Selector enabled, add a Unity UI Selector Display component so you can assign Unity UI elements instead of using legacy Unity GUI. You can put these UI elements on a Canvas whose Sort Order is below your full screen GUI. You can also assign custom button images to Unity UI Selector Display's Reticle In Range and Reticle Out Of Range fields. Examine the scene Unity UI Examples / SF Example Scene to see how it's set up.

    If you want to use a custom set of UI elements for a specific usable, add a Usable Unity UI to that usable. In SF Example Scene, Sergeant Graves has a custom Usable Unity UI.
     
    Hormic likes this.
  17. Admiral_Ampersand

    Admiral_Ampersand

    Joined:
    Jan 28, 2017
    Posts:
    1
    Hi! i just downloaded your asset and i think it will be a huge help with my project, i've been futzing around with it for a few hours now, and i'm stumped, my game is using multiple main characters and i was wondering how i would be able to have npcs interact with each character uniquely, sorry if this is a dumb question, i'm a fairly amateur programmer ^^
     
  18. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @Admiral_Ampersand - Thanks for using the Dialogue System!

    Short answer:
    Use [var=Actor] in Dialogue Text, Variable["Actor"] in Conditions or Scripts, or DialogueManager.CurrentActor in code.

    Example: (Chooses a different greeting for Gimli; uses the main character's name in the subtitle.)
    • START
      • Dialogue Text: "Well met, [var=Actor]!"
        Conditions: Variable["Actor"] ~= "Gimli"
      • Dialogue Text: "Ugh, a dwarf..."
        Conditions: Variable["Actor"] == "Gimli"

    Long answer:
    Conversations start with two main participants, called the Actor and Conversant. (You can also involve other participants by assigning them to specific dialogue entry nodes, but I'll skip over that for now.)

    When you start a conversation, you can specify the GameObjects to use as the Actor and Conversant. I usually adopt the convention that the Actor is a player character and the Conversant is the NPC being interacted with.

    In the example below, the GameObject "Player" is assigned as the Actor, and the GameObject "Private Hart" is assigned as the Conversant:



    When the Dialogue System starts the conversation, it sets the variables "Actor" and "Conversant" to the names of the GameObjects, or to the value of Override Actor Name if you've added this component to the GameObject. You can use these variable values as shown in the short answer example above.

    The Dialogue System also sets the properties DialogueManager.CurrentActor and DialogueManager.CurrentConversant (among other useful properties) that you can use in your C# scripts.

    There's quite a lot more you can do, most without any programming. So if you have any questions about something you want to accomplish, please let me know. I'll do my best to point you in the right direction.
     
  19. Muralidaran

    Muralidaran

    Joined:
    May 2, 2014
    Posts:
    93
    Awesome. Thanks Tony. I let you know how it goes.
     
  20. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Localize TextMesh

    If anyone needs to localize Unity's TextMesh component, there's a small download on the Dialogue System Extras page. It works the same as the Dialogue System's Localize UI Text component for Unity UI, but for TextMesh. It's the last download button in the UIs section.
     
  21. longroadhwy

    longroadhwy

    Joined:
    May 4, 2014
    Posts:
    1,548
    Thank you.
     
  22. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    @longroadhwy - Happy to help!

    ---

    Updated Third Party Support Packages Available

    Just dropping a note that the Dialogue System Extras page offers several updated packages for third party support, including:
    • Action-RPG Starter Kit: Updated to handle player Mecanim animation better.
    • Makinom: Updated for Makinom 1.6.0.
    • ORK Framework: Updated for ORK 2.9.1; adds event steps to control quests.
    • Realistic FPS Prefab: Adds PersistentDeadBody and addresses Unity 5.3+ deprecation messages.
    • S-Inventory: Fixes bug with persistent vendors & item groups when changing scenes.
    • Third Person Controller: Added DamageEvent for triggering barks, etc.

    A beta patch is also available on the Pixel Crushers customer download page. The changes below (as well as the updated packages above) will be in the next full release, too. If you need the patch before then and don't yet have access to the customer download page, please PM your Asset Store invoice number.
    • Changed: OnBarkStart/End are now also sent to the Dialogue Manager.
    • Fixed: After an entry with a Response Menu Sequence, subsequent entries wouldn’t play Response Menu Sequences.
    • Fixed: Intermittent editor issue with Condition drawer.
    • Improved: Added [LuaScriptWizard] and [LuaConditionsWizard] attributes that you can use in your scripts.
    • Improved: Persistent Position Data now logs more info when Dialogue Manager’s Debug Level is Info; streamlined design is easier to set up.
    • Improved: Unity UI Typewriter Effect now supports randomized audio clips.
     
  23. imaginationrabbit

    imaginationrabbit

    Joined:
    Sep 23, 2013
    Posts:
    349
    Question about remapping a dialogue input key inside of a conversation... I've got my dialog looking and acting exactly the way I want it to but I want to make it so the first node which is a button prompt uses a different button than the rest of the tree-


    Is it possible to make it so the key "Y" is used for input on the first node and have the additional nodes use the "A" key unless there's another "Y" prompt node?

    It may be an error in the way I set things up that has brought me to this- but I saw the "toggle subtitle cancel key" in the docs and thought that there might be a way to do it- I'm familiar with the super handy UI Button Key Trigger script you provided but don't know how to use that from in a dialogue node- Thank you.
     
  24. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @mdotstrange - Using the dialogue UI's explicit Buttons list is probably a good solution. Here's an example scene:

    DifferentButtonsExample_2017-02-04.unitypackage

    To configure it, I created a dialogue UI with four predefined buttons named Response Button A, Response Button B, Response Button X, and Response Button Y:



    I assigned the keys A, B, X, and Y. In practice, you should probably define a button in Unity's Input Manager and assign that instead. That way the button can also map to a joystick button.

    In the dialogue UI, I unassigned the Button Template field and assigned the four new buttons to the Buttons list:



    Note that each button has a position (Element 0, Element 1, etc.). You can use this in your Dialogue Text, using the [position #] markup tag. For example, the entry below will use Element 3, which is Response Button Y:
    • Dialogue Text: "[position 3]Talk"
    If you don't specify a position, the Dialogue System will choose the first unused button in the Buttons list. (Since Button Alignment is To First, it will choose the first unused button. If you set Button Alignment to To Last, it will use the last unused button.)
     
    imaginationrabbit likes this.
  25. imaginationrabbit

    imaginationrabbit

    Joined:
    Sep 23, 2013
    Posts:
    349
    Awesome- thank you so much :)
     
  26. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Glad to help! There are other ways to do this, too. If that doesn't work out for you, let me know. It just seemed like the closest to what it sounds like you're designing.
     
    imaginationrabbit likes this.
  27. Mazak

    Mazak

    Joined:
    Mar 24, 2013
    Posts:
    226
    Hi Tony,
    I hope this will be easy.

    Context: Tutorial -
    a. Please press the "Left-Arrow" key
    b. The tutorial will pause until the key press
    c. Once the key is pressed the tutorial would continue.

    I would also like the following
    a. Please press the "Left-Arrow" key
    b. User presses 'let me try this' response
    c. The tutorial will pause and the dialog hides (alpha = 0)
    c. Once the key is pressed the tutorial would unhide and continue.

    I have a Lua Function created and its working as expected.

    I tried DialogueManager.Pause(); but that does not seem to do anything the dialog is still active.

    I tried DialogueManager.DialogueUI.Close() - this closes the dialog as expected... but Open() opens a blank dialog <sigh>
     
    Last edited: Feb 5, 2017
  28. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @Mazak - Here's an example:

    TutorialHideDialogueExample_2017-02-05.unitypackage

    Here's how I set it up:

    1. First, I created two inactive buttons named "Left Arrow Button" and "Let Me Try Button":



    2. Left Arrow Button is positioned off screen and is invisible (the color's alpha is zero). It has a UI Button Key Trigger that listens for Left Arrow. When clicked, it runs a sequence that sends the message "LeftArrowPressed" to the sequencer:



    The sequence "None()->Message(LeftArrowPressed)" means do nothing ("None()"), and when you're done doing nothing send the message "LeftArrowPressed" to the sequencer.

    3. Let Me Try Button isn't a response menu button. It's just a regular button. When clicked, it deactivates itself and the Dialogue Panel:



    4. The dialogue entry node has the Sequence show below:



    The first two lines activate the special buttons I created (Let Me Try Button and Left Arrow Button).

    The last two lines wait for a sequencer message "LeftArrowPressed". When it receives this message, reactivates the Dialogue Panel (in case Let Me Try Button deactivated it) and deactivates Let Me Try Button.


    ---
    To clear up a couple questions in your post, DialogueManager.Pause() pauses the sequencer and timer (if used) but still allows the conversation to run.

    DialogueUI.Open() and Close() aren't the best choices because they partially close out the conversation, leaving it in a bad state.

    If the example above doesn't work for your needs, let me know. I'm sure there's another easy way to accomplish what you want to do.
     
    Mazak likes this.
  29. Mazak

    Mazak

    Joined:
    Mar 24, 2013
    Posts:
    226
    I am off to give this a try!

    Thanks!

    Is there a way to quickly search these forums for this type of wisdom so you don't have to create this over and over?
     
  30. Mazak

    Mazak

    Joined:
    Mar 24, 2013
    Posts:
    226
    Tony,
    YOU ARE THE BEST!

    Since I need to do more than listen for a single key this is what I ended up with:

    1. I added this to UnityUIDialogueUI.cs:

    public GameObject TheGameObject
    {
    get { return gameObject; }
    }

    2. This is my wait for class:

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using MegaWars.Input;
    5. using PixelCrushers.DialogueSystem;
    6. using UnityEngine;
    7.  
    8. namespace MegaWars.DialogSystem.Scripts
    9. {
    10.     public enum WaitForCommands
    11.     {
    12.         Unknown,
    13.         Input,
    14.         Menu,
    15.         Command,
    16.         Event,
    17.         Time
    18.     }
    19.  
    20.     public class WaitFor
    21.     {
    22.         public readonly WaitForCommands cmd = WaitForCommands.Unknown;
    23.         public string arg = "";
    24.         public string mods = "";
    25.  
    26.         public string Conversation;
    27.  
    28.         public bool WaitCompleted;
    29.  
    30.         public WaitFor(string arguments)
    31.         {
    32.             WaitCompleted = false;
    33.  
    34.             var split = arguments.Split(',');
    35.             if (split.Length == 0) return;
    36.  
    37.             if (split.Length >= 1)
    38.                 cmd = (WaitForCommands)Enum.Parse(typeof(WaitForCommands), split[0].Trim().ToLower(), true);
    39.  
    40.             if (split.Length >= 2)
    41.                 arg = split[1].Trim();
    42.  
    43.             if (split.Length >= 3)
    44.                 mods = split[2].Trim();
    45.  
    46.             Conversation = DialogueManager.LastConversationStarted;
    47.         }
    48.     }
    49.  
    50.  
    51.     public class MegaWarsWaitFor : MonoBehaviour
    52.     {
    53.         private List<WaitFor> inputList;
    54.  
    55.         void Awake()
    56.         {
    57.             inputList = new List<WaitFor>();
    58.             Lua.RegisterFunction("MW_Wait_For", this, typeof(MegaWarsWaitFor).GetMethod("MW_Wait_For"));
    59.         }
    60.  
    61.         void Destroy()
    62.         {
    63.             Lua.UnregisterFunction("MW_Wait_For");
    64.         }
    65.  
    66.         public int MW_Wait_For(string arguments)
    67.         {
    68.             // This causes the system to pause until the user does something
    69.             inputList.Add(new WaitFor(arguments));
    70.             return 0;
    71.         }
    72.  
    73.         // has anything happened?
    74.         private void Update()
    75.         {
    76.             if (inputList.Count == 0) return;
    77.  
    78.             var unityUIDialogue = DialogueManager.DialogueUI as UnityUIDialogueUI;
    79.             if (unityUIDialogue != null)
    80.                 unityUIDialogue.TheGameObject.SetActive(false);
    81.  
    82.             foreach (var waitFor in inputList)
    83.             {
    84.                 switch (waitFor.cmd)
    85.                 {
    86.                     case WaitForCommands.Unknown:
    87.                         break;
    88.                     case WaitForCommands.Input:
    89.                         if (dInput.GetKey(waitFor.arg, InputState.FlightInput))
    90.                         {
    91.                             waitFor.WaitCompleted = true;
    92.                         }
    93.                         break;
    94.                     case WaitForCommands.Menu:
    95.                         break;
    96.                     case WaitForCommands.Command:
    97.                         break;
    98.                     case WaitForCommands.Event:
    99.                         break;
    100.                     case WaitForCommands.Time:
    101.                         break;
    102.                     default:
    103.                         throw new ArgumentOutOfRangeException();
    104.                 }
    105.             }
    106.  
    107.             var compeleted = inputList.Where(x => x.WaitCompleted).ToList();
    108.             foreach (var waitFor in compeleted)
    109.             {
    110.                 inputList.Remove(waitFor);
    111.             }
    112.  
    113.             if (inputList.Count == 0)
    114.             {
    115.                 // turn the tutorial back on!
    116.                 if (unityUIDialogue != null)
    117.                     unityUIDialogue.TheGameObject.SetActive(true);
    118.                 DialogueManager.UpdateResponses();
    119.             }
    120.         }
    121.     }
    122. }
    123.  
    3. In Chat Mapper I can simply use this function:
    MW_Wait_For("Input, RotateCW")

    3.a Since RotateCW maps to any key, This will allow the user to do a remapping of the keyboard and it will not break the tutorial.

    I can now use this to trigger on any game event, input, etc in my enum.

    Thanks for your help.
     
    Last edited: Feb 6, 2017
  31. Tiny-Tree

    Tiny-Tree

    Joined:
    Dec 26, 2012
    Posts:
    1,314
    hey @TonyLi i remember you talked about a quest system plugin somewhere, is it still worked on ?
     
  32. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    When I remember, I try to cross-post things like this on the Pixel Crushers forum. Similarly, if I post something there, I usually post a link here for those who don't want yet another forum account to log into.

    Thanks for posting your solution. That's a more flexible approach.

    Yes, absolutely. The WIP thread is here. It's not ready for beta yet, but I'm trying to get it there asap.
     
  33. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    hey TonyLi, i have examined your RFPS Book example and have tried to rebuilt it in my own RFPS Scene, but one thing is not working in my own scene - the switch to the mousemode. ( I see the book with the first page. but i'm still in FPS mode and have no mouse cursor, therefore i can't interact with it.)
    I haven't found the script on the book or the Book Dialog UI Canvas which is reasonable for this switch.
    Where is it, how is it accomplished?

    My second question is:
    I also own the Book Reader component -> https://www.assetstore.unity3d.com/en/#!/content/25143
    which looks very nice and is very easy to implement.
    So maybe it is easier to use this component for me.
    Instead of using your example and trim it so, that it looks like this?
    Is it possible to use this one with the same functionality and integration into DS as your example?
    Or is it better the other way round?
     
  34. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @Hormic - The Dialogue System's RFPS integration pauses player control and switches to mouse mode during conversations -- if the conversation involves the player. Make sure the player is assigned as the Conversation Trigger's Actor.

    To use the Book Reader asset:

    1. When opening the book, tell the player that a conversation is starting:
    Code (csharp):
    1. var player = FindObjectOfType<FPSPlayer>();
    2. player.SendMessage("OnConversationStart", player.transform);
    2. When closing the book, tell the player that a conversation is ending:
    Code (csharp):
    1. var player = FindObjectOfType<FPSPlayer>();
    2. player.SendMessage("OnConversationEnd", player.transform);
     
    Hormic likes this.
  35. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    Thank you Tony!

    I had assigend the player as actor and it doesn't work so it seems there must be something else,
    - Screenshot attached.

    Thank you for the example code, i was trying it but it was not working.
    I integrated this code in the bookreader section where the book is activated, maybe it is the wrong place for this snippet?
    but i guess when i use this, i can't use it in colaboration with DS and use the Text from a DS Conversation. I think therefore much more effort is required, as simple attaching a script or something, is it so?
     

    Attached Files:

    Last edited: Feb 6, 2017
  36. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @Hormic - Does your player correctly pause control and enter mouse mode during regular conversations?

    Since you got the message:
    I wonder if maybe the FPS Player isn't configured for the Dialogue System yet (Component > Dialogue System > Third Party > Realistic FPS Prefab > Disable Gameplay In Conversations).

    If the player does pause control and enter mouse mode in regular conversations, temporarily set the Dialogue Manager's Debug Level to Info. Then reproduce the problem. Look for the line:

    Dialogue System: Starting conversation 'Book' with actor FPS Player and conversant Book (1).

    Make sure that the actor and conversant look correct.
     
    Hormic likes this.
  37. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    OMG, yes of course this was the problem, i was setting up another scene and wasn't thinking.
    So i have to save the player prefab to use it already configured in other scenes.
    Thank you very much Tony now it works well!!
     
    TonyLi likes this.
  38. kk99

    kk99

    Joined:
    Nov 5, 2013
    Posts:
    81
    Can anybody tell me`?

    what is the easiest way to quit/exit the dialogue? e.g. you have a counter or any other condition running in the background and you want to shut down/exit/quit the dialogue so that my OnEnd function is called?
     
  39. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Use DialogueManager.StopConversation(); or the equivalent PlayMaker (etc.) action if you're using visual scripting.
     
    kk99 likes this.
  40. kk99

    kk99

    Joined:
    Nov 5, 2013
    Posts:
    81

    Thank you, gosh so easy :)

    I have been trying so much with these trigger events

    npc.GetComponent<ConversationTrigger>().stopConversationOnTriggerExit = true;
    npc.GetComponent<ConversationTrigger>().trigger = DialogueTriggerEvent.OnTriggerExit;

    but they didnt work^^


    Thanks
     
  41. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Happy to help!

    "Stop Conversation On Trigger Exit" is for a different purpose. If your game allows the player to move during conversations, then if the player exits the NPC's trigger collider it will automatically stop the conversation.
     
    kk99 likes this.
  42. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    Aehmmmm, it works not so well as i thought. :p
    So when i integrate these lines to the bookreader.cs for the other bookreader component:

    Then it works really well just for these books, but all other interactions from RFPS what are induced with the F-Use key are getting stucked.
     
  43. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @Hormic - Here's an example scene:

    RFPSwithBookReader_2017-02-08.unitypackage

    There's a book on a table near the start of the scene.

    To set it up, I created a script named BookPickup.cs and added it to the book:

    BookPickup.cs
    Code (csharp):
    1. using UnityEngine;
    2.  
    3. /// <summary>
    4. /// Add this to the Book. Realistic FPS Prefab will run the PickUpItem() method,
    5. /// which will open the book.
    6. /// </summary>
    7. [RequireComponent(typeof(Book))]
    8. public class BookPickup : MonoBehaviour {
    9.  
    10.     public int pageNumber = 0;
    11.  
    12.     public void PickUpItem() {
    13.         if (enabled) {
    14.             FindObjectOfType<BookReader>().Open(GetComponent<Book>(), pageNumber);
    15.         }
    16.     }
    17. }
    Then I created a script named BookReaderToDialogueSystem.cs and added it to the FPSPlayer GameObject:

    BookReaderToDialogueSystem.cs
    Code (csharp):
    1. using UnityEngine;
    2. /// <summary>
    3. /// Add this to the FPSPlayer. It will freeze the player and unlock the mouse while
    4. /// the book is open. You MUST make changes to BookReader.cs, too.
    5. /// </summary>
    6. public class BookReaderToDialogueSystem : MonoBehaviour {
    7.  
    8.     private BookReader m_bookReader;
    9.     private Book m_currentBook;
    10.  
    11.     void Awake() {
    12.         m_bookReader = FindObjectOfType<BookReader>();
    13.     }
    14.  
    15.     void OnEnable() {
    16.         m_bookReader.openedBook += OnOpenedBook;
    17.         m_bookReader.closedBook += OnClosedBook;
    18.     }
    19.  
    20.     void OnDisable() {
    21.         m_bookReader.openedBook -= OnOpenedBook;
    22.         m_bookReader.closedBook -= OnClosedBook;
    23.     }
    24.  
    25.     void OnOpenedBook(Book book) {
    26.         BroadcastMessage("OnConversationStart", book.transform);
    27.         m_currentBook = book;
    28.     }
    29.  
    30.     void OnClosedBook(Book book) {
    31.         BroadcastMessage("OnConversationEnd", m_currentBook.transform);
    32.     }
    33. }
    Finally, I had to make three small changes to BookReader.cs:

    In the class definition near the top:
    Code (csharp):
    1. public class BookReader : MonoBehaviour {
    2.     public delegate void BookStateDelegate(Book book); // ADD
    3.     public event BookStateDelegate openedBook = delegate { }; // ADD
    4.     public event BookStateDelegate closedBook = delegate { }; // ADD
    In the Open() method:
    Code (csharp):
    1. public void Open(Book book, int pageNumber){
    2.     if (!isActive()){
    3.         SetupBook(book, pageNumber);
    4.         StartCoroutine("AddPages", book);
    5.         openedBook(book); // ADD
    In the Close method():
    Code (csharp):
    1. public void Close(){
    2.     StopCoroutine("AddPages");
    3.     StartCoroutine("WaitClose");
    4.     closedBook(null); // ADD
     
    Mazak and Hormic like this.
  44. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    Wow, its working like a charm, i'm speechless you are awesome!
    Thank you so much for your great and outstanding support! :)

    edit: Ok i thing a little problem is still there.
    So when i open up the book the first time, all is fine and i can move the mousecursor but when i close the book and open it up again, i can't move the mousecursor it is still in FPS mode.
     
    Last edited: Feb 9, 2017
  45. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    I'll check this and get back to you. Does the problem also happen in the included demo scene?
     
    Hormic likes this.
  46. Hormic

    Hormic

    Joined:
    Aug 12, 2014
    Posts:
    251
    Yes it does, i added the scroll on the table near the book in the demo scene.
    But it guess it also occurs when you close the book and open it again.
     
  47. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Okay, thanks. I'll check and reply back here as soon as I can later today.
     
    Hormic likes this.
  48. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    I'm sorry; I can't reproduce the problem. I tested these steps:
    1. Added Scroll to scene; added BookPickup to Scroll. So the table has a gun, book, and scroll.
    2. Played the scene. Read the book, then closed it. Repeated.
    3. Read the scroll, then closed it.
    4. Picked up the gun.
    5. Read the scroll, then closed it. Repeated.
    6. Read the book, then closed it. Repeated.
    Please double check that the problem occurs in your copy of the included demo scene (Dialogue System Examples / RFPS with Book Reader / RFPS Book scene).

    Would it be possible for you to send an example scene or project to tony (at) pixelcrushers.com?
     
    Hormic likes this.
  49. katie-muller

    katie-muller

    Joined:
    Feb 18, 2014
    Posts:
    18
    Hello! I'm currently using Dialogue System as a part of my master's thesis, alongside Love/Hate. I'll be popping in here from time to time with questions :)

    My first question surrounds using my own script's variables to set dialogue conditions. Currently, I am using Love/Hate to keep track of if my characters are angry or happy (which is tracked by an integer value in Love/Hate's script). How can I access that script, check that value, and then determine which dialogue can be displayed? I see the "Conditions" section under Dialogue Entry, but I'm not familiar with Lua. and it seems the Lua Wizard isn't giving me an option to check my own scripts. Thank you! :p
     
  50. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,528
    Hi @katie-muller - Thanks for using the Dialogue System (and Love/Hate)! The Lua Wizard only provides drop-downs for the built-in Dialogue System data (variables, quests, etc.). For custom scripts, you'll need to register your script with Lua and manually enter the function in the Conditions field. (It's actually very simple, and you really don't need to know anything about Lua specifically.)

    This is also how Love/Hate interfaces with the Dialogue System. (The instructions start on page 29 of the Love/Hate manual.) For example, let's say you want an NPC named "Bob" to say how he feels. Add the LoveHateLua component to the Dialogue Manager as described in the Love/Hate manual. This registers C# functions such as "GetHappiness()" with Lua. Then set up the Conditions to use GetHappiness():



    You can use the Script field to set values:



    In the screenshot above, the player's response increases Bob's Happiness and Pleasure by +80.

    You can use the instructions here to register C# functions to get and set values in your own scripts. Let's say your C# script has an integer named angryValue:
    Code (csharp):
    1. public class MyScript : MonoBehaviour {
    2.     public int angryValue;
    3. }
    Add another small script like this to the Dialogue Manager:
    Code (csharp):
    1. public class MyLuaScript: MonoBehaviour {
    2.  
    3.     void OnEnable() {
    4.         Lua.RegisterFunction("GetAngryValue", this, typeof(MyCustomScript).GetMethod("GetAngryValue"));
    5.         Lua.RegisterFunction("SetAngryValue", this, typeof(MyCustomScript).GetMethod("SetAngryValue"));
    6.     }
    7.  
    8.     void OnDisable() {
    9.         Lua.UnregisterFunction("GetAngryValue");
    10.         Lua.UnregisterFunction("SetAngryValue");
    11.     }
    12.  
    13.     public double GetAngryValue(string npcName) {
    14.         // (One of the few Lua quirks is it always uses doubles for numbers.)
    15.         return GameObject.Find(npcName).GetComponent<MyScript>().angryValue;
    16.     }
    17.  
    18.     public double SetAngryValue(string npcName, double newValue) {
    19.         GameObject.Find(npcName).GetComponent<MyScript>().angryValue = (int) newValue;
    20.     }
    21. }
    This script registers the C# functions GetAngryValue() and SetAngryValue() with Lua so you can use them in your Conditions and Script fields like this:



    To save on typing, I only put a condition on the "Go away!" node. But I set the link's Priority to Above Normal. When the Dialogue System determines what node to use, it checks nodes at the highest priority level first. If it finds any valid nodes, it stops there. Otherwise it checks the next-highest priority level, and so on. Since "Go away!" has higher priority than "Hi!", it will always take precedence if Bob's angryValue is >= 50.
     
    katie-muller likes this.