Where are the OOW/"hidden" action rules?

I’m looking to have the room the player appears in when the game is resumed be a variable room (like a checkpoint, but not necessarily the nearest room with a “checkpoint flag” in it), and not the one the game was saved in. Where would I find the “Saving the Game” rule, or any of the default actions/rules, for that matter? For example, how would I know whether my X rule is listed before or after or instead of some default Y rule?

Open the index pane and click on the actions tab. The actions are listed there. If you click on the magnifier icon next to the actions it lists the rules in their action rulebooks, including the ones defined by you, in the order of precendece.

I’ve tried that, but can’t find “source” of the “Carry Out Saving the Game” rule, which is what I would need to modify.

The out-of-world action rules are listed in the Index/Actions tab, same as all the other action rules.

(Sorry, Juhana just posted that.)

Out-of-world actions only have check and carry out rules; there’s no before/after/instead phases. (See chapter 12.15.)

I think you’ll have to write your own “carry out saving the game” rule, though. The source is I6 code in the template file ZMachine.i6t or Glulx.i6t.

I wish I could explore the index, but on this machine the Index tab is nothing but blank whiteness, for some reason (6LO2). On my other (non-accessible) machine I remember finding the action tab, but no explicit rules for “saving the game” (in red text) other than “carry out saving the game.”

What about the rules like “immediately restart the VM rule” and the “immediately restore saved game rule” (basically the rules I’m talking about). Are they all sourced in I6?

Most of the low-level stuff like saving and restoring is handled in I6. The easiest way to do this would probably be to put in a “check saving the game” rule that moves the player to the proper spot, then a “last carry out…” rule to move them back.

That sounds crazy enough to work. I’ll test that and report back with results, and stuff my noggin with I6 in the mean-time.

Tweaking the restore phase requires a little bit of brain-bending, as you’ll see if you try:

Report saving the game: say "### Just saved."
Report restoring the game: say "### Just restored."

Result: after a successful restore, the current action is “saving the game” and it’s the save rulebooks which are operating! If this doesn’t make sense, think about it more. :slight_smile:

The easiest way to get your result without descending to the I6 level is with the response messages. This is hacky, but effective:

The Kitchen is a room.
The Bathroom is east of the Kitchen.

The restore the game rule response (B) is "Ok. (Now in [run paragraph on][post-restore adjustment].)"

To say post-restore adjustment:
	move the player to the Kitchen, without printing a room description; 
	say the location;

Here the “say post-restore adjustment” phrase doesn’t just print stuff; it moves the player. This is icky but legal. The library is smart enough to display the “restore the game rule response (B)” after a successful restore, so it happens at the right time.

If you also want to trigger this after “undo”, it would be

The immediately undo rule response (E) is "[bracket]Previous turn undone.[close bracket] (Now in [run paragraph on][post-restore adjustment].)"

I did indeed find out today that tweaking these phases is pretty brain-bending!

I thought about it a bit more, and since I’ll be disregarding normal saving in exchange for using an item to save (like the typewriters and ink rolls from the Resident Evil series), I figured I could do all of my moving around in the “carry out using the save item” instruction.

But alas, things aren’t that simple.

The code below is exactly how the save system in my game works, and exactly where it doesn’t. After restoring a game, messages are printed that should only be printed after /saving/ the game, specifically.

So, I moved those messages to a “report saving the game” rule, but they were still printed after restoring a game (I figured out that restoring and saving were the same function then!).

So I tried to make a “first carry out restoring the game” rule, and a “last carry out saving the game” rule, but those didn’t even fire, for some reason.

I even tried to make a “loading flag” that flipped when the action was “restore the game”, and was checked in the “report saving the game” rule, moving the player to the desired location if true, and actually reporting saving the game if false, but that didn’t work either.

[code]Wand of Game Savery is a kind of thing.
The description of Wand of Game Savery is “Allows the game to be saved.”

Spraypaint of Game Savery is a kind of thing.
The description of Spraypaint of Game Savery is a kind of thing. “Allows you to tag a room to be returned to upon loading a game. (use TAG WALLS to do so)”

The wall-tag is a thing.
The initial appearance of the wall-tag is “A spray-painted mark is on the wall.”

Spraying is an action applying to nothing. Understand “tag walls” as spraying.

Check spraying:
if the player does not have a Spraypaint of Game Savery:
say “You need the Spraypaint of Game Savery to do that.”;

Carry out spraying:
say “You make your sweet mark on a wall of [the location].”;
now the desired location is the location;
move the wall-tag to the location;

The Sanitary Lab Room is a room.

The Golden Lab Room is a room. “Swishflick the Wand of Game Savery to save the game. You can use the spraypaint in your bag to mark a room to return to after using restoring a game (use TAG WALLS to do so). The Parking Deck is downwards.”

The Parking Deck is a room. The Parking deck is below the Golden Lab Room.

There is a wand of Game Savery in the Golden Lab Room.
The player is in the Golden Lab Room.
The player carries a Spraypaint of Game Savery.

The saving flag is a truth state that varies.
The saving flag is false.

The saved location is a room that varies.
The desired location is a room that varies.

When play begins:
Now the desired location is the Sanitary Lab Room.
Now the wall-tag is in the Sanitary Lab Room.

Check saving the game:
if the saving flag is false:
say “You need the Wand of Game Savery to do that.”;

Swishflicking is an action applying to one thing. Understand “swishflick [a wand of game savery]” as swishflicking.

