How to know when the game state is saved for undo purposes (I7 in glulx via quixe)?

I’m producing something that involves an additional client that intervenes between the player and the game client (glulx via quixe). I’d like my client to track which exchanges between player and game comprise undo-able turns, so that my client can keep its own reliable record of the game history in the event the player employs undo.

This is a bit challenging because my testing reveals some quirks in when the game state is saved - for example commands rejected by the parser are usually undoable but not when they are the first turn.

A nice way to solve this would be for the game to output some mark-up whenever it creates a saved state for undo, so my client can intercept this mark-up and realise this exchange was not an undo-able turn. I’m tentatively guessing that might be a few lines of I6 (although perhaps not, seeing as I believe glulx itself has more of a hand in undo than inform itself?). But if anyone has any such lines up their sleeve, I’d be very grateful.

Alternatively, can anyone point to any other reliable way to know what is and isn’t undo-able? This is what I have noted so far:

  • Whenever I manually reject the player’s command, that exchange isn’t undoable.
  • When the parser rejects the player’s command without ever previously having accepted a player’s command, that exchange isn’t undoable.
  • The standard response to final question rule isn’t undoable.
  • I think there might be some issues with disambiguation requests but I haven’t got to the bottom of it.
  • I think there might be an issue with If the player consent’s style questions. I never use them but am not confident the parser never will.

It’s quirky because the Inform library has a couple of different code paths for “accept input” and they aren’t all rigged for undo-ability.

The low-level answer is to look at the Keyboard() function (an I6 function in the library). This can be summed up as

  • Print prompt, get input
  • Ignore blank input lines
  • Handle OOPS
  • Save an UNDO state

Regular input goes through this routine.Yes/no questions, wait-for-a-key pauses, and the game-over question do not.

My Unified Glulx Input extension (i7-exts/Unified Glulx Input.i7x at master · erkyrath/i7-exts · GitHub) tries to regularize this – run everything through a single input function with consistent (and controllable) undo handling. But it’s still experimental, I’m afraid.

2 Likes

Thanks Zarf! I followed your breadcrumbs and ended up in Glulx.i6t where I added the print statement in the following:

[ VM_Save_Undo result_code;
    @saveundo result_code;
    if (result_code == -1) { GGRecoverObjects(); return 2; }
	print "<undoSaveState />";
    return (~~result_code);
];

Now my client can, if it detects an undo (via mark-up I have also placed in the undo reporting text), rewind its own transcript to the appropriate place.

Except - could you suggest what I might add to make sure I properly deal with different possible values of result_code to only output the mark-up if the save was successful? That might still be a fly in my ointment, I think. Are there any other flies?

(I noted from doing this that if the first player command of the game is rejected by the parser, undo state is saved, but undo nevertheless won’t work. I think this doesn’t invalidate my approach, however.)

(If anyone wonders why on earth I want this: it’s so the player can request my client to replay the previous n turns, as if undone turns didn’t actually happen. My game is audio only.)