Dialogue - A simple and easy way to make characters talk

So my latest asset store submission is a simple way to make characters talk to each other (at least I think it’s easy). Dialogue allows you to:

  • Have a click-through dialogue with any number of characters talking.
  • Write in an easy to understand script like format.
  • Use gotos and ends to navigate your script.
  • Use calls to send things back to your behaviour.
  • Give the player options to choose and make the dialogue dynamic.
  • and more… :slight_smile:

As an example dialogue script (taken from the demo scene for robot 4):

Robot 4:        Hello!
Player:            {Hello!}                [goto hello]
                {What do you demo?}        [goto whatDemo]
        
-hello
Player:           Whoa! That looks usefull!
Robot 4:        Good isn't it? This way the player gets a little more freedom in what they do.
Robot 4:        It could be used fo buying things in a shop for instance.
Player:           That's cool, thanks!
                [end]

-whatDemo
Robot 4:        I demo the option system.
Robot 4:        It allows players to choose what they say and allows you to take different actions!
Player:           That's pretty cool, thanks!
                [end]

Demo :slight_smile:

And it’s all for only $5 :smile:
Click here to go to the asset store

Update 1.3.3 available now!


Ability to load variables into the script to show up-to-date information to the user!
Plus bug fixes and some spelling mistakes rectified :slight_smile:

  • Jamie
  • Ninjapoke Studios


Demo is now up! :smile:

(I’ve been a little busy recently so didn’t get chance, sorry)

-NinjaPoke studios

Update 1.1
We’ve completely redone the interface!

We realised it’s wasn’t as nice as we’d like to incorperate into your projects so we’ve made it even easier to open dialogues:

DialogueManager.DisplayDialogue(filename);

Plus we’ve also got a pretty long list of what we want to add so look forward to more updates! :smile:

Buy now for $5!!

Will this work on mobile?

How do you make the dialogue say player names or string variables?

Hi Gekigengar,

Sorry I haven’t seen this sooner my email notifications must have been turned off.

The character speaking is automatically displayed alongside the text (although you can remove that quite easily). As for displaying variables, it’s on my todo list… :stuck_out_tongue: You should be able to define your own tag (something like variableName) and replace it with your variable just before it’s displayed using a custom renderer but it might have to be a bit of a hack until I add functionality. Of course if you want to modify the source code and make a more permenant feature you could!

I’m trying to test mobile right now :slight_smile:

Apologies and Regards,
Jamie

Regarding Mobile, I dont see any reason why it shouldn’t work. It uses Unity’s own GUI sytems and no external dependancies, if it gets a bit deformed then you can always write a custom renderer for it :slight_smile:

Thanks for the reply!,
If you’d develop this further, this might even be the best dialog system so far.
(Easy to track, Author friendly, and Localization friendly.)

Perhaps, make it so it can change global variables?
Or even, play uSequencer events and such.

and yes, Var sounds great! Please do it asap!
I am thinking the only drawbacks is that I can’t play animation or change variables through this.

Does the system supports if/then/else statements?

Can it call functions in between the texts?

If this supports the New UI, that would be so cool!

I am actually thinking of rAthena style of NPC scripts.

