Menu

Another Star 2 Dev Log #14: A Scripting Language

Almost everything in the original Another Star was hard coded, other than the layout of the map itself. Every item, every enemy, and every scene was entered as lines of C# code. Even the layout of some of the tile graphics I manually typed in. For many things, this actually wasn’t too much of a bother. Typing up all the enemies and their stats could be a little annoying because the C-derived family of languages tends to be so verbose, but it’s not too different than creating a parsable data file.

Scene scripting, on the other hand, was an absolute nightmare of a chore. Another Star was a very simple game. Other than the player, characters couldn’t move and were limited to “teleporting” around to room if the story needed them to be somewhere, and they always faced down with no alternate sprites for the other cardinal directions. Most of the story was given using raw text and nothing else. And yet, despite how little really needed to be done, it was still such a pain every time I had to write a new scene to advance the plot.

Code for an early scene in Another Star.

Writing a story in a programming language just feels unnatural to me. Remembering to slap a semicolon on the end of every line, no matter how short, or having to reach for the parenthesis and curly bracket keys all the time. It may seem silly, but it really does disrupt my thought flow. I suppose you could say it puts me in a “programming” state of mind for problem solving, instead of a creative one for coming up with interesting scenarios and enjoyable dialog.

Worst of all, if you look over the code you’ll probably notice another, even bigger issue: none of the actual dialog is in there! The localized dialog is another of the small handful of things that’s not compiled into the code. It’s all off in a plain text file so that it could be possible to translate the game into other languages. So whenever I wrote a scene in Another Star, I’d have to constantly go back and forth between the code file and the dialog text file. Countless numbers of times I’d mismatch a line, or forget to remove a cut line no longer there, or just leave an important line out by accident altogether. Some of these made it all the way into the original release without being caught.

Speaking of which, the all-caps dialog didn’t help with catching typos.

For Another Star 2, I wanted to avoid having to go through all that again.

Now, there’s a lot of scripting languages out there that I could have just downloaded a library for and dropped into my project, but the vast majority of them have the C-style syntax I was trying to get away from, or just throw weird characters all over the place, like LISP’s unsettling infatuation with parentheses. I wanted something that felt a little more like natural English and didn’t have me reaching all over the keyboard just to do simple things. And I honestly didn’t need the raw power of most of these languages anyway. 95% of what I need to do is just pop a dialog box up on the screen. A simple language without a lot of bells and whistles would be just fine.

A test draft of an early scene in Another Star 2.

After a lot of thought and a couple weeks of work I managed to put together a simple command-driven scripting language with support for functions and if-then-else blocks for branching. It could still use some tweaking for sure, but already it feels a lot more like writing a novel than writing a game engine. Writing a test scene was a lot more fun than frustrating, even as I was working out some of the kinks in the language’s syntax.

And see how all the actual dialog can be easily included in the script itself. The script is compiled to bytecode with a custom compiler so that the game doesn’t have to parse it on-the-fly, and this compiler outputs two files: the script bytecode goes to one file, and all the localized text goes to a separate text file to support possible translations in the future. You’ll notice that each line of dialog is indexed, so that moving things around in the code won’t completely mess up existing translations just to do minor fixes. I’m not wild about having to number all the lines out like that, but it beats having to manually track them in another file.

I’ve been careful to document how the language works and what all the commands do so that everything is ironed out and I won’t forget little details like what each command’s compiled byte code means. But maybe I got a little carried away on that front…

I’ve paid for released products that aren’t this well documented…

The first successful test for running the script in the game was to lock the player’s controls for a couple seconds and then play a song, but that’s kind of hard to show in a picture, so instead I used it to place this little lookout tower on the overworld.

You can walk over it to enter, but it doesn’t take you to the right place yet.

That probably seems like a weird thing to use scripting for, instead of just slapping it there in the room editor, but I promise it will make more sense later.