Hi and thanks for your excellent reply.
I understand what you’re saying about the advantages of using an established programming language. I have had the same thoughts, but here is what i concluded:
- Tools like VSCode do make it a lot easier, but writers don’t use them.
- You can combine a DSL with an established language.
- You are at the portability mercy of any existing language (mobile version etc?)
Regarding point (2), my original idea was to implement a DSL according to, what i call, the 90% rule. this was:
Have the DSL able to easily implement 90%+ of the game and leave the 10% to a “proper” programming language.
The thoughts behind this was to endeavour to make the DSL as simple and non-technical as possible so that nearly all the game could be spun in it very quickly. And indeed, some (simpler) games would be possible entirely in the DSL.
Could swallowing a few extra characters of ‘verbose’ syntax be a reasonable price to pay even for regular IF authors? If by authoring in Typescript they are on a continuum of expressivity that can achieve almost anything they want if they put the learning in, perhaps it’s worth starting there and staying there.
I thought this too! But it turns out that expressivity doesn’t necessarily re
quire extra syntax. Example: natural language needs extra words but not extra syntax to say more.
Importantly, the core engine and Reader, has no concept of rooms or world state at all
Yes, i agree. I have the same thing, and this should also be true of your DSL. You don’t need it to internalise concepts like “rooms”. Even basic verbs like “get” and “inventory” should be written in the DSL itself and not part of the implementation. Neither should be the dictionary.
Confession: i currently have some hard-coded prepositions i need to eliminate (when i get around to it)
Turns out the concept of “in” needs to be part of the implementation. Most probably also “on”. This turned out necessary in order to compute the “interactive scope” ie the set of things the player can interact with.
Rather than centralising these capabilities into a single monolithic engine
Absolutely. But you shouldn’t need any special engine syntax for this. It’s essential to separate the UI from the engine. I have a thing called IFI
, which stands for “interactive fiction interface”, which is a messaging system between the “front-end” and the “back-end”. The engine (back-end), knows nothing about how the UI will present the information or get input.
same is true for “save game”. The actual save is always done by the UI (front-end). You don’t want your game engine having to mess with files for example. Otherwise it suddenly becomes horribly unportable.
YAGNI
I started writing some sample games in my DSL, but soon i began to factor bunches of this into reusable chunks. So this is now a “drop in” file to any game which provides all sorts of basic and standard stuff, “inventory” is one of them. And what you’re wearing etc.
the Reader and the core definition of Story wouldn’t have to be extended
I wound up implementing the “main loop” by the DSL. Which means it’s totally changeable by any given game. Not that many games need to change the main loop, but it’s there.
while retaining a simple engine. rather than defining a rich engine
Oh yes. I took a simple pattern as a building block and found i could use it in different ways to build the whole system.
I call this thing the “stave”:
NAME TOP
HEAD
* SELECTOR1
* SELECTOR2
TAIL
Sorry, this is probably meaningless. But that is the template (and syntax) for the whole DSL. It’s basically a branching builder and with different forms it can be a generator, an object or a choice.
Because;
- a generator is a bunch of alternatives chosen by the system
- a choice is a bunch of alternatives chosen by the player
- an object is a bunch of alternatives that semantically matches inputs.
All fascinating stuff!
Edit: I forgot to add. It turned out the DSL actually covered 99%+ of any game functionality. All the usual IF things wound up written by the DSL. An example of the 1% would be, say you wanted a black-jack implementation or chess or something. You’d do that in the companion “proper” programming language.