prontera,151,192,4   script   Monk::reset_monk   834,{

   set .@ResetStat,75000;   // Zeny for stat reset
   set .@ResetSkill,75000;   // Zeny for skill reset
   set .@ResetBoth,125000;   // Zeny for resetting both together
 
   cutin "bu_maggi1", 0; //Display cut-in image of name maggi expression 1 at position 0 (0 = left, 1 = center, 2 = right)
   mes "[Monk]";
   mes "Hello adventurer.";
   next; //Display the "Next" button for next dialog page.
   cutin "bu_maggi2", 0; //Display cut-in image of name maggi expression 2 at position 0 (0 = left, 1 = center, 2 = right)
   mes "[Monk]";
   mes "I decided to help those in needs";
   mes "After mastering the art of enlightenment.";
   mes "If you need my aid by any means,";
   mes "I am more than willing to aid you";
   next;
   cutin "bu_maggi1", 0;
   mes "[Monk]";
   mes "For a set of fee.";
   mes "Reset Stats: "+ .@ResetStat +"z";
   mes "Reset Skills: "+ .@ResetSkill +"z";
   mes "Reset Both: "+ .@ResetBoth +"z";
   mes "Please select the service you want:";
   next;
   switch(select("^FF3355Reset Skills:Reset Stats:Reset Both^000000:Cancel")) {
   case 1:
     mes "[Monk]";
     if (Zeny < .@ResetSkill) {
       mes "Even monks need zeny to survive nowadays..";
       close; //Display the close dialog button to close conversation.
     }
     set Zeny, Zeny-.@ResetSkill;
     sc_end SC_ALL;
     ResetSkill;
     specialeffect2 158;
     mes "There you go!";
     next;
     mes "[Monk]";
     mes "Come again soon..!";
     close;
   case 2:
     mes "[Monk]";
     if (Zeny < .@ResetStat) {
       mes "Sorry, you don't have enough Zeny.";
       mes "For a greater good, comes a great price.";
       close;
     }
     set Zeny, Zeny-.@ResetStat;
     ResetStatus;
     specialeffect2 371;
     mes "All done..!";
     next;
     mes "[Monk]";
     mes "Come again soon..!";
     close;
   case 3:
     mes "[Monk]";
     if (Zeny < .@ResetBoth) {
       mes "Sorry, you don't have enough Zeny.";
       mes "Come again next time.";
       close;
     }
     set Zeny, Zeny-.@ResetBoth;
     sc_end SC_ALL;
     ResetSkill;
     ResetStatus;
     specialeffect2 338;
     mes "done..!";
     next;
     mes "[Monk]";
     mes "Heh, heh, heh.";
     mes "It's a pleasure to do business";
     mes "With you.";
     close;
   case 4:
     close;
   }
}

As you can see, it is almost similar to yours, but it has the ability to change variables, or call functions such as cut-in images, play special effects, ResetSkill() functions, if then else statements, etc.

Thanks for the suggestions, I don’t really get around to much actual game design anymore so that’s some interesting food for thought!

Regarding animation and changing variables, you already can :wink: you can make calls to C#/JS functions and even pass in parameters using the call statement :slight_smile:

I also quite like the image cutin, might be a bit horrible to procedurally generate the GUI though…

Unity’s new uGUI is now fully supported, I just haven’t posted anything on here about the update!

Jamie

1 Like

Another NPC script, this time, with goto jumps.
As you can see, the script can either set a local variable, or a global variable.

It can also use text colors such as ^00AA00Magnifiers
Which is green color code. (RRGGBB)

These are a few inspirations which might allow you to create the most flexible dialog in the asset store! (While these are not perfect, the possibilities are huge!)
(I don’t know if this might help, but yeah!)

I think your dialog system is extremely unique, compared to the other competitors,
as this is the only hassle free, untangled solution, and writer friendly dialog system
I have come across in the asset store.

I hope you can make it even more powerful by implementing colors, if/then/else, local variable and global variable setups, and a while-loop.

//============================================================
//= Identifier Script
//============================================================

prontera,132,215,5    script    Identifier    833,{

// Price
// =====
// This is the Price in Zeny for one identified Item

set @price, 500;

// Actual Script Begins Here
// =========================

mes "[Identifier]";
mes "Hello there!";
mes "I can identify all your unidentified items.";
mes "It's just "+@price+" Zeny each item.";
next;
menu "Sure.",-,
"No thanks...",L_Bye;

getinventorylist;
set @identify, 0;

for(set @i, 0; @i < @inventorylist_count; set @i, @i + 1) {
if (@inventorylist_identify[@i] == 0) set @identify, @identify + 1;
}

if (@identify == 0) goto L_Nothing;

mes "[Identifier]";
if (@identify < 2) {
mes "You've got one unidentified item in your inventory.";
mes "I'll identify it for "+@price+" Zeny.";
} else {
mes "You've got "+@identify+" unidentified items in your inventory.";
mes "I'll identify them for "+(@identify * @price)+" Zeny.";
}
mes "If you've got any ^00AA00Magnifiers^000000, I'll take those instead.";
mes "Shall I start now?";
next;
menu "Ok, let's go!",-,
"What a ripoff...",L_Bye;

getinventorylist;
set @identified, 0;

for(set @i, 0; @i < @inventorylist_count; set @i, @i + 1) {
if (@inventorylist_identify[@i] == 0) {
if (countitem(611) > 0) delitem 611,1;
else if (Zeny < @price) goto L_NoZeny;
else set Zeny, Zeny - @price;
delitem2 @inventorylist_id[@i],1,0,0,0,0,0,0,0;
getitem @inventorylist_id[@i],1;
set @identified, @identified + 1;
}
}

mes "[Identifier]";
mes "Well, I identified everything!";
mes "I've identified a total of "+@identified+" items for you.";
mes "Come again.";
close;

L_Nothing:
mes "[Identifier]";
mes "You don't have any unidentified Items.";
mes "Come again when you do.";
close;

L_NoZeny:
mes "[Identifier]";
mes "You don't have enough Zeny.";
close;

L_Bye:
mes "[Identifier]";
mes "Come again soon.";
close;

}

