Playing Sean Barrett's "Heroes" in Frotz -- skipped output?

While playing Heroes by Sean Barrett using Frotz, I noticed that some of the output in the final scene seems to be skipped.

If played in Gargoyle/Bocfel, the epilogue text that appears after completing the last of the five stories begins:

Now do you understand, my love? Do you not recognize your old friend the bard there, before the fire? 

No, rest. Elando still lives, for now. The Kriit drained only a fraction of his life force. I would never rob you of your vengeance. You can finish him at your leisure.

However, if playing in Frotz 2.54, most of the first paragraph is skipped. The epilogue begins with:

No, rest. Elando still lives, for now. The Kriit drained only a fraction of his life force. I would never rob you of your vengeance. You can finish him at your leisure.

The issue seems to have something to do with the window size. If played within a window at the default size, the last word of the first paragraph is included:

fire? 

No, rest. Elando still lives, for now. The Kriit drained only a fraction of his life force. I would never rob you of your vengeance. You can finish him at your leisure.

Does anyone else see this behavior, or is it something specific to my setup?

Following is a save file to help illustrate the problem. It’s for release 2, and the command >GET GEM will finish the game.

heroes.sav (4.0 KB)

I haven’t tested this in interpreters. But it looks like the text gets printed after a screen-clear, and then the first line of the paragraph gets covered up by the status line.

That makes sense, in terms of screen layout. If I use a narrower window, then more of the last words of the first paragraph are printed.

The missing text does immediately follow a screen clear. I don’t get why it would be happening in Frotz but not Gargoyle/Bocfel, though. Some order of operations thing for the interpreters? Perhaps some strangeness in the way that the screen clear was implemented in the game?

From the spec, when you open the upper window (for the status bar or other purposes):

It is usual for interpreters to print the upper window on the top n lines of the screen, overlaying any text which is already there, having been printed in the lower window some time ago.

So it sounds like the screen gets cleared, Frotz prints the main window text starting at the top, then prints the status bar over it, obliterating the first line of that text. But Bocfel uses Glk, and in the Glk world, different windows can’t overwrite each other’s contents. So the main window text remains in the main window to be read.

Or to put it differently: in Glk, windows don’t overlap. So the main window starts at the bottom of the status bar, not the top of it, and that’s where the text ends up.

1 Like

Why doesn’t this problem come up more often? Well, the cursor always starts at the bottom left of the main window, well away from the status line. But in V5, a change was made to the @erase_window opcode:

In Versions 5 and later, the cursor for the window being erased should be moved to the top left. In Version 4, the lower window’s cursor moves to its bottom left, while the upper window’s cursor moves to top left.

Which means if you don’t print some newlines after a screen clear, it’s entirely compliant with the spec to have the status line obliterate the next few lines you print. This seems like a bad default to me, but it’s what the specs say.

So in versions 5 and later, you should always print some newlines after clearing the main window or clearing the entire screen. Conveniently, the interpreter stores the current window height (in lines) at 0->$20, so if you print that many newlines, you should always end up at the bottom of the screen again.

What I dimly recall from the days when I worked in Z-code:

This wasn’t a problem if the status window was already open when you cleared the screen. However, the I6 library might do a sequence of (1) set status line to zero height; (2) clear the window; (3) print text; (4) set status line to non-zero height. That was the bad case.

Heroes was library 6/10. This might have been addressed by a bug fix in 6/11. I don’t remember, but it seems like the kind of thing that we were looking at.

1 Like

Seems like the problem is caused by doing 3 before 4. I would think that the proper sequence would be doing 4 before 3. After all, status line is fixed font, while main window is proportional.

Or maybe just clear the status line without changing the height?

Suggested method of clearing the screen by printing lots of line will trigger (more) prompt, right? That’s not desirable.

That makes sense, too. I hadn’t really internalized the technical implications of Bocfel being Glk-based.

I ran the game file through reform to see what’s going on. The relevant logic is:

print "^^[press any key] ";
@read_char 1 -> local1;	! <-- waits for key
@split_window 0;		! <-- removes status line
@erase_window 65535;	! <-- erases whole screen
routine83864();			! <-- prints the epilogue text

By the time the final question prompt rolls around, the status line has been restored (presumably by the library as zarf says), so it is a case of simple overwriting and definitely a game-side issue (which is fortuitously negated by Gargoyle).

Mystery solved! I guess Gargoyle is the best interpreter to use for this game.

2 Likes

I wonder why the split window needs to be set to zero? Is there a bug I’m not aware of? I’m curious because I want to do ASCII art using Inform 6, and the status window will definitely be larger than 1!

This instruction doesn’t matter, since the following instruction (@erase_window -1;) unsplits the screen anyway.