Having 1-byte external file with z-machine

The TLDR is that I read Can an Inform 7 project hosted online communicate with an external file? and realized that what I wanted might be possible. That is, z-machine code that focuses on one byte and sends it to the external file once you solved an area. Or it reads the byte from the file once you start.

I’m a bit baffled as to how to do things here, though. The pseudocode needed would be

(read the external file to, say the Global_Vars–>25 variable, or binary-progress-number i7)

(write the Global_Vars–>25 variable to the external file)

Or, perhaps, writing and reading an array of booleans. But I think I could derive this from the example where we just read Global_Vars–>x.

special case: Fourdiopolis re-release

I was recently putting the finishing touches on a re-release of Fourdiopolis. It was glulxe, and I thought that was just due to 32-bit hashes to make searches for scenery go faster–so I set OMIT_UNUSED_CODE and even memory economy to make it build in z-machine in debug.

With that & other changes it was well within z-machine limits … except for one thing! I had an external file that saved progress. Now Glulxe has a command for that, but Z-Machine throws a runtime error.

My test case is as follows: Fourdiopolis wants to save one byte for progress to an external file. It is 6 bits or’d, depending on the progress you’ve made. So if you solved scenario 1, it’d write 1, or 2&3, it’d write 6, and so forth.

Obviously, having something fit in z-machine isn’t strictly necessary, but I’m proud of what I did, and I’d like to reduce the binary size if I can, especially since the final thing to do, where I’m clueless, seems a potentially trivial case. (If not, glulx it is!)

Thanks to all who can help!

Try this:

Include (-
Constant SAVE_DATA_SIZE = 1; ! In bytes
Array saved_data -> SAVE_DATA_SIZE;
Array save_filename static string "exdata.aux" ! Set this to something unique to your game

[ SaveDataToFile res ;
    @save saved_data SAVE_DATA_SIZE save_filename 0 -> res;
    return res;
];

[ LoadDataFromFile res ;
    @restore saved_data SAVE_DATA_SIZE save_filename 0 -> res;
    return res == SAVE_DATA_SIZE;
];
-).

To decide whether saving to the/-- external file succeeded: (- SaveDataToFile() -).
To decide whether loading from the/-- external file succeeded: (- LoadDataFromFile() -).
To decide what number is byte (N - a number) of the saved data: (- saved_data -> ({N}) -).
To set byte (N - a number) of the saved data to (X - a number): (- saved_data -> ({N}) = {X}; -).

Note: NOT TESTED YET. But this is how I’d go about it. I’ll test it properly when I have time.

2 Likes

See related discussion at Which interpreters comply with ZMS 1.1 regarding prompt parameter of @save/@restore opcodes?.

2 Likes

I don’t know exactly how well supported the extended operands are, but I know that they’re not supported in Parchment/Lectrote at least. Just use Glulx.

Things work with my simple test case! I’ll try to include them.

This would be the case most of the time, but here it really is a matter of one byte.

Inform 7 of course has SAVE and RESTORE, but in this case, if someone forgets their save file, it tries to be smart and say, okay, these are the scenarios completed. It’s sort of an extra small thing that’d be nice to have. It looks like I can … and if it isn’t available on the web version, I can definitely live with that, because I can hint at it in other ways.

I’ll try and include the official source code changes that I push to github, to show people how it was implemented in a simple case, so anyone else who wants to try this can know/see/study for later.

1 Like

A slightly more general-purpose version would let you set the number of bytes saved via a use option, and store words instead of bytes, since I7 generally doesn’t make you worry about wrapping around at 256. So if I make it an extension, I’ll do that. But for a single byte it seemed like overkill.

It’s not the size of the data that’s the issue. It’s that this is a very niche, and arguably experimental, feature. The full 1.1 save features were only added to both Frotz and Bocfel last year. Are there any other interpreters that support it? I really doubt it. And saying that it was added to Frotz really means Unix Frotz. It looks like Windows Frotz also supports it, but many other Frotzes wouldn’t. IosFrotz doesn’t. So you can’t even tell players to play it in “Frotz”, or “Gargoyle”. And it’s not a feature that you can easily test whether the interpreter supports it. You’d have to bundle the game with an interpreter, or else specify exact interpreter version numbers.

Usually when people are targeting Z-Machine it’s for retro reasons, which is a fine intent to have! But this isn’t a retro feature. It’s cutting edge. Glulx is actually the conservative option here. Compile to Glulx and you could actually use it on a ~15 year old interpreter.

I dunno; I used the @save opcode back in the ‘comp96.z5’ ‘front end’ game for saving text (the randomized list of games) to a file. And every year from there through 2012, there was a new one, so I think most interpreters from that era at least implemented @save, if not @restore.

(I mean, they obviously implemented ‘save’ and ‘restore’ for save game files; it’s just the ‘save/restore only this bit’ that had to be handled differently.)

It’s exactly the sort of thing that could easily be lost again (since virtually nothing else uses it), so I’m not surprised if ‘losFrotz’ los’t it (sorry).

However, that points to another reason to not do this in zcode: even if a suite of interpreters support it at a given moment, it’s the sort of thing that can get dropped in the next generation of interpreters. I would echo the suggestion to use Glulx, since those interpreters have (I think) been more consistent in implementing support for it.

1 Like

It’s specifically the prompt operand that doesn’t seem to have been implemented very widely. But it’s also an issue that the game can’t (easily) tell if the interpreter saved a savefile or a data block.

A whole bunch of really good ideas here. Thanks all for adding to the data I can think about. There’s so much more than “gee, a neat feature I’d like to add.”

So: I really do want to have a z-machine version of the re-release as a personal goal. I’d like to have the special functions in there, for if/when interpreters support them, but if not, that’s no problem.

This is one of the ways I feel I can grow as a programmer, but I don’t want it to be a vanity thing.

I think telling the player “you can type CONFIG 1 to start with this area finished next time” works well enough until things are supported

One of the other main reasons to convert to z-code was for speed on the web version. Thankfully, some fixes (checking for hash values instead of indexed text) made things go a lot quicker, and while it isn’t as instantaneous as more normal parser games, testing shows the speed’s satisfactory.

So I think it’s probably best to release the gblorb to the web, then, since this is a tricky feature to support, and I’ll have a separate zblorb to download, noting that’s my own technical project. Inform allows us to have (for Z-machine only) and (for Glulx only) sections, and I’ve only used them in a trivial extensions header before.

1 Like