Carry out swishflicking:
say “You intone the ancient spell [italic type]Wingardium Leviosavemygame[roman type].”;
now saving flag is true;
now the saved location is the location of the player;
say “The location to be returned to after saving is [the saved location], and we should hopefully end up in [the desired location] (the desired location) after restoring a game.”;
say “Before saving the game, we are in [the location] and are going to move to [the desired location], to try to get the game to save [the desired location] as the location to return the player to upon restoring a game.”;
move the player to the desired location, without printing a room description;
say “Now we are in [the location] and are saving the game.”;
try saving the game;
[these messages still print even after loading the game]
say “After saving the game, we are in [the location] and are going to move to [the saved location].”;
move the player to the saved location, without printing a room description;
say “Now we are in [the location], and hopefully the player has noticed nothing because all of this movement reporting will be silent eventually.”;
now saving flag is false;[/code]

Zarf I am going to fiddle with your suggestions and see if I can get my ideas to work.

That is indeed correct. :wink:

When you restore the game, it restores everything…including the action variables. So Inform now finishing the action that was in progress when you saved (saving the game), with the “loading flag” in the same state as when you saved.

Zarf’s solution is probably the best, or you could modify the I6 for that action slightly to expose the variable which tells whether you’re saving or restoring.

Would using an external file be another possibility?

Many thanks to Zarf for his insight! I’ve worked out the kinks in this problem :slight_smile:, but now for the thousand more. Ahh, newbie programming.

This is really awesome using the parentheses for 6L38–but I’m wondering if there is an easy way to add an “immediate” rule for 6G60?

Modifying SAVE_THE_GAME_R didn’t quite work, as the 6g60 auto.inf code and the 6l38 auto.inf codes are different. So if I do

Include (- ... return GL__M(##Restore, 2); ... -) instead of "Save The Game Rule" in "Glulx.i6t".

6L60+Glulx doesn’t like that. But it’s the only way I see to modify 6G38+Glulx to get the effect using the (B) syntax, which pretty clearly maps to

	RESTORE_THE_GAME_RM('B'); new_line;

In the auto.inf file for 6L38.

Am I missing something semi-easy here? Is there a way to choose source based on the compiler version used? Or is that too convoluted?

I’m asking because I am trying to write an extension, and ideally I’d like it to be 6G and 6L compatible. But if there’s no way to do this, that’d be kind of a bummer–and I’d assume I can’t just say “6G60 needs to comment out this code. Sorry.”


They really need to update the standard rules date, but it doesn’t seem like that happens. If they did you could have sections that were conditional on different version dates. You could also use a (for use with English Language by Graham Nelson) section heading, but then it won’t work with other languages…

Alternatively if you’re in I6 you can check the NI_BUILD_COUNT constant.

This doesn’t help with the possibility of using the same extension for 6G60 and 6Lxx, but in 6G60 you could presumably use Custom Library Messages by Ron Newcomb to replace library message 2 for restoring the game, with the same effect as the (B) rules. That way you wouldn’t have to dive down into I6 yourself (since the extension does it for you).

I guess this leaves open a possibility to have the 6G60 code be “for use with Custom Library Messages by Ron Newcomb,” and the 6Lxx code be for use without, and then instruct 6G60 users that they need to include CLM themselves. Though I don’t much like the idea of an extension that doesn’t include all its dependencies. Generally I assume that there will be different versions of extensions for 6G and 6L, though that might be harder for the authors to deal with.

Hm, yes, authors of extensions and of code that uses them. But maybe it can be reduced to a mere nuisance.

I am wondering if it’d be kosher to have, say,

[code]part IDE dependent

[6G60: uncomment text below for building on 6G60]

[6L38: uncomment text below for building on 6L38]

[uncomment one of the above sections]

I thought they did? The standard rules for 6G60 have the line

Version 2/090402 of the Standard Rules by Graham Nelson begins here.

While 6L* has Version 3/12****.

So the version is different–how would I make code that could find the version this way? Is it possible?

Oh they did change the date. When I saw the 2012 dated standard rules for 6L I thought they hadn’t updated it because it was released in 2014.

Unfortunately I thought the following would work, but it doesn’t.

[code]Section (for use without version 3/120430 Standard Rules by Graham Nelson)

Section (for use with version 3/120430 Standard Rules by Graham Nelson)[/code]

So the best thing to do then is use the I6 compiler constant NI_BUILD_COUNT. But I’m not sure how. Does anyone know how to get a string constant into an array?

VM_PrintToBuffer will do that. But that’s awfully heavyweight, and can only be done at runtime. You want something that can be used for conditional compilation.

It’s hacky, but you could test “#ifdef ShowOneExtension;” That function was introduced in 6L02.

aschultz, try this. Zarf’s idea was a good one, and through the 6L38 changelog I was able to find a constant I that I think was introduced then. I haven’t actually tested it for versions other than 6L38 though…

Include (- [ DetectCompilerversion; #ifdef RTP_TABLE_NOTABLE2; return 38; #Endif; #ifdef ShowOneExtension; return 02; #Endif; return 60; ]; -). To decide if the compiler is 6G60: (- ( DetectCompilerversion() == 60 ) -). To decide if the compiler is 6L02: (- ( DetectCompilerversion() == 02 ) -). To decide if the compiler is 6L38: (- ( DetectCompilerversion() == 38 ) -). When play begins: say "6G60: [whether or not the compiler is 6G60][line break]6L38: [whether or not the compiler is 6L38]";