Really neat. I actually wrote something similar but far more primitive in Scheme (worse CL, primitive parser, minimal interactivity, and so on). I wouldn't reccomend either system for serious IF, though. Tads, Inform and the rest are far more capable.
I think this implementation isn't tackling the root of the problem here. Implementing this as a state machine that can load arbitrary node, status, and links would better model the problem.
I'm curious what you've identified as the root of the problem for making these sorts of parser-based games. It sounds to me that you'd rather it be a choose-your-own-adventure game, which your suggestion would make sense for, but parser-based games tend to model a virtual world of objects which your character interacts with. OO-style ontology tends to work somewhat better than state machines here (though I think rule-based dispatch has proved more successful in Inform 7, or in a Python-based text adventure engine I once made. Some complications are in expressing indirect objects for verbs and in rules which only apply to certain instances of objects in certain situations -- there is always a game which will complicate your simple world model).
Also, what is the harm in making it so that the data for the game is Clojure source rather than some other format? "Code is data" allows for data being code. It saves having to make a state machine interpreter which you have to extend with exceptions for particular games which will eventually become a poorly implemented lisp in Clojure in the JVM.
>I'm curious what you've identified as the root of the problem for making these sorts of parser-based games
It's not a parser based game. It's a state based game. When you have to track complex interactions with massive sets of states, nodes, and interconnections you are writing a state machine.
To truely understand that this is the case you have to see an example. As such I recommend looking at the Fallout 1/2/3/New Vegas quest flow charts that have been generated. Here are a few:
These should all demonstrate what I mean. All that would need to happen is for the state machine to interface with a player "inventory" and check the states of that before actions are completed. It turns most of the game logic into walking a tree and checking conditions.
> but parser-based games tend to model a virtual world of objects which your character interacts with.
That's not what I'm talking about. I'm talking about modeling the game as a set of actions that can be taken but are blocked by sets of preconditions.
> Some complications are in expressing indirect objects for verbs and in rules which only apply to certain instances of objects in certain situations -- there is always a game which will complicate your simple world model
I'm not saying to create the human interface using a state machine. I'm saying to model the story as a state machine.
> Also, what is the harm in making it so that the data for the game is Clojure source rather than some other format? "Code is data" allows for data being code. It saves having to make a state machine interpreter which you have to extend with exceptions for particular games which will eventually become a poorly implemented lisp in Clojure in the JVM.
There are many reasons to do this. For one, it allows people who aren't programmers to create stories for your engine. To take a look at the interesting side effects of this I'd recommend watching this video: https://www.youtube.com/watch?v=FnFKEWCzVCo
It's again from one of the people involved with the fallout series but he goes into how the scripting side of things enabled story writers to create an entirely different experience. When you give non-programmers a safety-scissors equivalent of a programming environment they can create cool things without bothering you.
Another great side effect is that you've abstracted your problem. You could pull your state machine code out of your game, turn it into a module and interface with it there. Any other code that you need to use a state machine will be able to now interface with it.
This is, I'd say, the most fundamental idea possible in computer science. The idea of abstracting concepts to make the project being created simpler.
Finally, there is the problem of reusability. This game is pretty much locked to it's engine. It can't be reimplemented or updated by people who don't have knowledge of the code base.
On a side note this cannot be configured to run a story safely if it is clojure code that is executed.
Basically, you're removing reusability of this engine, you're not creating a solution to the root problem, and you're making it so the user cannot play other sto...
By "parser-based" I was referring to terminology from the interactive fiction community. A parser-based game is one whose primary mode of interaction is a parser reading user commands.
I agree that there is an underlying state machine, but that's true of any program. I was saying that modeling the state transitions for these sorts of games tends to work out better for authors when using an OO-style model, since the game is simulating a player object interacting with other game objects. Making a system to help organize running certain logic on certain conditions is exactly one of the goals of blah-orientation, where "blah" is object, functional, state machine, or whatever.
I've seen state transition diagrams like the ones you mention for the design of interactive fiction, but only for high-level design. The interactions between objects in these games tends to be too complicated to completely describe that way. For instance, does the player character see anything in a room if they put their only light source inside an opaque closable container? What if the player is inside that container? Puzzles in IF quite often use emergent behaviors of simulated environments, and there are large standard libraries for them in, for instance, Inform 7 or TADS.
Ok, so what I'm gathering is that you have identified the root problem of these sorts of games as being organizing the story as a state machine, making it so that non-engine authors are able to make trusted content, and making it so the engine can be reused.
But I think an adventure game engine is more along the lines of the underlying game engine for Fallout 4 than the code inside Fallout 4 which helps drive the story. For instance, where is the crafting system implemented? Is it really thought of as a giant state transition diagram? I find that difficult to believe.
Again, I believe you are thinking choose-your-own-adventure rather than this genre of parser-based games. CYOA games tend to just disallow disallowed actions, but parser-based games with a modeled world tend to attempt reasonable responses to any (reasonable) action. Whether you agree games should support these sorts of interactions is a different question from whether these games should be implemented as state transition diagrams.
And sure, with this Clojure-based engine arbitrary code can be executed. There are a couple differences between this and Fallout 4. The first is that the cost of making interactive fiction is much less than a game like that, so one or two people can easily produce one, reducing the need to abstract game logic to a separate language. The second is that the engine can be compiled into the game for distribution, just like most other games.
Also, it's conceivable that the game could run in a locked-down virtual machine. The old Infocom games ran in a bytecode interpreter that their in-house Lisp-like language targeted. In the modern day, people still distribute interactive fiction in the same (but somewhat modernized) format.
> This is, I'd say, the most fundamental idea possible in computer science. The idea of abstracting concepts to make the project being created simpler.
I agree that abstraction is powerful and can make things simpler. But it also requires the correct abstraction, and I'm just not convinced that modeling interactive fiction games using state machine diagrams is actually simpler. I found the discussion of ontology problems in the Inform 7 white paper interesting: http://inform7.com/learn/documents/WhitePaper.pdf
There was a small table there. The small table contained:
A bottle. The bottle contained a amount of water
@Bedroom [0] > get all
I didn't see that.
@Bedroom [1] > get bottle
I couldn't take that.
@Bedroom [2] > take bottle
I couldn't take that.
@Bedroom [3] > drink water
I didn't know how to do that.
@Bedroom [4] > open bottle
I couldn't open that.
My experience too. Couldn't help but be disappointed in the parsing engine of this game. But I guess I am a little spoilt, having grown up on most of the Infocom adventure games...
Try Inform games. They're built atop the Z-machine (and now its successor, Glulx), and have a very good parser. This is why when I make an adventure game, I'll give you a verb list unless there's a explicit reason not to. Even the best parser can't compare to the ability to express your intent in the knowledge that it will be understood.
I think in this particular case, the game example script is more to blame than the parser. I don't even remember putting that bottle there, but I should've marked it to be take-able and drink-able.
I made it so it's fairly simple to extend the supported verbs (you can even add your own verbs as a lib user, without modifying the lib code). It's just that it hadn't been used much before today, so a lot of somewhat obvious verbs are probably missing.
(full disclosure: I had little experience with infocom games myself, I'm more used to graphic adventures, but this was a far more interesting programming project to learn Clojure).
One of the 'shortcuts' in the Infocom Z-parser based games when I entered a room that was rich in 'stuff' was to issue a 'take all' command. That would immediately give me an idea of what was an object that could be manipulated vs what wasn't. e.g.
> take all
bottle: taken
table: that's nailed to the floor
bed: that is too heavy to take
wallet: taken
rug: you can't take that!
This (a) automatically lets me pick up anything that I can (and drop the ones that I don't immediately need), but (b) it also tells me that there is no point in trying anything with the table & rug, but the BED might still be an actionable item because of the response. Perhaps I could 'move' instead of 'take' the bed?
Good, I didn't know about the "take all" feature, taking note.
In advenjure you can get a similar effect with the autocomplete. If you enter "take " and hit tab you will get suggestions for all the items available in the room.
Either case still requires the game scripter to try to guess what the players will attempt and write specific responses for that, otherwise they'll get the frustrating generic responses.
Ah, the tab thing is useful. But is seems to list ALL objects in the room, not just ones you can interact with. Seeing something on the tabbed list make me assume that you CAN in fact 'take' it, but nearly everything on the list CANNOT in fact be taken. A long and tedious process if you have to do them one by one, and not via global 'take all'.
Apologies if I sound harshly critical - I am not, and I applaud your efforts here. I am simply framing my comments from many years of playing Infocom games over 30 years ago. I still have Frotz on my iPad these days so I can continue to enjoy bootleg copies of Infocom and other games. Would continue to use Advenjure too if the parsing quirks are worked out so that the game flowed naturally, rather than being a constant fight with the interpreter to try and achieve what I want to do.
> Good, I didn't know about the "take all" feature, taking note.
If you're serious about making a viable interactive fiction engine, you should get really familiar with the Infocom games, the Z-machine engine and its various ports, and the Inform compiler that a latter-day fan made for the Z-machine (and the fan-made games that use it). That's the standard by which your work will be judged.
If you're just fooling around, then do whatever you like. :) Some of your ideas are pretty neat, like tab completion.
Yes, but not anytime near it came out (it was probably around 2000 C.E. for me).
Earlier this year I was playing around with recompilation (reading the Emscripten whitepaper) of z-code. The Infocom games used a virtual machine to get their games onto lots of contemporary computers, and also to reasonably implement a virtual memory system to fit the games into the small memory of those computers.
Anyway, it isn't too hard to make a z-machine interpreter (at least version 5 of z-code), so I made one which recompiles the code into javascript: http://tmp.esoteri.casa/zmach/zmach.html
The way z-code works makes it so you can't tell what is code and what is data ahead of time, so it decompiles as you play. "Dump routines" gives you the the code so far (as javascript). Part of the fun is making code which can pause execution to wait for player input. (Turns out the technique is already in some paper from some scheme workshop.)
A quick explanation of what this is, because it took me a bit to figure it out: it appears to be an interactive fiction engine written in Clojure. The linked example game is running through ClojureScript in the browser, but the engine also works in the terminal.
Here's a quick link to the main code file defining the rooms and actions for the example game: https://github.com/facundoolano/advenjure-example/blob/maste.... I doubt I'm the only one that likes looking at this type of example first when looking at an interactive fiction engine, and it may help some people confused by the game.
The history of interactive fiction and Lisp is surprisingly intertwined. To the best of my knowledge, all of the original Infocom games were written in ZIL [0], an idiosyncratic Lisp variant that was meant to be a more portable version of the programming language used to write the original mainframe Zork, MDL—which was apparently designed by some of the same people who worked on Scheme and Common Lisp [1].
There appears to be an active but still incomplete open source compiler for ZIL written in C# [2], and a few Common Lisp experiments, but not many mature projects combining interactive fiction and Lisp.
I hope projects like this one catch on more. I've had trouble grasping other interactive fiction engines, which I often feel are trying to please programmers and writers but hitting an awkward space in between. Lisp's "code is data" idea seems like it could be a more graceful way of hitting that balance.
I think that's an astute observation that the history of IF languages seems to be trying to find a balance between easy for programmers on one side and easy for writes on the other, and that Lisp is certainly as intertwined in the early history of IF as it is because it naturally hits an interesting place in that balance given the S-Expression "code is data"/"data is code" simplicity.
I still find Inform 7 a deeply fascinating example simply for trying a "Prose is code" approach that tries to favor writers first, somewhat at the expense of sometimes making programmers frustrated.
Graham Nelson's "The Inform Designer's Manual, 4th Edition" [DM4] is an essential read for those wishing to implement an interactive fiction authoring system. Especially the chapters on Inform's world model and its flexibility.
24 comments
[ 4.7 ms ] story [ 45.0 ms ] threadGood work though on keeping this very simple.
Also, what is the harm in making it so that the data for the game is Clojure source rather than some other format? "Code is data" allows for data being code. It saves having to make a state machine interpreter which you have to extend with exceptions for particular games which will eventually become a poorly implemented lisp in Clojure in the JVM.
It's not a parser based game. It's a state based game. When you have to track complex interactions with massive sets of states, nodes, and interconnections you are writing a state machine.
To truely understand that this is the case you have to see an example. As such I recommend looking at the Fallout 1/2/3/New Vegas quest flow charts that have been generated. Here are a few:
Example of describing story with a state machine: http://i.imgur.com/mAENC.jpg
Example of describing spacial directions with state machine: http://i.imgur.com/qVnEH.png
A Fallout NV mod as another example of story-as-state machine: http://www.thumbsticks.com/wp-content/uploads/2015/02/Fallou...
These should all demonstrate what I mean. All that would need to happen is for the state machine to interface with a player "inventory" and check the states of that before actions are completed. It turns most of the game logic into walking a tree and checking conditions.
> but parser-based games tend to model a virtual world of objects which your character interacts with.
That's not what I'm talking about. I'm talking about modeling the game as a set of actions that can be taken but are blocked by sets of preconditions.
> Some complications are in expressing indirect objects for verbs and in rules which only apply to certain instances of objects in certain situations -- there is always a game which will complicate your simple world model
I'm not saying to create the human interface using a state machine. I'm saying to model the story as a state machine.
> Also, what is the harm in making it so that the data for the game is Clojure source rather than some other format? "Code is data" allows for data being code. It saves having to make a state machine interpreter which you have to extend with exceptions for particular games which will eventually become a poorly implemented lisp in Clojure in the JVM.
There are many reasons to do this. For one, it allows people who aren't programmers to create stories for your engine. To take a look at the interesting side effects of this I'd recommend watching this video: https://www.youtube.com/watch?v=FnFKEWCzVCo
It's again from one of the people involved with the fallout series but he goes into how the scripting side of things enabled story writers to create an entirely different experience. When you give non-programmers a safety-scissors equivalent of a programming environment they can create cool things without bothering you.
Another great side effect is that you've abstracted your problem. You could pull your state machine code out of your game, turn it into a module and interface with it there. Any other code that you need to use a state machine will be able to now interface with it.
This is, I'd say, the most fundamental idea possible in computer science. The idea of abstracting concepts to make the project being created simpler.
Finally, there is the problem of reusability. This game is pretty much locked to it's engine. It can't be reimplemented or updated by people who don't have knowledge of the code base.
On a side note this cannot be configured to run a story safely if it is clojure code that is executed.
Basically, you're removing reusability of this engine, you're not creating a solution to the root problem, and you're making it so the user cannot play other sto...
I agree that there is an underlying state machine, but that's true of any program. I was saying that modeling the state transitions for these sorts of games tends to work out better for authors when using an OO-style model, since the game is simulating a player object interacting with other game objects. Making a system to help organize running certain logic on certain conditions is exactly one of the goals of blah-orientation, where "blah" is object, functional, state machine, or whatever.
I've seen state transition diagrams like the ones you mention for the design of interactive fiction, but only for high-level design. The interactions between objects in these games tends to be too complicated to completely describe that way. For instance, does the player character see anything in a room if they put their only light source inside an opaque closable container? What if the player is inside that container? Puzzles in IF quite often use emergent behaviors of simulated environments, and there are large standard libraries for them in, for instance, Inform 7 or TADS.
Ok, so what I'm gathering is that you have identified the root problem of these sorts of games as being organizing the story as a state machine, making it so that non-engine authors are able to make trusted content, and making it so the engine can be reused.
But I think an adventure game engine is more along the lines of the underlying game engine for Fallout 4 than the code inside Fallout 4 which helps drive the story. For instance, where is the crafting system implemented? Is it really thought of as a giant state transition diagram? I find that difficult to believe.
Again, I believe you are thinking choose-your-own-adventure rather than this genre of parser-based games. CYOA games tend to just disallow disallowed actions, but parser-based games with a modeled world tend to attempt reasonable responses to any (reasonable) action. Whether you agree games should support these sorts of interactions is a different question from whether these games should be implemented as state transition diagrams.
And sure, with this Clojure-based engine arbitrary code can be executed. There are a couple differences between this and Fallout 4. The first is that the cost of making interactive fiction is much less than a game like that, so one or two people can easily produce one, reducing the need to abstract game logic to a separate language. The second is that the engine can be compiled into the game for distribution, just like most other games.
Also, it's conceivable that the game could run in a locked-down virtual machine. The old Infocom games ran in a bytecode interpreter that their in-house Lisp-like language targeted. In the modern day, people still distribute interactive fiction in the same (but somewhat modernized) format.
> This is, I'd say, the most fundamental idea possible in computer science. The idea of abstracting concepts to make the project being created simpler.
I agree that abstraction is powerful and can make things simpler. But it also requires the correct abstraction, and I'm just not convinced that modeling interactive fiction games using state machine diagrams is actually simpler. I found the discussion of ontology problems in the Inform 7 white paper interesting: http://inform7.com/learn/documents/WhitePaper.pdf
I made it so it's fairly simple to extend the supported verbs (you can even add your own verbs as a lib user, without modifying the lib code). It's just that it hadn't been used much before today, so a lot of somewhat obvious verbs are probably missing.
(full disclosure: I had little experience with infocom games myself, I'm more used to graphic adventures, but this was a far more interesting programming project to learn Clojure).
> take all
bottle: taken
table: that's nailed to the floor
bed: that is too heavy to take
wallet: taken
rug: you can't take that!
This (a) automatically lets me pick up anything that I can (and drop the ones that I don't immediately need), but (b) it also tells me that there is no point in trying anything with the table & rug, but the BED might still be an actionable item because of the response. Perhaps I could 'move' instead of 'take' the bed?
In advenjure you can get a similar effect with the autocomplete. If you enter "take " and hit tab you will get suggestions for all the items available in the room.
Either case still requires the game scripter to try to guess what the players will attempt and write specific responses for that, otherwise they'll get the frustrating generic responses.
Apologies if I sound harshly critical - I am not, and I applaud your efforts here. I am simply framing my comments from many years of playing Infocom games over 30 years ago. I still have Frotz on my iPad these days so I can continue to enjoy bootleg copies of Infocom and other games. Would continue to use Advenjure too if the parsing quirks are worked out so that the game flowed naturally, rather than being a constant fight with the interpreter to try and achieve what I want to do.
If you're serious about making a viable interactive fiction engine, you should get really familiar with the Infocom games, the Z-machine engine and its various ports, and the Inform compiler that a latter-day fan made for the Z-machine (and the fan-made games that use it). That's the standard by which your work will be judged.
If you're just fooling around, then do whatever you like. :) Some of your ideas are pretty neat, like tab completion.
[0] http://grunk.org/lostpig/
http://mentalfloss.com/article/29885/eaten-grue-brief-histor...
Earlier this year I was playing around with recompilation (reading the Emscripten whitepaper) of z-code. The Infocom games used a virtual machine to get their games onto lots of contemporary computers, and also to reasonably implement a virtual memory system to fit the games into the small memory of those computers.
Anyway, it isn't too hard to make a z-machine interpreter (at least version 5 of z-code), so I made one which recompiles the code into javascript: http://tmp.esoteri.casa/zmach/zmach.html
The way z-code works makes it so you can't tell what is code and what is data ahead of time, so it decompiles as you play. "Dump routines" gives you the the code so far (as javascript). Part of the fun is making code which can pause execution to wait for player input. (Turns out the technique is already in some paper from some scheme workshop.)
https://github.com/kmill/zmach is the project.
Here's a quick link to the main code file defining the rooms and actions for the example game: https://github.com/facundoolano/advenjure-example/blob/maste.... I doubt I'm the only one that likes looking at this type of example first when looking at an interactive fiction engine, and it may help some people confused by the game.
The history of interactive fiction and Lisp is surprisingly intertwined. To the best of my knowledge, all of the original Infocom games were written in ZIL [0], an idiosyncratic Lisp variant that was meant to be a more portable version of the programming language used to write the original mainframe Zork, MDL—which was apparently designed by some of the same people who worked on Scheme and Common Lisp [1].
There appears to be an active but still incomplete open source compiler for ZIL written in C# [2], and a few Common Lisp experiments, but not many mature projects combining interactive fiction and Lisp.
I hope projects like this one catch on more. I've had trouble grasping other interactive fiction engines, which I often feel are trying to please programmers and writers but hitting an awkward space in between. Lisp's "code is data" idea seems like it could be a more graceful way of hitting that balance.
[0] http://www.ifwiki.org/index.php/ZIL
[1] https://en.wikipedia.org/wiki/MDL_(programming_language)
[2] https://bitbucket.org/jmcgrew/zilf/overview
I still find Inform 7 a deeply fascinating example simply for trying a "Prose is code" approach that tries to favor writers first, somewhat at the expense of sometimes making programmers frustrated.
[DM4]: http://inform-fiction.org/manual/download_dm4.html