cartoon pic of site's author
Blog  |  D&D Stuff  |  About  |  Other Places  |  rss logo

A dialogue on dialogues

First off, hey guess what I remembered I had a site where I had a blog! I'm going to try to write write more longer posts about Delve and maybe other things and you know what? Here's a good spot for when my thoughts get a bit too long for bluesky

NPC Dialogue

Long ago, in the ancient days (late spring/early summer 2024) of Delve's development, I was at a point where there were enough NPCs that I wanted to ditch handling dialogue in pure C# (this was always the plan of course). I wanted to be able to edit NPC scripts without needing to recompile the game. I did some very perfunctory researched before settling writing my own script system. I don't remember finding any good examples of open source games with a Stardew or RPG-esque dialogue system I could crib notes from and Ink seemed big and complicated. I felt like I could just write my own baby dialogue system in less time than it would take to integrate someone else's. I'd also finished working through Part 1 of Crafting Interpreters and that may have biased my thinking...

What I came up with was a syntax that was loosely based on Scheme/lisp. Despite having not too much experience in Scheme. I did work through the Little Schemer a few years back, and as I went along implemented a (very, very bad) top Scheme interpreter. I need to revisit the Little Schemer because the chapter on the y-combinator went totally over my head.

A sample script might look like:

(
  (say 
    (pick
      ("I thought I'd make a few zorkmids selling gear to adventurers, but this dungeon is way too dangerous!"
      "Go to where the customers are, they said. Location is key, they said."
      "I'm selling off my remaining stock at a discount and getting out of here.")
    )
  )
  (shop-menu)
)

This just picks a random line of dialogue to say to the player (and displays a shop menu since this NPC is a travelling peddler).

Not going to lie, this feels like tech debt, but I had a lot of fun writing the parser and mini-interpreter that handles NPC dialogue. In my initial version, I never actually allowed definable variables. There were hard-coded variables so you could do things like:

(
  (cond
    ((= MET_PLAYER false) 
      ( 
        (say "I used to be an adventurer like you! Sure the top floors of the dungeon are all #EARLY_DENIZEN and rats, but then things get a lot worse.")
        (set MET_PLAYER true)
  ...
)

However, today I was wanting to do things like add more options to lists of dialogue longs based on conditions in the game. Up to now, I was very awkwardly using cond expressions to select from entirely separately lists. But it would be much easier to just do this:

  (def lines '("It is my duty to look after the spiritual well-being of #TOWN_NAME." 
          "Have you heard the good word about Huntokar?"
          "I feel in my bones that the [BRIGHTRED old evil] begins to stir once more."
          "Long ago, the ruins were a mighty kingdom. But then a great evil arose deep underground."
          "Adventurers defeated the evil but it appears to be waking again, endangering #TOWN_NAME."
          "Huntokar grants mightier blessings to loyal followers."
          "Huntokar weeps for those whose bones lay in the depths without having proper funerary rites."
          "There were shrines to Huntokar below ground, but foul monsters have desecrated them. A terrible sin!")
  )
  (cond
    ((= ORCHARD_EXISTS true) 
      (append lines "It is said in ancient days the elves of old would grow magic fruit in their secret orchards.")
    )
  )

  (say (pick lines))

Ie., set a list of lines to pick from and conditionally add more before picking one to say. I had been loathe to make the dialogue system too much like a real programming language but this felt like a necessary addition because I was beginning to avoid making dialogue changes because they were too annoying.

A rule I follow for when I am going to do a bit addition, refactor, or rewrite is when a part of my codebase is annoying me to work on, I know it's probably time.

So this afternoon, I added in user-definable lists as shown above. It actually wasn't too much work! My script language still isn't Turing complete. There is no looping or recursion and god help me, there never will be.

Now after that little side trek back to working on NPC dialogue!

Delve 0.5.0

I've mentioned it on bluesky, but the next release of Delve will be on January 31st!

Dana's Delve is open source under the Creative Commons CC0 1.0 Universal license and its source code is available on GitHub.