Inform6/Z-machine command to indent all printed output?

I’m working on another Adventure port (to Parchment). I’m wondering if the Z-machine has any built-in support for indented output, like this:

> DROP BIRD AND CAGE Little bird The little bird attacks the green snake, and in an astounding flurry drives the snake away. Wicker cage Dropped.
That is, if my current code looks like

print "Little bird^"; set_indent(true); print "The little bird attacks the green snake, and in an astounding flurry drives the snake away.^"; set_indent(false); print "Wicker cage^"; ...
then is there any sequence of instructions that I can put into set_indent() to make it behave as above? or must I resign myself to using a wrapper function around every “print”?
As in the subject line, I’m writing in Inform6 (assembly is okay) and targeting either .z5 or .z8. A thousand bonus points if the solution works in the presence of explicit linebreaks, as in “…astounding flurry^drives the snake…”

That is rather difficult, because the Z-machine (v5/8) does not deal with the concept of line-wrapping. It sends out a stream of text, and the interpreter formats it as necessary. (v6 lets you have control of line-wrapping, at the price of having to pay attention to line-wrapping, which is an almighty pain in the butt.)

If you’re setting up a Parchment page, you have the option of customizing the stylesheet. You can set margins and indentation in the CSS file. But it looks like you want to indent some lines, which is rather more dificult. You’d have to apply some hacks – maybe repurpose one of the Z-machine “fonts” to be a custom CSS class.

Yep, I’m aware that the Z-machine leaves line-wrapping up to the implementation; but I was kind of hoping there might be some way for the Z-machine to communicate to the implementation a request like “indent this text” (or “blockquote this text”) the same way it has a way of communicating the request “put this text in a pop-up box”. Not that I know how that works; I guess it’s just an application of the general windowing facility.

That’s an interesting idea that might be worth my pursuing.

I think the path of least resistance, though, is for me to replace every “print foo” with “myprint(foo)”, and have myprint() somehow loop over the characters of the argument string and append four spaces to every newline character if necessary. (I’m doing explicit linebreaks already, actually, even though my initial question implied the opposite.)

Hmm… you could print to stream three and programmatically add line breaks. Hacky, but it should work.

I infer that this was a solution to my “somehow loop over the characters of the argument string”, right? (It requires hacky solutions because strings are normally stored compressed in ROM and thus don’t have individual characters to be “looped over”.) Here’s what I put together in a few tens of minutes of hacking:

Array BUFFER --> 100;

Global need_indentation = 0;

[ indent_newlines start end i c;
for (i=start: i < end: ++i) {
c = i->0;
if (need_indentation) print " ";
@print_char c;
need_indentation = (c == 13);

[ printme indented string len letters end_of_letters ;
if (indented) {
@output_stream 3 BUFFER;
@print_paddr string;
@output_stream -3;
len = BUFFER–>0;
letters = BUFFER+2;
end_of_letters = letters+len;
need_indentation = 1;
indent_newlines(letters, end_of_letters);
} else {
need_indentation = 0;
@print_paddr string;

[ Main ;
printme (0, “Little bird^”);
printme (1, “The little bird attacks the green snake, and in an astounding flurry^drives the snake away.^”);
printme (0, “Wicker cage^”);
printme (1, “Dropped.^”);

Now, just like ZSCII itself, stream three isn’t Unicode-safe. At least on Fizmo, if you enable stream 3 and then “@print_unicode 8212”, the buffer ends up containing just a single byte 255. This won’t be a big deal for me; it’s just something I noticed.

I think what I’m going to end up doing is implementing “indent_on()” and “indent_off()” builtin functions in the vbccz C-to-Inform compiler, and then making the builtin puts/printf interact with them. (My puts/printf already interact correctly with Unicode, which is why stream 3’s Unicode-ness isn’t a big deal.) Kind of crazy, but it’ll work.

Alternatively, I could finally implement a compiler feature where C string literals are encoded as Z-machine strings no matter how they’re used, and then magically unpacked into bytes (via stream 3) whenever the program needs to access them byte-by-byte. But that seems like a ton of work just to specify the semantics, let alone actually implement. (Right now strings are stored as byte Arrays, except in the special case of arguments to puts/printf, which are stored as Z-machine strings. A large part of fitting a game into 64K involves figuring out how to refactor char* variables into string literals.)

Depends how much unicode you have - if you can fit all the extra characters into a custom unicode table then they will be written back to stream 3 safely.

Resurrecting this thread to announce that I’ve successfully implemented a solution to my original problem! It does end up using stream three, basically as outlined above — thanks Dannii! To see it in action (in a reduced version of “Adventure 6” that uses only short room descriptions), visit … 1-short.z8

And my code is available on Github as usual: