Saving without a dialogue box, and Quixe

I need to identify the source of some inconsistent restore behaviour. Odds are the source is going to be related to my custom save code (originally by Erik Temple)

So, normally in an I7 game, if you save a game and restore it, there’s no look by default upon the restore. I checked that.

In my project I’m using custom quicksave/quickrestore code that saves a file to a slot without using a dialogue.

What I’ve noticed when using this code:

  1. In the IDE or Gargoyle, a look occurs after the restore. It seems to happen ‘automatically’ - I don’t have a rule asking for a look.

  2. In Quixe, the look doesn’t happen automatically.

This would normally not be a big deal except the CYOA engine is wrapped around the skeleton of LOOK.

Obviously, if I add a post-restore look myself, I end up with 2 looks in IDE/Gargoyle, and just the one I need in Quixe.

I’m going to paste the I6 and the hooks here in case someone can see something to target re: why this is happening:

[rant][code]Part - Quicksaving

A save slot is a kind of thing. slot 1 is a save slot.

A save slot has an external file called the savedata.

The binary file of slot 1 is called “slot1”. The savedata of slot 1 is the file of slot 1.

An external file can be a save file.

the file of slot 1 is a save file.

Restoring from a saved game is an activity.
Failing to restore from a saved game is an activity.
Automatically saving the game is an activity.
Failing to automatically save the game is an activity.

For restoring from a saved game (this is the restoring from a saved game rule):
say “[bold type][bracket]Game restored - play on.[close bracket][default type][paragraph break]”;

For failing to restore from a saved game (this is the failing to restore from a saved game rule):
say “[bold type][bracket]Sorry, your game could not be restored for some reason.[close bracket][default type]” (A);

For automatically saving the game (this is the automatically saving the game rule):
say text of save the game rule response (B);

For failing to automatically save the game (this is the failing to automatically save the game rule):
say “[bold type][bracket]Sorry, your game could not be saved for some reason.[close bracket][default type]” (A);

To load_savedata (filename - save file external file):
(- FileIO_LoadSavedGame({filename}); -).

To write_savedata to (filename - save file external file): [see note above on read routine]
(- FileIO_WriteSavedGame({filename}); -).

To set (filename - external file) as a save file:
(- FileIO_SetSaveFile( {filename} ); -).

To decide if (filename - external file) exists: [This phrase can be used on both save game files AND regular table files]
if filename is a save file:
set filename as a save file;
decide on whether or not filename exists part b;

To decide if (filename - external file) exists part b:
(- (FileIO_Exists({filename}, false)) -).

Include (-
[ FileIO_LoadSavedGame extf struc fref res;
if ((extf < 1) || (extf > NO_EXTERNAL_FILES))
return FileIO_Error(extf, “tried to access a non-file”);
struc = TableOfExternalFiles–>extf;
fref = glk_fileref_create_by_name(fileusage_SavedGame + fileusage_BinaryMode, Glulx_ChangeAnyToCString(struc–>AUXF_FILENAME), 0);
if (fref == 0) jump RFailed;
gg_savestr = glk_stream_open_file(fref, $02, GG_SAVESTR_ROCK);
glk_fileref_destroy(fref);
if (gg_savestr == 0) jump RFailed;
@restore gg_savestr res;
glk_stream_close(gg_savestr, 0);
gg_savestr = 0;
rtrue;
.RFailed;
CarryOutActivity( (+ failing to restore from a saved game +) );
];

[ FileIO_WriteSavedGame extf struc fref res;
	if (actor ~= player) rfalse;
	if ((extf < 1) || (extf > NO_EXTERNAL_FILES))
		return FileIO_Error(extf, "tried to access a non-file");
	struc = TableOfExternalFiles-->extf;
	fref = glk_fileref_create_by_name(fileusage_SavedGame + fileusage_BinaryMode, Glulx_ChangeAnyToCString(struc-->AUXF_FILENAME), 0);
	if (fref == 0) jump SFailed;
	gg_savestr = glk_stream_open_file(fref, $01, GG_SAVESTR_ROCK);
	glk_fileref_destroy(fref);
	if (gg_savestr == 0) jump SFailed;
	@save gg_savestr res;
	if (res == -1) {
		! The player actually just typed "restore". We have to recover all the Glk objects;
		! the values in our global variables are all wrong.
		GGRecoverObjects();
		glk_stream_close(gg_savestr, 0); ! stream_close
		gg_savestr = 0;
		CarryOutActivity( (+ restoring from a saved game +) );
		rtrue;
	}
	glk_stream_close(gg_savestr, 0); ! stream_close
	gg_savestr = 0;
	if (res == 0) CarryOutActivity( (+ automatically saving the game  +) ); rtrue;
	.SFailed;
	CarryOutActivity( (+ failing to automatically save the game  +) );
];

[ FileIO_SetSaveFile extf struc;
if ((extf < 1) || (extf > NO_EXTERNAL_FILES))
return FileIO_Error(extf, “tried to access a non-file”);
struc = TableOfExternalFiles–>extf;
struc–>AUXF_BINARY = struc–>AUXF_BINARY | 2;
];

-).

