Devlog: Dialog Parser and Gamejam Wrap-Up

Mar 2, 2019, 10:30:14 PM

This Mortal Coil Leeblejam Project

This Mortal Coil Leeblejam Project

Hey everyone, the month-long gamejam is over! If you want to play the game, click through to this blog post and read about the game and how you can download it. In the post, I talk about a dialog parser I wrote in Ruby, content creation for conversations, wrap up for the gamejam, and the future of this project.

From Last Time

In my previous devlog, I talked about almost quitting this project because I just didn't know enough Ruby or how to deal with RPG Maker to make what I wanted. And most likely RPG Maker is probably not the way to go to make this kind of game.

The idea was to make a simple open world type of experience, but RPG Maker has some limitations which doesn't really allow it to work that way. I mean, it’s made for making old-school RPGs and story-driven games with sprite graphics like To the Moon or Rakuen. I wanted something a little more open world and randomly driven and not an entirely scripted experience. Once you get out of the extended cutscene between Kamiko and Susanoo in the beginning of the game, it opens up and allows you to do as you please, even though it's a limited action set -- ferry the souls, talk with them, or don't. :P

And I didn’t quit! I persevered and continued to build a game using RPG Maker like I said I would. There’s an end "product" you can download. Skip to the bottom for download instructions. The rest of this post is for those curious about my coding adventure in RPG Maker VX Ace.

Hacking RPG Maker!

Today I’ll talk about a “visual novel” parser I wrote in Ruby. It’s the other major component I wanted for this game so I could produce randomized dialogue.

Over the month of February as I work on this gamejam project I got better and better at using Ruby and figuring out ways to hack RPG Maker VX Ace.

Sure, you can use RPG Maker to script cutscenes using their custom GUI editor. The GUI has a scripting tool, but instead of writing code you click a button to bring up a menu of various command that you can use to script with. You can express common coding structures such as conditional and loops. There are a whole host of custom events to RPG Maker’s engine that you can include in the script such as displaying text, images, giving your party items, and so much more.

It’s kind of daunting.

There are three pages of commands! Here's a sample:

RPG Maker Command List

RPG Maker Command List

Yeah, that's a nasty interface...

I’m a programmer. The idea of using a point-and-click interface to script code doesn’t appeal to me. It feels slower and I feel hamstrung by it.

In my game, I wanted to have conversations between the main character and different souls that you meet. You could script this with the GUI editor, but these conversations are text heavy experiences between two characters. It would be really time-consuming to produce that content using the custom GUI editor.

So, I wrote my own dialog parser.

I didn't know if it was possible or not, because everything is burned into RPG Maker’s custom event scripter.

But, all of those scriptable events in the GUI are available inside of the Ruby scripting engine.

If you’re curious to hack the code yourself start with Game_Interpreter. That script is the main loop that handles all of the commands that you express inside of their GUI editor. That’s where I began.

To see if I can even hack the code and turn it into my own Ruby script, I put print statements into the game interpreter and viewed the output in the debug console window.

The "clearly named" Command_101 is the dialog text messaging function. This will write text into a dialog box. (This code is copy/paste from RPG Maker VX Ace.)

\# \* Show Text  
   def command\_101  
     $game\_message.face\_name = @params\[0\]  
     $game\_message.face\_index = @params\[1\]  
     $game\_message.background = @params\[2\]  
     $game\_message.position = @params\[3\]  
     while next\_event\_code == 401       # Text data  
       @index += 1  
     case next\_event\_code  
     when 102  # Show Choices  
       @index += 1  
     when 103  # Input Number  
       @index += 1  
     when 104  # Select Item  
       @index += 1  

The important line in the script that displays the message is:


Now, if you were to write a simple Ruby script that called $game_message.add(), it would work fine.

If you ran it, you would see a text box come up with your text typed out in it.

RPG Maker Text Window

RPG Maker Text Window

But, I'm also using a plug-in called Yanfly's Ace Message System, which gives you a bunch of short codes for referring to things in the game engine such as player names, item names, and game variables. It also shows the name box over the dialog. I thought it would be really cool to have access to those things. Calling $game_messages.add() in script and attempting to the use these short codes doesn't work.

But, it does work if you use the game interpreter engine, because it hooks into all of RPG Maker’s in-game UI. Yanfly’s script extends the functionality of command_101 and the game window UI to do that. Instead of reinventing the wheel, I want to patch into that code too. So that's why I had to figure out a way to hook into it and mimic its functionality inside of my own script reader.

