I can’t seem to get the “immediately undo rule” to work for me. Here’s my sample:
Room1 is a room. "This is room 1.".
Room2 is west of Room1. "This is room 2.".
player is in Room1.
newundoing is an action out of world.
understand "newundo" as newundoing.
carry out newundoing:
follow the immediately undo rule.
“undo” behaves normally. “newundo” only pretends that it did something:
Room1
This is room 1.
>w
Room2
This is room 2.
>undo
Room1
[Previous turn undone.]
>w
Room2
This is room 2.
>newundo
Room2
[Previous turn undone.]
>newundo
Room2
[Previous turn undone.]
>newundo
Room2
[Previous turn undone.]
I believe the problem is that it creates the undo state right before parsing and executing the action, so when you jump back to that undo state, you’ve only undone the action of newundoing. This is why UNDO isn’t an action normally (like AGAIN and OOPS, it happens outside of the action machinery).
This seems to work. It isn’t perfect – for example, if the UNDO fails it prints an unrecognized command message – but it allows for undo-related code in I7. (It also removes OOPS, if anyone cares.)
Include
(-
Global just_undid_flag = 0;
[ Keyboard a_buffer a_table nw i w w2 x1 x2;
sline1 = score; sline2 = turns;
while (true) {
! Save the start of the buffer, in case "oops" needs to restore it
for (i=0 : i<64 : i++) oops_workspace->i = a_buffer->i;
! In case of an array entry corruption that shouldn't happen, but would be
! disastrous if it did:
#Ifdef TARGET_ZCODE;
a_buffer->0 = INPUT_BUFFER_LEN;
a_table->0 = 15; ! Allow to split input into this many words
#Endif; ! TARGET_
! Print the prompt, and read in the words and dictionary addresses
PrintPrompt();
DrawStatusLine();
KeyboardPrimitive(a_buffer, a_table);
! Set nw to the number of words
#Ifdef TARGET_ZCODE; nw = a_table->1; #Ifnot; nw = a_table-->0; #Endif;
! Conveniently, a_table-->1 is the first word on both the Z-machine and Glulx
w = a_table-->1;
return nw;
}
];
[ SpecialSaveUndo i;
just_undid_flag = 0;
i = VM_Save_Undo();
#ifdef PREVENT_UNDO; undo_flag = 0; #endif;
#ifndef PREVENT_UNDO; undo_flag = 2; #endif;
if (i == -1) undo_flag = 0;
if (i == 0) undo_flag = 1;
! this code gets run immediately after a Restore_Undo
if (i == 2) {
just_undid_flag = 1;
VM_RestoreWindowColours();
VM_Style(SUBHEADER_VMSTY);
SL_Location(); print "^";
! print (name) location, "^";
VM_Style(NORMAL_VMSTY);
IMMEDIATELY_UNDO_RM('E'); new_line;
}
];
-) instead of "Reading the Command" in "Parser.i6t".
to i7_save_undo: (- SpecialSaveUndo(); -).
to decide what number is just_undid: (- just_undid_flag -).
after reading a command:
if the player's command matches "undo":
follow the immediately undo rule;
[if you want to undo for some other reason, it has to be done now, before the save_undo occurs.]
i7_save_undo;
if just_undid is 1: [resuming immediately after an undo]
say "Put your post-UNDO code here.";
[halt further command processing]
rule succeeds;