This one is an example of variable arrays, which is extremely useful.

prontera,163,172,3    script    Stylist#custom_stylist    878,{

    cutin "orleans_1",2;
    mes "[Stylist]";
    mes "I can change your style in a blink of an eye..!";
    next;
    cutin "orleans_2",2;
    mes "[Stylist]";
    mes "It is a pleasure for me to see the citizens in a better style..!";
    next;
    cutin "orleans_6",2;
    mes "[Stylist]";
    mes "How may I help you today..?";
    setarray .@Styles[1],getbattleflag("max_cloth_color"),getbattleflag("max_hair_style"),getbattleflag("max_hair_color");
    setarray .@Look[1],7,1,6;
    set .@s, select(" ~ Cloth color: ~ Hairstyle: ~ Hair color");
    set .@Revert, getlook(.@Look[.@s]);
    set .@Style,1;
    while(1) {
        setlook .@Look[.@s], .@Style;
        message strcharinfo(0),"This is style #"+.@Style+".";
        set .@menu$, " ~ Next (^0055FF"+((.@Style!=.@Styles[.@s])?.@Style+1:1)+"^000000): ~ Previous (^0055FF"+((.@Style!=1)?.@Style-1:.@Styles[.@s])+"^000000): ~ Jump to...: ~ Revert to original (^0055FF"+.@Revert+"^000000)";
        switch(select(.@menu$)) {
            case 1:
                set .@Style, ((.@Style!=.@Styles[.@s])?.@Style+1:1);
                set .@sx, rand(1,7);
                cutin .sface$[.@sx],2;
                if (.@sx <= 3){
                    specialeffect2 457;
                } else if (.@sx == 4) {
                    specialeffect2 890;
                } else if (.@sx >= 5) {
                    specialeffect2 463;
                }
                specialeffect 4;
                specialeffect2 5;
                specialeffect2 53;
                break;
            case 2:
                set .@Style, ((.@Style!=1)?.@Style-1:.@Styles[.@s]);
                set .@sx, rand(1,7);
                cutin .sface$[.@sx],2;
                specialeffect 4;
                specialeffect2 5;
                specialeffect2 53;
                break;
            case 3:
                message strcharinfo(0),"Choose a style between 1 - "+.@Styles[.@s]+".";
                input .@Style,0,.@Styles[.@s];
                if (!.@Style) set .@Style, rand(1,.@Styles[.@s]);
                set .@sx, rand(1,7);
                cutin .sface$[.@sx],2;
                specialeffect 4;
                specialeffect2 5;
                specialeffect2 53;
                break;
            case 4: set .@Style, .@Revert;
                setlook .@Look[.@s], .@Revert;
                set .@sx, rand(1,7);
                cutin .sface$[.@sx],2;
                specialeffect 4;
                specialeffect2 5;
                specialeffect2 53;
                break;
        }
    }

OnInit:
    .sface$[1] = "orleans_1";
    .sface$[2] = "orleans_2";
    .sface$[3] = "orleans_3";
    .sface$[4] = "orleans_4";
    .sface$[5] = "orleans_5";
    .sface$[6] = "orleans_6";
    .sface$[7] = "orleans_7";
    end;
}

