Dialogue system

Our current in-development project. Slash your way through an enemy horde in this musou-inspired action roguelike with random loot but strategic builds.
Post Reply
User avatar
celes
Posts: 55
Joined: Sun Feb 15, 2026 8:09 pm
Location: The offices at Carrot Corp
Pronouns: she/they

Dialogue system

Post by celes »

I've been taking a bit of a break from the "core gameplay loop" so next up on the menu working on the lore and creating the area where the metaprogression is gonna happen: The Hub.

But before we reveal any details about the hub (it's a bit of a spoiler :blobpeek:). I've started working on a new dialogue system. So time for a micro devlog!

Dialogue is one of those things that I could over-engineer to no end and end up at Disco Elysium levels of coolness... That'd be really nice, but if I ever wanna get there, I feel it's something for future me to worry about. I want to start simple and expand as needed, so I think something like RPG Maker dialogue system is gonna be best. This is what I have, for now:
dialogue.gif
dialogue.gif (45.72 KiB) Viewed 360 times
Other than a reminder that my little UI library is cool and some appreciation for FontStashSharp's rich text mode, there wasn't really much to displaying the dialogue itself.

Storing the dialogues, however, was a bit more interesting. :hammyeyes: Carrot Survivors had the dialogues embedded in code. But for this time I wanted to experiment with something a bit easier to author, so my first instinct was to develop a little dialogue scripting language, with a custom handwritten parser. Like most people who were infected by the langdev virus, I have this urge to get my fix by writing a tiny parser from time to time... And I was about to do that, so I started researching to see what kinds of languages people were using to store in-game dialogues. Then I stumbled upon this:
image.png
image.png (152.29 KiB) Viewed 360 times
Keep in mind I skipped reading the question (a bit of a bad habit of mine), and I stopped reading after the first sentence of the answer, the one I highlighted.

I only needed those words, and I was defeated. Langdev zoomies dead on the spot. :pensivecat: The ominous music rang inside my head:

Now I remember! I was lost in the sea of human souls.
Wrangler of the pom, beacon of the enterprise. You can call me Duke.
From henceforth, I am at your service. For I am thou, and thou art I.


Of course it's hypertext. It's always hypertext isn't it? XML fit every criteria I had for this little dialogue scripting language:

- Allows defining basic structure: A dialogue is a list of commands, commands allow setting the character and the portrait, display a text, display a bunch of choices, set a variable... Different commands have different parameters and some commands contain messages.
- Inside messages, I need good support for mixing plain text and other kinds of metadata. I have implemented color for styling already, but I also have ideas to embed custom commands in the middle of the text. For example, to set text speed, play sound effects or read variables (like the player's name).

My plan is not to add all the features I listed here for this game. But I like to make the thought exercise early on to know if this is gonna be a system that can grow with me, hopefully in future games!

Implementation-wise XML simplifies things by a lot. The parser is already there, every language has an XML parser. Not the simplest language and not the cheapest to parse by far, but it's just a bunch of dialogue. Anyone who obsesses about the memory usage of parsing a bunch of dialogue lines should try writing one (1) megabyte of text just to get a sense of how silly worrying about memory in this scenario is.

Another great point in favor of XML is people are already familiar with it. I'm not going to be doing the bulk of the writing (hi Kathee! :blobpeek:), so optimising this language for myself would be silly. I don't want to be fixing bug reports for the dialog language parser :akko_nope:. Plus, these files may be handed off to other translators too, and I'll risk my XKCD#2501 status to say the average person is already familiar with XML (via HTML, if nothing else), and CSS of course (of course!).

XML also saves me a bunch of work on the tooling front. Tooling for XML is not excellent, but it's adequate. My editor already has syntax highlighting and auto-formatting for XML. It wouldn't be hard to add squiggles based on XML-Schema which would get me 80% of an LSP at 1% of the cost. Great tradeoff!

Anyway, XML! This is the XML dialogue from the clip above. Writing the "parser" for this, plus the UI bits and snippets took a few hours over the last couple days, so I'm very happy with the experiment.
image.png
image.png (59.43 KiB) Viewed 360 times
Now, time to add some lore into the game! :akko_fistup:
 

POSTREACT(ions) SUMMARY

Purple Heart (1)
Sugui
User avatar
palas
Posts: 8
Joined: Tue Feb 17, 2026 3:24 pm

Re: Dialogue system

Post by palas »

Oh man I was so ready for a language parsing tangent! :blobcatchewwire:
As for XML, this was kinda eye-opening. For *dialogue* use case specifically, with different styling, modifiers, external variables etc, seems like hypertext is a clear winner. With say JSON and its inability to intertwine plain text with attributes, writing something similar to your provided example would be pretty cumbersome.

How do you handle loading dialogue into memory? Is it preloaded upfront or on demand? If it's the latter, is it cached in any way?
 

POSTREACT(ions) SUMMARY

User avatar
celes
Posts: 55
Joined: Sun Feb 15, 2026 8:09 pm
Location: The offices at Carrot Corp
Pronouns: she/they

Re: Dialogue system

Post by celes »

Hehe me too! I was hoping for a good parsing tangent but alas :pensivecat:

I was thinking what other languages could be used for this and XML is quite unique in that it allows structure, plain text inside the structure, and then going back to structure inside the plain text in a flexible way. This is not something other languages like JSON or YAML can do, once you're in a string, you can't go back to data.

I guess BBCode (the thing this forum uses for styling) allows for a very similar use case, but XML is going to have better tooling support all-around!

For loading into memory, I open the XML file using the `XmlDocument` C# class, which loads it all into memory, then I parse it into the data structures I need, which are not a direct mirror of the XML but something a bit closer to what I need in-engine. For example, all the styling tags are flattened as a sequence of commands I call MessageFragment.

For the actual memory management aspect of it, I use my asset system which lazily loads assets the first time you request them. So you'd ask for the asset "dialogue/test.dialogue.xml", and the asset system would hand you a handle object, when you call .Get() on it for the first time, the thing is loaded from disk into memory. The XML tree itself is discarded after loading (not by me, the GC takes care of it) and I just keep my data structures. One nice aspect of having handles for assets like this is that the .Get() method is what I use to check for changes during hot reloading, when I detect a file change I set a dirty flag for the asset and its .Get() method will triggers another load the next time it's called.

On the subject of hot reloading: If you don't keep the reloading use case in mind during development you'll create a solution that's unfit for it. For example, here, if I wrote the naive version of my dialogue UI, and then reload the currently active dialogue it's very easy to crash the game with silly stuff like: "there's now one less line of dialogue so you get an out of bounds access". You have to write the code with the mindset that the current dialogue could change at any time, and the UI should adapt immediately. This is why immediate-mode stuff pairs so well with hot reloading and why hot reloading is so hard to retrofit into an existing system that wasn't built for it.

Anyway, in case you're curious here are the type definitions that get loaded into memory from the XML, the parsing code for these should be pretty obvious, it's just a recursive function that walks the XML tree. Also note how I'm finding more use cases for Dusharp! It's a pretty nice library all around.

Code: Select all

public List<DAction> dialogueActions;

public enum CharacterMood {
    Grin,
    Happy,
    Sigh,
    Angry,
    Laugh,
}

[Union]
public partial struct MessageFragment {
    [UnionCase]
    public static partial MessageFragment Text(string name);

    [UnionCase]
    public static partial MessageFragment SetColor(string? color);
}

[Union]
public partial struct DAction {
    [UnionCase]
    public static partial DAction Character(string charName, CharacterMood mood);

    [UnionCase]
    public static partial DAction Talk(List<MessageFragment> messageFragments);
}
 

POSTREACT(ions) SUMMARY

User avatar
Sugui
Posts: 18
Joined: Tue Feb 17, 2026 12:50 pm
Location: Europe
Pronouns: she/her

Re: Dialogue system

Post by Sugui »

Great post! I was already interesting in implementing something like this, so I'm really happy that this came out at this moment :bunhappy:

I'm really relieved that you actually found an easier way to implement dialogues without having to write a parser from scratch :blobcatgiggle:. Having things like XML, it would be a bit of a waste of time to not use it. I mean! Writing your own language for something like this sounds very fun, especially if you are learning to write parsers or something! But if your goal is to make a game, that time would be better spent in writing actual dialogues of the game :akko_smile:.

I noticed that your XML format assumes some specific rules that can be overlooked, and be a bit problematic especially if the features keep growing, and especially if someone (🪼) external of you helps you to write dialogues. For example, I assume that, the first child of a <dialogue> block must be a <character> block, so the engine knows what face to put at the start. Did you thought about using an XML schema to define the structure of the XML? I think it could be helpful :neobot: . Just in case if you don't know what I'm talking about, I think this provides a good example https://www.w3schools.com/XML/schema_example.asp. I guess there should be good LSP support for this kind of thing...

Now, go and start writing some good lore to keep us addicted to your game! :akko_fistup: :blobcatheart:
 

POSTREACT(ions) SUMMARY

User avatar
celes
Posts: 55
Joined: Sun Feb 15, 2026 8:09 pm
Location: The offices at Carrot Corp
Pronouns: she/they

Re: Dialogue system

Post by celes »

Yup! I wanna look into XML-Schema support once the thing is a bit more fleshed out, hopefully there's a nice extension that shows validation errors inline, that'd make for a pretty good user experience

That said, the UI is built with the use case in mind that there may not always be a character portrait so the chatter command is not mandatory ^^
 

POSTREACT(ions) SUMMARY

Orange Heart (1)
Sugui
Post Reply