Community
SCI Programming => SCI Syntax Help => Topic started by: Doan Sephim on March 26, 2024, 08:42:47 AM
-
I'm trying to add a "Retry" button on the death dialog that will automatically restore the most recent save.
Here's what I have tried to no effect:
(repeat
(= mbResult
(Print
{Remember:\nsave early, save often!}
#title
{Words to the wise:}
#font
gDeadFont
#button
{Restore}
1
#button
{Retry}
2
#button
{Restart}
3
#button
{__Quit__}
4
)
)
(switch mbResult
(1
(if (!= (gGame restore:) -1) (return))
)
(2
(gCast eachElementDo: #dispose)
(gCast eachElementDo: #delete)
(RestoreGame objectName 0 gVersion)
(return)
)
(3 (gGame restart:) (return))
(4 (= gQuitGame TRUE) (return))
)
)I simply added a new button called retry, and when it is clicked I copy/pasted some code from the restore method in the game script, but I am clearly missing something. Here is the code from the game script. I'm a bit out of my element when it comes to deciphering the base code, so any help would be appreciated.
(method (restore &tmp gameNum oldCursor hSound)
(= gameNum -1)
(Load rsFONT gSaveRestoreFont)
(Load rsCURSOR gNormalCursor)
(Load rsCURSOR gLoadingCursor)
(= oldCursor (self setCursor: gNormalCursor))
(= hSound (Sound pause: 1))
(if (GetSaveDisk TRUE)
(if gPrintDlg (gPrintDlg dispose:))
(= gameNum (Restore doit: &rest))
(if (!= gameNum -1)
(self setCursor: gLoadingCursor)
(if (CheckSaveGame objectName gameNum gVersion)
(gCast eachElementDo: #dispose)
(gCast eachElementDo: #delete)
(RestoreGame objectName gameNum gVersion)
else
(Print
{That game was saved under a different interpreter. It cannot be restored.}
#font
0
#button
{OK}
1
)
(self setCursor: oldCursor (HaveMouse))
(= gameNum -1)
)
)
(GetSaveDisk FALSE)
)
(Sound pause: hSound)
(return gameNum)
)
-
First thing that comes to mind, are both these things part of the same object?
-
The restore method is part of the "game" object. But whenever I call it using (gGame restore:) it shoots up the restore window.
I am attempting to use (RestoreGame) which I don't exactly know where that's defined, but I am trying to call it in the dying script
-
It is worth noting that RestoreGame can fail. Try inserting some Print statements (both before and after RestoreGame) to see if the code gets called at all and to catch any errors from RestoreGame.
-
I know where restore is from. The question is, where is your dialog handler?
Also, lskovlun is right and you should maybe include the surrounding CheckSaveGame call.
(Feel free to skip this next part if you already know this stuff.)
As you know, the saved games are stored with a file name that includes the name of the Game object. Not the class, the object instance, so KQ4 of Game saves to KQ4SG.002. Though restore is defined in class Game, it's instance KQ4 that's calling it, so it uses "KQ4" to name the files. If the objectName I see here in these two separate code blocks is from two separate objects... it'll try to restore from DEADSG.002 or whatever, if for example that dialog box with the options is handled by an object named Dead.
-
Maybe try setting a flag for "retry", call restore and them modify the restore method like this:
(method (restore &tmp gameNum oldCursor hSound)
(= gameNum -1)
(Load rsFONT gSaveRestoreFont)
(Load rsCURSOR gNormalCursor)
(Load rsCURSOR gLoadingCursor)
(= oldCursor (self setCursor: gNormalCursor))
(= hSound (Sound pause: 1))
(if (GetSaveDisk TRUE)
(if gPrintDlg (gPrintDlg dispose:))
; handle retry
(if (btst fRetryFlag)
(= gameNum 0)
(bclr fRetryFlag)
else
(= gameNum (Restore doit: &rest))
)
; end handle retry
(if (!= gameNum -1)
(self setCursor: gLoadingCursor)
(if (CheckSaveGame objectName gameNum gVersion)
(gCast eachElementDo: #dispose)
(gCast eachElementDo: #delete)
(RestoreGame objectName gameNum gVersion)
else
(Print
{That game was saved under a different interpreter. It cannot be restored.}
#font
0
#button
{OK}
1
)
(self setCursor: oldCursor (HaveMouse))
(= gameNum -1)
)
)
(GetSaveDisk FALSE)
)
(Sound pause: hSound)
(return gameNum)
)
The problem is how do you know game 0 is the most recent save?
-
It is worth noting that RestoreGame can fail. Try inserting some Print statements (both before and after RestoreGame) to see if the code gets called at all and to catch any errors from RestoreGame.
I would do that, but I'm not sure where it is defined. I searched for it, but didn't find. I will keep looking.
-
The problem is how do you know game 0 is the most recent save?
Ohohohohohohohoh yeeesss X3
-
The problem is how do you know game 0 is the most recent save?
Ohohohohohohohoh yeeesss X3
That's fair, but I used shorthand. I have an autosave feature that always uses the "0" slot for its save. It autosaves at the beginning of each room. The player could of course choose to save over it, but they would still be in the same room they died, so that is the game I would call.
I will definitely look through this as many people have given info for me to consider!
-
Maybe try setting a flag for "retry", call restore and them modify the restore method like this:
(method (restore &tmp gameNum oldCursor hSound)
(= gameNum -1)
(Load rsFONT gSaveRestoreFont)
(Load rsCURSOR gNormalCursor)
(Load rsCURSOR gLoadingCursor)
(= oldCursor (self setCursor: gNormalCursor))
(= hSound (Sound pause: 1))
(if (GetSaveDisk TRUE)
(if gPrintDlg (gPrintDlg dispose:))
; handle retry
(if (btst fRetryFlag)
(= gameNum 0)
(bclr fRetryFlag)
else
(= gameNum (Restore doit: &rest))
)
; end handle retry
(if (!= gameNum -1)
(self setCursor: gLoadingCursor)
(if (CheckSaveGame objectName gameNum gVersion)
(gCast eachElementDo: #dispose)
(gCast eachElementDo: #delete)
(RestoreGame objectName gameNum gVersion)
else
(Print
{That game was saved under a different interpreter. It cannot be restored.}
#font
0
#button
{OK}
1
)
(self setCursor: oldCursor (HaveMouse))
(= gameNum -1)
)
)
(GetSaveDisk FALSE)
)
(Sound pause: hSound)
(return gameNum)
)
The problem is how do you know game 0 is the most recent save?
Seems to have worked simply and easily. Will have to play around a little bit to make sure there are no issues, but seems like a very easy solution. Plus, there should always be a "0" save slot since the autosave triggers at the beginning of each room, so there should be no calling on a non-existent save.
-
I had a similar issue with another SCI0 project where ScummVM just ignores SAVE/LOAD commands if they aren't coming from the scripts it expects. I never bothered looking at the scummvm source code, but I worked around it in the same way using flags. Just an heads up for anyone else who might encounter this oddity.
-
Yeah. Lots of odd code to make saving/loading (of SCI32 games in particular - and Phantas1 especially) work. I'm not surprised.
-
It is possible to know which savegame is the most recent one, by the way. The last time saving came up (https://sciprogramming.com/community/index.php?topic=1902.0), I wrote some code:
(procedure (ShowIndices &tmp [slots 20] [names 400])
(GetSaveFiles (gGame name?) @names @slots)
; (SetDebug)
(FormatPrint "%02d %02d %02d %02d %02d\n%02d %02d %02d %02d %02d\n%02d %02d %02d %02d %02d\n%02d %02d %02d %02d %02d"
[slots 0]
[slots 1]
[slots 2]
[slots 3]
[slots 4]
[slots 5]
[slots 6]
[slots 7]
[slots 8]
[slots 9]
[slots 10]
[slots 11]
[slots 12]
[slots 13]
[slots 14]
[slots 15]
[slots 16]
[slots 17]
[slots 18]
[slots 19])
)
The first entry in the slots array tells you the index of the most recent savegame (the one that appears at the top of the restore dialog).
-
@Iskovlun kudos on that bug fix in the thread you linked
-
I had a similar issue with another SCI0 project where ScummVM just ignores SAVE/LOAD commands if they aren't coming from the scripts it expects. I never bothered looking at the scummvm source code, but I worked around it in the same way using flags. Just an heads up for anyone else who might encounter this oddity.
Would this still be the case if you enabled the "use original save/load dialogs" checkbox in engine options for the game?
-
I thought that the automatic save function in QfG4 worked well. You could ignore it if you wanted, but if tou forgot to save before a potentially dangerous scene you would still have a save from just right before you commited to the danger. to try again, but you would still have all of your normal saves to revisit different parts of the game or simply wanted to try a different path in the game.
-
The ScummVM save/load code is so full of odd cases that it's hard to say what goes wrong without actually trying it in the debugger.