That title needs some more acronyms and jargon, am I right?
The computer game my friends and I are making uses a visual novel (NVL) engine for our narrative. In other words, we present the story in the style of a visual novel. We primarily use the Lua programming language for our game but we want to make it possible for non-programmers to easily work with story data; it should not require being a computer programmer to write dialog for a game. That’s why I am working on a domain-specific language (DSL) for our engine.
So I thought it would be interesting to take a thorough look at creating such a DSL in Lua, starting with most important question first: “Why?”
Thanks Lack of Self-Restraint!
First of all, there is something you have to understand about me and my partners, Jeff and Jesse: We are story-tellers. It is why Jesse and I run our own Dungeons and Dragons campaigns while also playing together in a shared campaign. It is why every single video game Jeff and I have ever talked about making has spiraled out of control into a massive role-playing game. You only need to look at the game we are currently making to see that this is true. Initially we set out with the idea of a multiplayer shmup, and now the three of us have turned that into a thematically broad and (hopefully) compelling single-player narrative. We can’t seem to help ourselves. We will slap three novels of backstory onto Tetris if you let us.
So when our project inevitably spawned an RPG-like story we agreed that we would need another technical component to present that story, because the shmup genre has no inherent mechanism for telling a lengthy tale. Visual novels have worked with other types of gameplay in the past: RPGs, tactical games, and simulations being the most common. So why not a shmup too?
Thus spawned LNVL.
Why a DSL Too?
Writing a visual novel engine from scratch is already a daunting task, despite the simplicity of visual novels on the surface. Why also invest the time and effort creating a domain-specific language on top of that? What are the pros and cons?
The most important benefit of a well-designed DSL is that it allows more people to contribute to that part of our game. We try to convey this in the Howto Guide for LNVL. The dialog scripts that we write, shown as examples in that document, are actually Lua code. The DSL tries to hide that fact though, so that knowledge of Lua or programming in general is not a prerequisite for a non-programming task: writing a game story.
The cost of that benefit is the obvious major ‘con’ of creating a DSL: the time required. We could choose a less friendly approach that demands programming knowledge but allows us to get to work more quickly. This is fine for some games, especially if we were building something smaller in scale that did not deserve its own ‘engine’ component in the first place. Furthermore, deciding to create a DSL is not a black-and-white choice.
After deciding to create a DSL we then must ask ourselves: “How closely will this resemble actual code?” The answer to this question has a profound impact on the technical implementation, as we will see.
At one extreme we can completely hide any scent of a programming language. Instead of a DSL we could design a markup language like how we use HTML for websites. People writing dialog scripts in our markup language would have no idea that we are using Lua behind the scenes, nor would they have access to the language. This approach gives us the freedom to design any syntax we want since we are not incorporating the underlying language in any accessible way.
Or we can choose to plant the design of the DSL somewhere in between that and full-out Lua. By using Lua as the foundation of the DSL we give ourselves the option of being able to resort to Lua in our scripts for situations where our DSL does not meet our needs. Ideally we want to keep these cases to a minimum, but in our experience they are unavoidable.
I realize that I avoided talking about any specific details with regard to Lua or our own DSL. Today I simply wanted to set the stage by introducing the high-level questions we ask ourselves when starting this type of project. For my next post in this series I will actually dig into how we can create DSLs in Lua by taking advantage of some syntax tricks and data-structure manipulation.