[We will also alter the built in if (external file) exists phrase so that we don’t confuse matters with two similar phrases.]

Include (-
[ FileIO_Exists extf fref struc rv usage;
if ((extf < 1) || (extf > NO_EXTERNAL_FILES)) rfalse;
struc = TableOfExternalFiles–>extf;
if ((struc == 0) || (struc–>AUXF_MAGIC ~= AUXF_MAGIC_VALUE)) rfalse;
if ( struc–>AUXF_BINARY )
{
usage = fileusage_BinaryMode;
} else {
usage = fileusage_TextMode;
}
if ( struc–>AUXF_BINARY & 2 == 2 )
{
usage = usage + fileusage_SavedGame;
} else {
usage = usage + fileusage_Data;
}
fref = glk_fileref_create_by_name( usage, Glulx_ChangeAnyToCString(struc–>AUXF_FILENAME), 0 );
rv = glk_fileref_does_file_exist(fref);
glk_fileref_destroy(fref);
return rv;
];

-) instead of “Existence” in “FileIO.i6t”.[/code][/rant]
Then the line to reload a game is ‘load_savedata savedata of slot 1;’

-Wade

I can’t bring myself to really trust Gargoyle, so out of curiosity, what is the behaviour when you use WinGlule or WinGit or Filfre? If you can’t test yourself and are curious, PM me the build and I’ll tell you.

Until I get back to you I’m sure someone will have sorted it out, but, you know, when behaviour’s inconsistent across interpreters I find it best to check all available interpreters and see where the odd one out is.

EDIT - Quixe would seem to be the odd man out, wouldn’t it? If by default you don’t get a look and you want a look… and if by default terps do not print the description after a restore (I checked to be sure, and Gargoyle usually doesn’t either)… It seems to point at Quixe.

I suppose the same issue would pup up in Lectrote, but while no one answers you better, maybe you could try it out in there. Just to make sure.

EDIT - Kids, this is what a post looks like when you really want to be helpful but don’t have the knowledge to back it up. Take heed.

Can you post a complete game that shows this problem?

I tried adding lines to your sample to test it:

Quicksaving is an action out of world applying to nothing.
Understand "qsave" as quicksaving.

Quickloading is an action out of world applying to nothing.
Understand "qload", "qrestore" as quickloading.

Carry out quicksaving:
	write_savedata to savedata of slot 1.

Carry out quickloading:
	load_savedata savedata of slot 1.

But the result does not auto-look in any interpreter.

(This may be a Quixe bug that I found this weekend, but I want to try a real test case.)

Hehe, that’s how I feel about 50% of the time in this forum. Usually what happens is - I try to help someone who is asking something not too outrageously difficult, then matt w appears and points out that I either misread or misinterpreted the original request, then he also solves their problem.

Re: Lectrote, that’s actually where I first spotted the problem, which made me go backwards to try it in Quixe, where I got the same thing, further suggesting Quixe.

Zarf, I’ll PM or email you.

-Wade

Email preferred, thanks.

Lucky for you, that’s the choice I made before I read your post.

-Wade

This would have been easier to spot if you’d specified what part of the “look” wasn’t working. I spent quite a bit of time staring at the (correct) text

…before realizing that it was the menu list that was missing.

Anyway. Yes, I think this is the same bug, which is that when a restore occurs, local variables up the stack are corrupted. That is, in the function calling FileIO_WriteSavedGame (and any functions calling that), local variables wind up restored incorrectly. This does not affect normal Inform games, because they happen not to rely on any local variables in those functions after the save/restore point. But I guess you are.

(The bug does not affect undo, only restore.)

It is fixed in the Quixe repo, and the fix will be in the next Lectrote release.

Sorry about this. The bug has been around forever – it’s in every version of Quixe. I only noticed it this weekend because my autorestore work bumped into it.

And yes, I think you reported this once before – or someone reported a similar problem which fits the same situation – and I didn’t follow it up then. Oops.

Sorry. I just forgot what would be obvious or not after working with this particular setup for months.

It was me, but I was trying to solve several problems at once and had not isolated their causes. Folks including yourself collectively solved at least one of the problems, then I forgot about this one or mistakenly believed it had gone away. And nobody else had cause to dwell on it.

Thanks.

-Wade