Forum rules - please read before posting.

Conversation via Scripting?

Hi! I'm interested in writing conversation options and responses directly with scripting, but I'm having trouble finding if that's even possible via the scripting guide (I can pull an existing convo via arrays, but I can't set them?)  Is there an example script available of a dialog tree that is written in c#?

Thank you!

- Mo

Comments

  • edited May 2017
    A Conversation's record of options is stored in a List, not an Array, so you can add to them by script by adding a new ButtonDialog class:

    int[] idArray = myConversation.GetIDArray ();
    ButtonDialog newOption = new ButtonDialog (idArray);
    myConversation.options.Add (newOption);


    Where "idArray" is an Array of the existing options internal ID numbers.  This array is used to generate a new, unique ID number for the new option, which is necessary to manage them together.

    For convenience, I'll add a constructor that lets you define the ID number directly, but the code above should work.  You can then assign the various fields in the new ButtonDialog class following this page of the scripting guide.  However again, I'll see about adding constructors that lets you more easily assign the key fields, such as label text and output DialogOption interaction.
  • edited May 2017
    Yaaay!!! Thanks so much this makes a lot more sense now. I was a little confused about triggering custom scripts from here but then realized I need to set both the function and the gameobject with the script.  :D :D :D Thank you so much again!

    In case someone comes across this in the future and gets stuck on the "how to make the selected option run a custom script" here (after the code Chris suggested, and assuming the response script is attached to the same gameobject that has the dialog option script):






    newOption.label = "Test Option";
    newOption.customScriptObject = gameObject;
    newOption.customScriptFunction ="customResponseFunction";
    myConversation.options.Add (newOption);
      
  • edited May 2017
    Ooh so I have one more question on this topic,

    I have the ButtonDialog set to ReturnToConversation:

    newOption.conversationAction = AC.ConversationAction.ReturnToConversation;

    But, when I play the dialog, it just hangs and I can't click to continue:

    KickStarter.dialog.StartDialog (KickStarter.player, "Words", false, -1, false, false);

    Probably related, but if I add a second dialog line after that, it just skips to the last dialog line. I've toyed around with the true/falses in StartDialog with little success (tho it works if outside of a conversation..) Suggestions?

    thanks again!!!
  • Are these responses all set to custom objects?  The "Return To Conversation" option only works if they're running ActionLists (i.e. DialogOption instances set via the ActionList Editor) when run.  Otherwise, you'll need to re-run the Conversation at the end of your custom response function.
  • Hmm, so I can't click out of the dialog (it's set not to continue unless the player clicks for the next line).  When I run the conversation after that line of dialog, it shows that menu underneath the unskippable dialog line... here's an example gif (kinda hard to see, but the purple highlight is the conversation layer behind the dialog being spoken.)
    image
  • Hmm, added this work around, not sure if it's good practice though, and it blocks all of the hotspots because onmousedown requires a box collider :/






        void OnMouseDown() {

            if (KickStarter.dialog.IsAnySpeechPlaying(false) == true){

                KickStarter.dialog.KillDialog(KickStarter.dialog.speechList[0]);

            }

        }
      
  • You could use Active Inputs to kill dialog when a button is pressed (see Section 2.14 of the Manual) without the need for a collider.

    Are you choosing to not wait for the dialogue to finish before showing the Conversation?  If you want a "final" line to show at the same time (e.g. Mass Effect-style), you can show it in a Menu whose Appear type is set to Manual instead.
  • edited May 2017
    Hm, so I just gave Active Input a try, set the Action List to kill all dialog, but when I select a dialog option in the conversation it skips the dialog line all together (or passes it too fast to read).  I guess I'm a little stuck on figuring out how much the API can do? In the action-list version of a conversation, the whole dialog line plays out and waits until the player clicks the mouse to the next line.  Maybe my response dialog function needs more than just a KickStarter.dialog.StartDialog call?  My goal is to finish the dialog before seeing the choices or going to the next dialog line.  But if I put a second line of dialog in the response function, it plays through the first one too fast to notice, and gets stuck displaying the last dialog in the function.  If I end the function with myConversation.Interact() then it hides that new menu underneath the dialog line and doesn't move on.  Thanks again for all your help and patience! I know I'm super close to understanding this..
  • Though most use Actions in favour of the API, I would like the hard-coded route to be just as powerful - so I'm keen to see this issue resolved for you.

    The Active Input is probably responding to the user clicking on the Conversation option as well - so you would need to make it conditional to only work at certain times (during Cutscene gameplay may be enough).

    However I wouldn't have thought you'd need to resort to this method.  I think we need to back up a post or two because I'm not perhaps fully understanding the issue.  Is this a problem with the last dialogue being played before a Conversation, or all dialogue lines?  A complete description of the exact behaviour of it all (with your code included) would be very helpful.

    Speech lines should handle user input from within - meaning so long as the game is in the Cutscene state, they should respond to user input whether they were called from code or from Actions.

    The main thing that separates a single StartDialog function call from the "Dialogue: Play speech" Action is that the Action can be made to wait until the dialogue has finished playing before running the next Action.  If you're coding this, you need to make sure the dialogue has finished before running the next Conversation / line.  This could be done in a coroutine, ie:

    KickStarter.dialog.StartDialog (...);
    while (KickStarter.dialog.CharacterIsSpeaking (myCharacter))
    {
      // Wait before continuing
      yield return new WaitForFixedUpdate ();
    }

  • edited May 2017
    Hmm On Cutscene doesn't seem to work for Active Input, does KickStarter.dialog start a cutscene or is there a way to declare one via code?

    I added the coroutine and that helps the dialog play the line, but I can't click for the next line/conversation/or return to gameplay.  It's a problem with all dialog lines, I can put one followed by the while loop, and then another dialog line, and it'll never get past the first line.  If I put the first dialog line, the second line, then the coroutine, it skips directly to the last line.  So in the sample code below, the second line never plays because I can't click past the first.





        IEnumerator testResponse () {

            KickStarter.dialog.StartDialog(KickStarter.player, "Response dialog.", false);

            while (KickStarter.dialog.CharacterIsSpeaking (KickStarter.player))

            {

                yield return new WaitForFixedUpdate ();

            }

            KickStarter.dialog.StartDialog(KickStarter.player, "Response dialog2.", false);

        }
      
  • You need to put the game into cutscene mode manually if you're doing it through script - see the front page of the scripting guide.  Apologies for neglecting that.  A tutorial on scripting Interactions can be found here.

    What is the context of this code - where are you calling it from?  All of your non-instant code needs to be in a co-routine.  Try this adapted script: it'll show a button in the corner that shows two lines that can be skipped:

    http://pasteall.org/392782/csharp

  • edited May 2017
    Starting/ending the cutscene did the trick, thanks for the example code to compare to also :)  I have one final question ;)  Is there any way to pass a var through 




    newOption.customScriptFunction 
    ?  I've tried passing it a string "functionName(var)" but it just tries to run a function with that name.  No worries if it isn't possible, just curious if there's a trick to it.  

    Thank you again for helping me work through this :)


  • You're welcome!  I'm afraid not about the parameter, though.
  • A bit late to the party here, but just a quick thanks to @ChrisIceBox and @MoCohen for this thread, because it enabled me to quickly implement a similar feature in my own current project

    As the information is all a bit scattered (and some of it no longer exists), here, for anyone else looking for the general format for scripted dialogues (or similar types of cutscene), is the coroutine that I'm using in my own project. It simply displays a Player statement and an NPC response, and was created after pulling together all the information contained in this thread

    It's very simple, but it demonstrates the principles involved. Invoke it using something like:

    StartCoroutine(DialogueCutScene(playerChar, playerSays, actorChar, actorSays));

     private IEnumerator DialogueCutScene(Char _player, string _playerSays, Char _actor, string _actorSays)
    {
        KickStarter.stateHandler.StartCutscene();
    
        KickStarter.dialog.StartDialog(_player, _playerSays);
        while (KickStarter.dialog.CharacterIsSpeaking(_player))
        {
            yield return new WaitForFixedUpdate();
        }
    
        KickStarter.dialog.StartDialog(_actor, _actorSays);
        while (KickStarter.dialog.CharacterIsSpeaking(_actor))
        {
            yield return new WaitForFixedUpdate();
        }
    
        KickStarter.stateHandler.EndCutscene();
    }
    
  • edited June 2020

    It appears that:
    KickStarter.stateHandler.StartCutscene();
    KickStarter.stateHandler.EndCutscene();

    have been changed to:
    KickStarter.stateHandler.EnforceCutsceneMode = true;
    KickStarter.stateHandler.EnforceCutsceneMode = false;

    is that right?

  • Correct - see the Changelog's "Upgrade notes" and "API" sections for full details on function/variable changes.

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.