This one is a part of my written script of an array and a while loop example.

    cutin "job_ko01",0;
     mes "[Muramasa]";
     mes "Hmm?";
     while(1){ //While(1) will always return true, hence the dialog will re-occur at the end of the dialog until close2; function is called to close the dialog.
       next;
       mes "[Muramasa]";
       mes "Anything you need?";
       next;
       switch(select("About Oboro:About the Demon Blades:I seek your advice.:End Conversation.")){
         case 1:
           cutin "job_ko02",0;
           mes "[Muramasa]";
           mes "^008800Oboro^000000 is a colleague of mine from back in the old times..";
           next;
           cutin "job_ko01",0;
           mes "[Muramasa]";
           mes "I discovered him and his blades when we were young, enchanted by its beauty.";
           next;
           mes "[Muramasa]";
           mes "He has always been a bit of an oddball since back then..";
           next;
           cutin "job_ko04",0;
           mes "[Muramasa]";
           mes "Despite his attitude, his craftsmanship techniques are unorthodox, and his skills were unparalleled.";
           next;
           cutin "job_ko02",0;
           mes "[Muramasa]";
           mes "I think it is better if you speak to him if you wish to know more.";
           break;
           end;
         case 2:
           cutin "job_ko01",0;
           mes "[Muramasa]";
           mes "Back in those times, all we care about is to create the blades of our dreams..";
           next;
           mes "[Muramasa]";
           mes "Both ^008800Oboro^000000 and Me, partners each other soon after..";
           next;
           cutin "job_ko01",0;
           mes "[Muramasa]";
           mes "It is because of this one vision we both share, to create a living blade.";
           next;
           mes "[Muramasa]";
           mes "He pursue it through the beauty within magical blades in the west.";
           next;
           mes "[Muramasa]";
           mes "Blah blah blah..";
           break;
           end;
         case 3:
           cutin "job_ko01",0;
           mes "[Muramasa]";
           mes "Advices..? Hmm..";
           next;
           cutin "job_ko04",0;
           mes "[Muramasa]";
           mes "^FF8800" + .obquote$[rand(1,.maxobquotes)] + "^000000";
           next;
           mes "[Muramasa]";
           mes "How is that..?";
           break;
           end;
         case 4:
           cutin "job_ko01",0;
           mes "[Muramasa]";
           mes "Well then, come again anytime.";
           close2;
           cutin "",255;
           end;
       }
     }
   }
   OnInit:
     .obquote$[1] = "By being lost, one is given the chance to rediscover their purposes.";
     .obquote$[2] = "It is not defeat if you end up winning last, it is progress.";
     .obquote$[3] = "With great power, comes great responsibilities.";
     .obquote$[4] = "There is nothing bad in losing your past, it is an opportunity to discover your new side.";
     .obquote$[5] = "By being lost, one discovers a new path.";
     .obquote$[6] = "Dangers is parcels and part of adventure.";
     .obquote$[7] = "Never underestimate the strengths in numbers.";
     .maxobquotes = 7;
     end;
}

I’ll definately look into those features for you and other users.

If/Else/Endif is something that I’d quite like to implement, that would then allow while loop items (though bare in mide you can still do this provided that it is only the user exiting the loop).

Colour is another that would be quite nice to implement, but how to do that is a little more tricky :slight_smile:

Jamie

Update 1.3
Update 1.3 is out!

It’s not a very big update it simply adds a new renderer for Unity’s new GUI system.

(Also I have no clue where update 1.2 is… it’s just missing from the thread I think…!)

Download from the Asset Store!

1 Like

Nice update!
No variables and text colors yet?

I see that the choices are separated into 2 when there is 2 choice,
what happen if there is more than 2 choices?

Does this have an input method anyways?
(Input a number question, input a string for names, etc.)

Nope I’m afraid not, submitted it before you asked so that’ll be a future update!

Yup it’ll split into as many as needed, obviously it’s the designers responsibility to make sure it’s still readable as the buttons get smaller though, I might see if it’s possible to split onto multiple lines at some point.

It doesn’t have input because there aren’t variables yet! Your best bet would be to call your own method to throw a prompt up and then process that as you need, until something better’s in place :slight_smile:

Jamie

Purchased today, will be waiting for updates!
Its amazing!

Glad you like it :slight_smile:

I have a lot on my plate at the moment so I can’t guarentee anything fast! :slight_smile:

I need guidance in modifying the system, on where and what to change.

I want to make a [nextpage] label.

so that the dialog displays the next line in the same box until the [nextpage] label is reached.

when it hits the [nextpage] label, it will clear out the lines and start anew.

This way I can manage what to display and where to stop scrolling.

When pressing next, the scroll ends at the next semicolon.
And display the next text one row below the end of the current line marked by the colons.

Test : Oh, hi!;
My name is Test,;
Nice to meet you!;
[nextpage]
$Player$ : Hello;
,I am $Player$;
, Nice to meet you too!;
[nextpage]
Test : How you doin mate?;
Anything great?;
Player : I am doing just fine!;
[end]

Any help?

I noticed that you don’t need to implement colors and styles to the system btw.

I tried using rich-text, and it works in the system from out of the box.

http://docs.unity3d.com/Manual/StyledText.html

Ooohhh I never knew you could do that! Thanks :smile:

Any news on using variables on dialogues? :s

Now everything is perfect except dialogues with variables.

Hmm good question… I was under the impression I had submitted that… :face_with_spiral_eyes: I’ll try and sort that today sorry.