STARK: Implement the save & load menu #1422
Conversation
cb1dc6b
to
5559fee
Compare
@@ -336,7 +336,8 @@ Common::Error StarkEngine::loadGameState(int slot) { | |||
|
|||
bool StarkEngine::canSaveGameStateCurrently() { | |||
// Disallow saving when there is no level loaded or when a script is running | |||
return _global->getLevel() && _userInterface->isInteractive(); | |||
// or when the save & load menu is currently displayed | |||
return _global->getLevel() && _userInterface->isInteractive() && !_userInterface->isInSaveLoadMenuScreen(); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used to try an implementation that allows saving through GMM while the save & load menu is displayed, but it is kind of complex since the menu needs to be notified when a save slot is updated and update the thumbnail of the corresponding widget. Maybe just disable the saving is a better approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disabling saving from the GMM when in the saveload menu to avoid too much complication sounds good to me.
@@ -113,7 +131,16 @@ void SaveMenuScreen::open() { | |||
} | |||
|
|||
void SaveMenuScreen::onSlotSelected(int slot) { | |||
g_engine->saveGameState(slot, "TestSave"); | |||
int chapter = StarkGlobal->getCurrentChapter(); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the returned value of getCurrentChapter()
really mean? I thought it was the index of the chapter, but calling this function in Chapter 1 gives me value 10
.
_textDesc(gfx), | ||
_textTime(gfx), | ||
_isMouseHovered(false) { | ||
// Load the corresponding save slot data | ||
Common::String filename = StarkEngine::formatSaveName(ConfMan.getActiveDomainName().c_str(), _slot); | ||
Common::InSaveFile *save = g_system->getSavefileManager()->openForLoading(filename); | ||
if (save) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like putting a delete save;
at the end is needed, but it will crash the game. The StarkEngine::loadGameState()
also doesn't delete the save
, why is that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructor for StateReadStream() is two arguments, the file and a flag (DisposeAfterUse::YES and DisposeAfterUse::NO) the flag indicates if the input file should be deleted or not after use.
In your case you used it with 1 argument which looks like that defaults to the 2 argument case with the flag set to dispose. I am not exactly sure where that is happening since the constructor to SubReadStream defaults the dispose to NO (see common/substeam.h). StateReadStream is a SeekableSubReadStream which is also a SubReadStream.
So you don't need to delete save since that is already being done by the destructor of StateReadStream, but just to be clear you may want to explicitly set the 2nd argument to be DisposeAfterUse::YES in the constructor of StateReadStream.
Alternately, you can set it to NO and delete the save manually.
Beware |
Hi, Please increment the save version number and load the seconds for saves that have at least the new version number. This way old saves remain compatible.
|
metadata.saveHour, metadata.saveMinute, metadata.saveSecond, | ||
metadata.saveMonth, metadata.saveDay, metadata.saveYear % 100)); | ||
_textTime.setColor(_textColor); | ||
_textTime.setFont(FontProvider::FontType::kCustomFont, 3); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you want FontProvider::kCustomFont instead of FontProvider::FontType::kCustomFont.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the returned value of getCurrentChapter() really mean? I thought it was the index of the chapter, but calling this function in Chapter 1 gives me value 10.
It's more a progress marker than exactly the chapter number. To obtain the actual chapter number, you need to divide that value by 10.
@@ -336,7 +336,8 @@ Common::Error StarkEngine::loadGameState(int slot) { | |||
|
|||
bool StarkEngine::canSaveGameStateCurrently() { | |||
// Disallow saving when there is no level loaded or when a script is running | |||
return _global->getLevel() && _userInterface->isInteractive(); | |||
// or when the save & load menu is currently displayed | |||
return _global->getLevel() && _userInterface->isInteractive() && !_userInterface->isInSaveLoadMenuScreen(); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disabling saving from the GMM when in the saveload menu to avoid too much complication sounds good to me.
if (chapter == 0) { | ||
desc = "Prologue"; | ||
} else { | ||
desc = Common::String::format("Chapter %d", chapter); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ultimately, chapter names will have to come from chapters.ini
so they are localized. But I guess having them hardcoded is fine for the first version. The original engine uses the string before the colon in chapters.ini
.
// Obtain the thumbnail | ||
Graphics::Surface *thumb = metadata.readGameScreenThumbnail(&stream); | ||
_texture->update(thumb); | ||
delete thumb; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Graphics::Surface
is very stupid. ->free()
needs to be called as well.
@bgK Currently So, is it okay to just block both saving and loading from GMM when the game is in save & load menu? p.s. Currently, the saving is already blocked. Deleting a save data through GMM while the load menu is displayed will make the corresponding widget, if it's on the current page, unresponsive. |
A new service for retrieving the chapter title and subtitle from |
Sure, ok. |
|
||
Common::String line, title, subtitle; | ||
|
||
// Assume that the formats of all chapters.ini are the same |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you notice Common::INIFile
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, didn't see that. I'll take a look.
The current mechanism of capturing the screenshot will also capture the cursor. I have spent some time trying to get rid of it, but the best I could get will also remove the model from the thumbnail. Any suggestion? |
A simple way would be to re-render the game window only just before capturing the screenshot. (And maybe re-render the whole screen afterwards if that causes glitches) |
Already tried this before. Simply re-render the game window (or even the game screen) will cause only the background rendered, without the models. Calling Still can't figure out what causes this. |
Oh, right. The depth buffer needs to be cleared for the depths tests to work correctly. Calling |
} | ||
|
||
// Obtain the thumbnail | ||
Graphics::Surface *thumb = metadata.readGameScreenThumbnail(&stream); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thumbnail is only available since save metadata version 9. Most of my saves are older than that and show garbage instead of the thumbnail.
// Freeze the screen for a while to let the user notice the change | ||
widget->loadSaveDataElements(); | ||
render(); | ||
g_system->updateScreen(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use GfxDriver->flipBuffer()
instead not to break the Driver abstraction.
lineSurface.free(); | ||
|
||
// Set the position | ||
_thumbPos.x = 41 + (_slot % 3) * (_thumbWidth + 39); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There could be constants for the number of slots per lines, the number of slot lines and the number of slots per page to make the code easier to understand.
} | ||
|
||
void SaveLoadMenuScreen::changePage(int page) { | ||
assert(page >= 0 && page <= 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a constant for the maximum number of pages. We may want to increase that number as the ResidualVM save and load dialogs have a lot more slots.
@@ -94,7 +94,7 @@ void DiaryIndexScreen::open() { | |||
_widgets.push_back(new StaticLocationWidget( | |||
"Back", | |||
CLICK_HANDLER(DiaryIndexScreen, backHandler), | |||
MOVE_HANDLER(DiaryIndexScreen, widgetTextColorHandler))); | |||
nullptr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just found out that this text will not change to blue in the original game.
_texture->update(thumb); | ||
thumb->free(); | ||
delete thumb; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have save data older than version 9. Could you please check this code for me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's working, thanks!
This is my collection of old saved games in case you need it: https://filenurse.com/download/361b5da097c32696eff053a7b026ad7b.html
A lot of them were made back when some entity save handlers were missing, so they don't load all the state, but oh well...
This PR is corresponding to implement the save & load menu of The Longest Journey.