As the main point is the story, I (@HughHoyland) decided to provide a tool to the screenwriters. What is a good tool, from a programmer’s perspective? A programming language!
A couple basic ideas were borrowed from Ink, a really impressive language to write interactive fiction in. Namely:
- An idea of a DSL that is as close to normal story text as possible. CRPG, though, is very different from IF, so we cannot take it as is;
- The idea of a hub that consists of:
- an NPC’s opening line,
- and player’s choices (words or actions), which lead to other hubs of the conversation and/or change the state of the world.
This language was unimaginatively called “Talk” (working name).
The runtime (a simplest game prototype) is able to hot-reload Talk files and do a basic syntax check. We all know how important it is to shorten a develop-test loop.
Short intro to syntax:
- Hub starts with a $hub <name>,
- spoken lines start with “- “,
- player’s choices (which can be speech or actions) start with “*”;
- a redirect “>” after each choice leads to another hub and optionally an expression(s) to execute.
Example of a character conversation in Talk:
$hub default
- Hello!
$if (not questMouse.started):
* - Can I be of any assistance? > give_quest
$else:
* - About our quest... > quest
* - Where am I? > whereami
$if (2+2 == 4):
* - True thing! >
* - Bye > leave
$hub give_quest
- Yes! Yes, my field was infested by a huge rats. Can you get rid of them?
* - Yes > quest_accepted; $(questMouse.started := true)
* - No > quest_declined
$hub quest_accepted
- Great! I'll be waiting
* (talk more) > default
* (end) > leave
$hub quest_declined
- Well...
* (end) > leave
$hub quest
- What about it?
$if (questMouse.done):
$if (questMouse.success):
* - It was fun. >default
$else:
* - Sorry for being such a loser. Can I try once again? >give_quest
$else:
* - I'm still working on it > leave
* - (lie) Done! > $(questMouse.success := true); $(questMouse.done := true); $(questMouse.lied := true); success
* - I cannot do it, sorry. > $(questMouse.success := false); $(questMouse.done := true); leave
$hub success
- Thank you! Now take this Flyswatter +2!
* (talk more) > default
* (end) > leave
As you can see, our screenwriters have not written any artful dialogue yet. The language is, though, fully functional and can even changes the state of the world.
The language is implemented with the fantastic PEG grammar parser generator called Pest.
An image of the current prototype.
Technologies used:
- Rust! Because I wanted to learn it. Which might have been not the best idea, because I got stuck for weeks while learning how to work with, you know, borrow checker;
- bracket-lib, a roguelike framework, and Legion ECS;
- Pest.rs, an awesome (if a bit abandoned) PEG grammar parser.
Edit: P.S. Had I known about Yarn Spinner before, I would have tried to integrate it. For some reason, I examined and rejected Twine (too attached to HTML) and Ink (not exactly suitable for CRPGs), but not Yarn Spinner. Which is really good, even if it’s only implemented for C# and Javascript. I’m seriously considering ditching Talk and implementing YarnSpinner parser in Rust. It’s a subject for discussion with our team.