Tool to generate COYA and export to Inform 6 / zcode

I find an old tool : Aventure Book.

It’s a windows tool (it works under Windows 10 !).

You can visualy create CYOA. : you type the choices and the link between us, no programming.

The tools generates Inform 6 code and compile to zcode .z5

If I may, Moiki Stories just added an export to z5 functionality :

1 Like

Interesting! The converter might need a little tightening… looking at the demo game, in Frotz I get “object#x” output that doesn’t show up in Parchment, and in Ozmoo I get Choix non reconnu, veuillez recommencer. even for valid input, which seems relevant since “a ton of retro computers” is mentioned as one of the points of I6 output.

Update: In Ozmoo, it rejects the regular 1/2 numbers until it gets a different kind of invalid input. Simply entering >a is enough to fix the problem and allow the game to continue. However, the game will later crash with a stack full (Ozmoo fatal error #6) message.

Thanks! I’ll pass that on!

I am the author of Moiki. To be more descriptive, Moiki is a webapp (only in French for the moment) that allows you to create stories with choices in a simple way (aka, no script).
I did few exports including ink, twee, pdf (to create a kind of cyoa book) and now inform6!
As @jcompton pointed out, there were a lot of issues: sweat_smile: but they’re fixed now.
In addition, the generated code has become very light and can be compiled in version z5 or z3.

If you are curious, I put a compiled sample available here (in french…) :


Why are some commands in English? Help, Redo, List, Show, Exit, etc.

Oh, the reason is: in English all these words are 4 characters long and this was handy for my code :slight_smile:
Anyway, my next step is to add a personalization page in the generator. From this page I will put some options to localize the hardcoded strings (like “Gagné” or “Cette commande est inconnue” etc.). I hadn’t thought of it, but I will be able to add localization for the menu commands.

Indeed, it’s a good reason.

I would be curious to see the Inform 6 source code.

No problems, you can get a sample here :
This is an export of this (ridiculous) story :

Thank you.
Your getInputChoice() function could be much simpler using the dictionary rather than testing letter by letter input. But you may have good reasons to do it this way.

In fact, I’m just a newbie in inform, so, if you have an advice / sample on how you will do it I can implement it in a better way. I don’t know how the dictionary is working…

I’ll take a look at that. It’s pretty close to what I’ve already done: La mort bleue, La caverne des Morlocks
You’re targeting Z-code v3, v5, v8 and GLULX?

Thanks, I will have a look. Until now, I’m targeting only zcode v3/v5. Maybe one day I will look around GLULX…, but I have some features I want to implement in my editor (and in all the exporters) before that.

(not the sort of thing the usual IF awards bodies look at, but surely .z3 has earned some sort of “Comeback Player Of the Year” award…)

Yes, but I wonder if the mandatory status line, that doesn’t seem to be editable, is not a problem here.
The point is that there are v3 experts now.

A quick example that is not v3 compatible but I will adapt it.
The choices are from 1 to 9, and not 10 as in your code.

!% -Cu
!% -~S

Constant MAX_INPUT_CHARS = 9;
Constant MAX_BUFFER_WORDS = 2;
Array buffer->(2+MAX_INPUT_CHARS+1);
#IfNot; !v3
Array buffer->(1+MAX_INPUT_CHARS+1);
Array parse->(2+(MAX_BUFFER_WORDS * 4));

[ LenMot motn; return parse->(motn*4); ]; 
[ PosMot motn; return parse->(motn*4+1); ];
[ DicMot motn; return parse-->(motn*2-1); ];
[ NbrMot; return parse->1; ];

[ showHelp; "HELP !^"; ];
[ showUndo; "UNDO !"; ];

[ getInputChoice numChoices   n ret;
   print "^>";
   read buffer parse;
#IfNot; !v3
   @sread buffer parse;
   if (NbrMot() == 1) {
      n = (buffer->(PosMot(1)))-'0';
      if (LenMot(1) == 1 && n > 0 && n < 10) {
         if (n <= numChoices) return (n);           
         print "Cette saisie ne correspond à aucun choix !^";
         jump FreshInput;
      ret = 1;
      switch (DicMot(1)) {
         'help': showHelp();
         'undo': showUndo();
         'redo': ;
         'exit': return (0);
         'list': ;
         'show': ;
         default: ret = 0;
      if (ret) return (0);
   print "Cette commande est inconnue ! Tapez ~HELP~ pour une liste des commandes disponibles.^";
   jump FreshInput;

[ main   choice;
   buffer->0 = MAX_INPUT_CHARS;
#IfNot; !v3
   buffer->0 = MAX_INPUT_CHARS + 1;
   parse->0 = MAX_BUFFER_WORDS;

   choice = getInputChoice(2);
   print "Choix : ";
   if (choice) print choice;
   else print "Meta verbe";
#EndIf; !TARGET_

Edit: Update for v3, v5 and v8.

Interresting! Thank you for this sample, the concept is clear.

On my side, I changed my exporter to generate 2 files : a .inf with all the strings as constants and a .h with all the “hidden work”.
Now, I can give a custom name to the commands, (eg.: Constant HELP = "HELP";)

It’s great, because it allows final users to easily tweak the generated code.
To make the “getInputChoice” correctly match command names (that are given dynamically now), I need to compare the string (eg. “HELP”) with the content of the buffer that store user inputs. So far, it works well, even if the code is a little bit verbose.
To implement your solution, I’m not sure how I will convert “HELP” like strings, to ‘help’, but I will have a look.

I’ve updated all z3/z5 export demos and the sample source .zip file if you’re still curious (same links).

Don’t define your constants as strings of characters, but as words from the dictionary: ‘aide’, ‘liste’ etc.

!% -Cu
!% -~S

Constant STR_CMD_HELP = 'aide';
Constant STR_CMD_LIST = 'liste';

Array Storage->32;

! From inform 6.12 library
[ UpperCase c; ! for ZSCII matching ISO 8859-1
   switch (c) {
      'a' to 'z':                            c = c - 32;
      201, 203, 211, 213, 220:               c++;
      215, 216:                              c = c + 2;
      155 to 157, 164, 165, 205 to 207:      c = c + 3;
      181 to 185, 191 to 195:                c = c + 5;
      169 to 174:                            c = c + 6;
   return c;

[ wputs w   i;
   @output_stream 3 Storage;
   print (address) w;
   @output_stream -3;
   for (i = 0 : i < Storage-->0 : i++)
      print (char) UpperCase(Storage->(i+2));  

[ Main;

Why not make a constant text and a constant dictionary:
Constant STR_CMD_HELP = “AIDE”;
Constant STR_DICT_HELP = ‘aide’;
Edit: Array Storage->32; Byte instead of Word.

Save your source files in UTF-8, it’s much easier to manage accents. Just put the !% -Cu option at the top of your file.

Oooh! Nice, I will certainly give it a try! Thanks!

I’m not really a fan of the solution which uses two constants because it forces the end user to be more vigilant. I might have to compare the two versions to see which is more advantageous in memory.