################################### # Untitled Storybook Game Project # ################################### This will be a project to create a system whereby "Choose Your Own Adventure" (CYOA) style stories can be easily written. Each page will read out story elements, and then prompt the user to select a new page based on a decision they would like to make. Making certain choices will also award ad-hoc stat bonuses i.e. +1 Knowledge or something, all stats are presumed to be 0 until points are awarded. This stat system also includes the ability to make checks when certain choices become available, or once they are selected. Requirements: 1. A language description and recognizer for creating CYOA-style stories. 2. An interpreter and interface for interacting with these stories. 3. Both story-writing and story-interaction tools need to be cross platform and relatively straightforwards for a non technical user to operate. Story language PEG: Story <- BlankLine* Title Attribution Page+ EndOfFile Title <- (!Attribution .)+ Attribution <- (!Newline .)+ Newline Page <- Header Body BlankLine* Header <- Identifier Newline BlankLine* Identifier <- [A-Z][A-Z0-9_]* Body <- Footer / TextLine Body TextLine <- (!Newline .)+ Newline Footer <- Ending / Goto / Choice+ Goto <- 'GOTO' Spacing Identifier Newline Ending <- 'THE END' Newline Choice <- [0-9]+ ')' Spacing (!Redirect .)+ Redirect Redirect <- StatCheck? Spacing '[' Identifier ']' Spacing StatChange? Newline StatCheck <- '<' StatName Spacing [0-9]+ ('+' / '-')? '>' StatChange <- '(' ('+' / '-') [0-9]+ Spacing StatName ')' StatName <- [A-Za-z]+ EndOfFile <- !. BlankLine <- Spacing Newline Spacing <- (' ' / '\t')* Newline <- '\r\n' / '\r' / '\n' Work log: 12/13/21 Right now I need to make a decision before any of the work has started on how the user would interact with the system. I think for a MVP it would be okay to just write a console application, but I think for the long term there needs to be a decision made on how this will work. I'm leaning towards one of three options. 1) We put the whole thing on the JVM and make it a library or something. Maybe in the future we can make a frontend for making and playing stories as a web interface, but we could make the interface pluggable as far as the backend is concerned. 2) I build this non-traditional game in a traditional game engine (Godot probably). This ensures cross-platform availability. I'm not 100% sure about my ability to use parsers in Godot, but this looks like a good option. 3) I build this as a reactive web page. I know this sounds like a terrible idea, but there are actually a lot of cool image and text transition libraries out there. It does mean setting up something like React tho, which like, just kill me now Out of the three of these I think the Java thing would be the easiest and I think the Godot thing would be the best. 12/26/21 Merry Christmas! Forgot to update this for a bit, but let's talk turkey about what's been done so far. I decided to implement this as a C++ project for portability. I know Java might have technically been more portable, but I'm thinking Godot is in the near future for this and Javascript has something like a FFI so I went for a C project called "peg/leg" (`man peg` weirdly...) to implement the language. I can't recommend the project, it is not copyleft and although the "leg" tool provides a lex/yacc-like interface but it does a terrible job of documenting the peg semantic actions, (like how the fuck the * operator works or how to properly use the predicates), and a lot of stuff is straight up missing (%nterm, $1, yyin). I like PEGs, but if I could do this again I'd just use flex/bison. Where to go from here? I could just start integrating this into a Godot project. Right now I'm making a little command line driver to test it out. Portability? This project is gonna be small and I could just use submodules, or just little subprojects in the same project for each interface (Web/Godot/Whatever else). At this point I've written so little code that I think I could just port it to each project as well. For Godot I'm pretty sure I'll have to integrate it with the SCons build that they provide on their website, so I probably can't link to a .so file. 12/30/21 I tried to migrate to a library "pegtl", which is pegs implemented using the C++ standard template library. It was a bit of a bust. The project was very deep, very academic and hard to pick up, especially since I'm not really a C++ guy. Guess I'll just keep chugging with what I've got. Next up is integrating with Godot for real this time. For real. This time... 1/1/22 I'm getting pretty frustrated with what I perceive to be bugs in the peg/leg parser. The project seems abandoned and I don't really feel like maintaining it. And GNU Bison is like right there. If I can write a cfg for my little language here I'll switch. I also can't shake the feeling that this is over-engineered, and I really don't need a parser for all this, but oh well. I could probably do it all with just lex actually. Maybe I need to spend some time rethinking this. 1/2/22 Okay I decided to just power through, and I finished the CLI version, which I'll be committing with this update. I did write a CFG however I realized that since this isn't a programming language an LR parser isn't exactly right. I made the right choice with the PEG, I just need better tooling. Anyway the immediate problem that I was having was that I assumed that semantic actions following an optional term in leg would be run with a null pointer or not be run at all, but it turns out you need to wrap the semantic action in the optional as well. Oh well lesson learned. Maybe some day I'll write my own. Next up is definitely the Godot Native module. I've already read a bit about how to do it, but I know there will be a few hitches here and there. Also I want to convert the base module to use entirely c++ semantics, with the exception of printf since I'm not sure if there is a c++ parallel, which is a bit odd. C++ is weird, no wonder I've avoided using it until now. It seems like c++ developers spend a lot of time coming up with new ways to do things, then declaring them unidiomatic and banning them. I guess that's kind of a trend with higher level languages as they get older cough Java cough. Regardless, I need to learn it and this is as good of a project as any. Also I still haven't mentioned to Pam I was doing this. Hope that's not a problem... 1/2/22 cont. Okay I've got the skeleton of a Godot Native module there, but I'm realizing cross-platform builds are limited by the compiler I'm using for the base module. I think I'll need to either compile from source for the Godot thing, or port the whole project over to the SConstruct build system, which shouldn't be too hard considering the size of the project. Still, yet another thing I have to learn, not too happy about that. 1/11/22 Well I found a library that's got good promise, but there was a catch, it's a Rust module. Fortunately Rust is like the coolest darn language I've ever seen. Guess I'm a Rust person now, ain't never gonna learn C++. Darn. Anyways I'm porting the whole library over on the rust branch, getting the parser working was easy as pie. Rust (despite having closures and algebraic data types) can just compile down to a static library so I'm going to do that instead of the peg/leg mess. If nothing else, finding this library and Rust itself just made this whole project worth it. 1/20/22 Okay this project is taking a really long time. At this point it was really just an excuse to learn Rust but now it's finally time to make this into a game! Up next is GODOT, it's that time now. Really got to take care of business. Rust stuff is done and somewhat in, I've left the old library for now. Also the "rust-ffi-demo" should really just be the CLI program now, but it's missing the game logic. I've decided the library won't handle that anyway, I'll try and make the library just read the stories and handle the pages. 1/24/22 So putting the whole project into a C-ABI compatible library was pretty exhausting but it's done now, and I was about half way through translating that into a Godot Nativescript module when I found the Rust "gdnative" package. It just does almost everything for you. On one hand I'm upset that I spent so much time on the C stuff but whatever. Rust apparently lets you add submodules right into your project, so that's all done. Do we want to call it a day? Nope. Here's a list of changes 1. Titles and authorship should be in the file. This means that a book is no longer a list of pages. Good thing I changed to a more flexible peg parser. (Complete as of 2/11/22) 2. Options with stat checks and changes should only happen the first time. That or ban circular stories altogether. (Let's hold off on this for now...) 3. Multiple stat check and change blocks per option should be permitted. 4. Allow statchanges on GOTOS I should really show this to Pam soon, I just want to get one example working that isn't totally embarrassing. 2/11/22 Work on this seems to be winding down, or perhaps real work is winding up. Either way a winding has occurred. I think I'm going to work on errors for a bit, building out static analysis. I sent what I had to Pam and I think she liked it, she says she's writing out a story now.