TL;DR: after an hour or two of trial-and-error I managed to figure out how to do it. I also found the function that allowed me to show bitmap images and with that combination I could display something kind of like a visual novel script in game.


The most difficult part of the dialog parser was to answer the question: do I need to use Ruby's fiber system?

Fibers in Ruby are its lightweight threading / coroutine system. I'm not unfamiliar with coroutines because I use them in Unity all the time. Yet, I haven't really done a lot of multithreaded programming. As an aside, coroutines in Unity aren’t really multithreaded anyway, they get called on the same thread before or after Update() -- I forget which. I’ve done a little using Win32’s multithreading library in the past for fun, but nothing extensive. I’m not an expert.

I was a bit worried that I might have to figure out Fibers, but like most things I come across that appear to be multithreaded, I didn’t have to dig into it. I was able to work around it.

Dialog Parser Examples

I ended up creating a class that would hold all of the functionality and use a very simple core loop to parse a script file written using Ruby’s array and object format to display a conversation.

Here’s an example script and a break down of how it works.

module SoulEntrance   
   SCRIPT = \[  
       actor\_id: 'id',   
       pic: "",  
       lines: \[  
         "Where am I?",  
       actor\_id: 1,   
       pic: "kamiko\_bust\_idle",  
       lines: \[  
         "Hey, kiddo. Take it easy you had a long trip.",  
         "But you made it back in one piece."  
   #continues on...

I wrote the dialog scripts as constant array of objects straight in Ruby. Yes, it would be better if they were text files, but I didn't want to deal with trying to load and parse text files so close to the end of the jam.

You can just add new Ruby files and since I wanted these in Ruby ultimately, this is what I choose. Each Ruby object contains a dialog line, picture and gets displayed by the game's UI.

I can run my dialog script in RPG Maker's GUI interface using the Ruby "script" command. Yeah... I know a lot of different types of scripts -- dialog scripts, Ruby scripts, and custom GUI scripts. In this case it would be like this:

RPG Maker Script Snippet

RPG Maker Script Snippet

$fg_dialogrunner is my global dialog script runner object. In this case I also take a variable for the soul's actor_id so I can show the correct name.

In my dialogue script I made it so I can parse the "lines" differently. In the basic case, it'll take the array of dialog and parse it one line at a time, so this way I can have a character speak multiple lines before we go to the next character.

Also, I can change it so the array of lines is interpreted as a random set of strings. The character then says one thing from a group of potential lines. It was fun to write and improv different dialogue options.

I extended that randomization concept further by allowing the script to jump to different blocks of text to have random conversations. Here's some advanced examples in my dialogue script:

  actor_id: 'id', 
  pic: "",
  lines: [
    "Do you think next time, I'll have a better dream?"
  choices: [{option: "Sure, kid.", jump: "sure"}, {option: "Who knows?", jump: "who_knows"}]
  label: "sure",
  actor_id: 1, 
  pic: "kamiko_bust_idle",
  lines: [
    "It'll be better next time.",
    "I'll take you across when you come back."
  jump: "continue"

In the code above, you can see I have a concept of a "jump" node. The jump node allows the script to continue at a different point. The parser will look for that position by doing a string compare on the label attribute (if it exists) in the array and continues execution from there.

There's also the concept of choices. I can define a nested array of objects that contain choice text and branches. This allows me to give simple choices the user can pick in the conversation.

There's probably a lot of other ways I could extend this script. Some drawbacks right now is that you can't really do cutscenes. Characters can't move around. They can stand and talk to each other, which is what I cared about. There's a lot of potential left though.

Once I finish the scripting system, I used it over the last three days of the gamejam to create a lot of the conversations that the player would have with these various souls. They're very rough and unpolished conversations. But, good enough for the jam.

Last Minute Bugs

I mostly work on this gamejam project over weekends in February. My focus was primarily Ruby scripting. But, for the run-up to the end of the month, I decided to take the last three days from the 26th to the 28th and “crunch” to get some content in. I guess you can see where my interests and priorities lie (i.e. coding).

I wouldn't even call it a game at this stage. It's kind of a tech demo / prototype. But, I think that's really all you can expect from a gamejam that I'm doing in my spare time.

Once I finished all the conversations and retrofit my events in game to use them, there were a couple of last-minute bugs that to resolve.

One of the major bugs was dealing with the soul spawner and save files. Honestly, this is probably an edge case. The contents of the soul spawner aren’t serialized properly and I’ve yet to figure it out.

In the normal use case: I'm sure if you were to sit down and play this game you might enjoy it in one sitting. It's maybe a 10 minute experience. There's no purpose to saving the game, but as I was testing it, it bothered me.

I tried various ways to solve it, but no luck. I’d need a few hours to debug and since it was 11 PM on the 28th, I decided to stop. I found a way to get it working mostly right.

And then, I let it go.

A problem for another time.

I'm sure even if I solve this bug, there will be another thousand bugs hiding in this code.

Around 11:45 p.m., I wrapped up the project and had RPG Maker compress it into an executable file and sent it off to wrap up the gamejam. Of course, my internet went down before I could upload the project anywhere -- there's always something last minute, isn't there? But, a personal hotspot on my smartphone got me around that obstacle.

Mission Accomplished

I’m proud of the work that I did.

I understand Ruby better, and I can hack RPG Maker’s engine to make a game. I spend most of February trying to bend RPG Maker to my will, which is kind of cool, but probably not worth it in the long run.

If I were to seriously make this game, I might turn to Unity. I know it better and it would give me more control over the code and fidelity of the simulation that I'm going for. But, the downside is that I would have to write everything from scratch and that would be a year-long project in the least.

Where to Download

You're probably wondering where can I play this game?

Before you download, a disclaimer!

You run the game at your own risk. I have done nothing malicious, but it is an unfinished product filled with bugs, but if you've read the above you know about the bugs and weird issues. With that said...

How to Play  For Windows

  1. Download the game here!
  2. Extract the executable into a new directory on your hard drive. I swear it’s not a virus even if your virus scanner says it’s one.
  3. Download RPG Maker’s runtime support package. When I compressed my game it only added the assets and scripts that were relevant to my game. The rest of the game exists in this run time package.
  4. Once you have the runtime package installed and the game you can play it by running game.exe

NOTE: If you have a overly aggressive antivirus software it may consider game.exe a virus. I have no control over what the name of the executable is, because RPG Maker's executable is specifically called game.exe. Blame it on them, but I assure you I did not include a virus.

If you’re on a Mac you’ll have to boot into a windows partition to run the game, as it’s Windows only. Or use some kind of Windows virtual machine to run it. It is another unfortunate limitation of using RPG Maker VX Ace.

What’s the Future For This Project?

Here’s my next project: To continue writing the novella series for This Mortal Coil. That's what I set out to do last summer and continued at the start of 2019. There's one novella out for Amazon Kindle called The Shinigami. You can purchase it on Amazon.

The novella series follows Kamiko, and this game is actually related to the novella series. Kamiko is portrayed as a death god in both. The Shinigami is an adventure story with her and is an introduction of sorts to the world of This Mortal Coil. The game I made is about Kamiko's moment-to-moment "day job" as a Shinigami.

This gamejam opportunity came up and I wanted to do it.  It has slowed me down for a month in terms of the novella project, but I think it was worth it.

And hey, I have a seed of a game planted. So who knows how it may blossom this year.

Once I can write another This Mortal Coil novella or two, I would like to come back to this project and continue exploring it.

I would continue with RPG Maker VX Ace as well, even though it’s not ideal. Nothing’s really ever ideal, so you gotta work with what it is and deal with the creative limitations, ya know?

Some of the next steps:

  1. Fix the linger bugs that annoyed me
  2. I love to do a new sprite and expression set for Kamiko and some of the other major characters that show up in the game.
  3. Redo the background Sprite tileset to fit more of the aesthetic and scale that I want.
  4. Add music and sound effects
  5. Script more random events into the world that would make it feel alive.

Once you're in the main loop of the game, you're only really able to go back and forth between the shores of the Mortal and Eternal Realms. Everything you encounter happens in that space. It was never meant to go beyond the shore, and any extended game would not either. It’s meant to be a limited stage with the question: how interesting can you make it? So I would like to spend more time to fill it out with game content that way.

If I do more development, you'll definitely hear about here on the blog. But, expect it to be another slow-moving project like The Shrine, which is still undone and, well, there.

I hope you enjoy this devlog series that I've written on making this RPG Maker game. There'll be more to come in the future.

If you have any questions about Ruby scripting, RPG Maker, or why I even made this game project feel free to ask in the comments below and I'll answer.

Thanks for reading, till next time...