parent
5c30b3c8df
commit
cc08602770
5 changed files with 247 additions and 2 deletions
|
@ -21,6 +21,7 @@
|
|||
#include "common/stdafx.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "common/scaler.h"
|
||||
|
||||
|
@ -193,6 +194,8 @@ const Common::String ScummDialog::queryResString(int stringno) {
|
|||
|
||||
#pragma mark -
|
||||
|
||||
Common::StringList generateSavegameList(ScummEngine *scumm, bool saveMode);
|
||||
|
||||
enum {
|
||||
kSaveCmd = 'SAVE',
|
||||
kLoadCmd = 'LOAD',
|
||||
|
@ -271,6 +274,9 @@ protected:
|
|||
GUI::ListWidget *_list;
|
||||
GUI::ButtonWidget *_chooseButton;
|
||||
GUI::GraphicsWidget *_gfxWidget;
|
||||
GUI::StaticTextWidget *_date;
|
||||
GUI::StaticTextWidget *_time;
|
||||
GUI::StaticTextWidget *_playtime;
|
||||
ScummEngine *_scumm;
|
||||
|
||||
public:
|
||||
|
@ -300,6 +306,39 @@ SaveLoadChooserEx::SaveLoadChooserEx(const String &title, const String &buttonLa
|
|||
((_scumm->_system->getHeight() % 200 && _scumm->_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1) + 8);
|
||||
_gfxWidget->setFlags(GUI::WIDGET_BORDER);
|
||||
|
||||
int height = 18 + ((_scumm->_system->getHeight() % 200 && _scumm->_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1) + 8;
|
||||
|
||||
_date = new StaticTextWidget(this,
|
||||
_w - (kThumbnailWidth + 22),
|
||||
height,
|
||||
kThumbnailWidth + 8,
|
||||
kLineHeight,
|
||||
"No date saved",
|
||||
kTextAlignCenter);
|
||||
_date->setFlags(GUI::WIDGET_CLEARBG);
|
||||
|
||||
height += kLineHeight;
|
||||
|
||||
_time = new StaticTextWidget(this,
|
||||
_w - (kThumbnailWidth + 22),
|
||||
height,
|
||||
kThumbnailWidth + 8,
|
||||
kLineHeight,
|
||||
"No time saved",
|
||||
kTextAlignCenter);
|
||||
_time->setFlags(GUI::WIDGET_CLEARBG);
|
||||
|
||||
height += kLineHeight;
|
||||
|
||||
_playtime = new StaticTextWidget(this,
|
||||
_w - (kThumbnailWidth + 22),
|
||||
height,
|
||||
kThumbnailWidth + 8,
|
||||
kLineHeight,
|
||||
"No playtime saved",
|
||||
kTextAlignCenter);
|
||||
_playtime->setFlags(GUI::WIDGET_CLEARBG);
|
||||
|
||||
// Buttons
|
||||
addButton(this, _w - 2 * (kBigButtonWidth + 10), _h - kBigButtonHeight - 8, "Cancel", kCloseCmd, 0, GUI::kBigWidgetSize);
|
||||
_chooseButton = addButton(this, _w - (kBigButtonWidth + 10), _h - kBigButtonHeight - 8, buttonLabel, kChooseCmd, 0, GUI::kBigWidgetSize);
|
||||
|
@ -342,9 +381,48 @@ void SaveLoadChooserEx::handleCommand(CommandSender *sender, uint32 cmd, uint32
|
|||
Graphics::Surface *thumb;
|
||||
thumb = _scumm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
|
||||
_gfxWidget->setGfx(thumb);
|
||||
if (thumb)
|
||||
thumb->free();
|
||||
delete thumb;
|
||||
_gfxWidget->draw();
|
||||
|
||||
InfoStuff infos;
|
||||
memset(&infos, 0, sizeof(InfoStuff));
|
||||
char buffer[32];
|
||||
if (_scumm->loadInfosFromSlot(_saveMode ? selItem + 1 : selItem, &infos)) {
|
||||
snprintf(buffer, 32, "Date: %.2d.%.2d.%.4d",
|
||||
(infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF,
|
||||
infos.date & 0xFFFF);
|
||||
_date->setLabel(buffer);
|
||||
_date->draw();
|
||||
|
||||
snprintf(buffer, 32, "Time: %.2d:%.2d",
|
||||
(infos.time >> 8) & 0xFF, infos.time & 0xFF);
|
||||
_time->setLabel(buffer);
|
||||
_time->draw();
|
||||
|
||||
int minutes = infos.playtime / 60;
|
||||
int hours = minutes / 60;
|
||||
minutes %= 60;
|
||||
|
||||
snprintf(buffer, 32, "Playtime: %.2d:%.2d",
|
||||
hours & 0xFF, minutes & 0xFF);
|
||||
_playtime->setLabel(buffer);
|
||||
_playtime->draw();
|
||||
} else {
|
||||
snprintf(buffer, 32, "No date saved");
|
||||
_date->setLabel(buffer);
|
||||
_date->draw();
|
||||
|
||||
snprintf(buffer, 32, "No time saved");
|
||||
_time->setLabel(buffer);
|
||||
_time->draw();
|
||||
|
||||
snprintf(buffer, 32, "No playtime saved");
|
||||
_playtime->setLabel(buffer);
|
||||
_playtime->draw();
|
||||
}
|
||||
|
||||
if (_saveMode) {
|
||||
_list->startEditMode();
|
||||
}
|
||||
|
|
|
@ -51,6 +51,24 @@ struct SaveGameHeader {
|
|||
char name[32];
|
||||
};
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
#pragma START_PACK_STRUCTS
|
||||
#endif
|
||||
|
||||
struct SaveInfoSection {
|
||||
uint32 type;
|
||||
uint32 version;
|
||||
uint32 size;
|
||||
|
||||
uint32 timeTValue;
|
||||
uint32 playtime;
|
||||
} GCC_PACK;
|
||||
|
||||
#if !defined(__GNUC__)
|
||||
#pragma END_PACK_STRUCTS
|
||||
#endif
|
||||
|
||||
#define INFOSECTION_VERSION 1
|
||||
|
||||
void ScummEngine::requestSave(int slot, const char *name, bool temporary) {
|
||||
_saveLoadSlot = slot;
|
||||
|
@ -84,6 +102,7 @@ bool ScummEngine::saveState(int slot, bool compat) {
|
|||
|
||||
out->write(&hdr, sizeof(hdr));
|
||||
saveThumbnail(out);
|
||||
saveInfos(out);
|
||||
|
||||
Serializer ser(0, out, CURRENT_VER);
|
||||
saveOrLoad(&ser, CURRENT_VER);
|
||||
|
@ -144,6 +163,23 @@ bool ScummEngine::loadState(int slot, bool compat) {
|
|||
in->skip(size - 8);
|
||||
}
|
||||
|
||||
// Since version 56 we have informations about the creation of the save game and the save time here
|
||||
if (hdr.ver >= VER(56)) {
|
||||
InfoStuff infos;
|
||||
if (!loadInfos(in, &infos)) {
|
||||
warning("Info section could not be found");
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
|
||||
_engineStartTime = _system->getMillis() / 1000 - infos.playtime;
|
||||
} else {
|
||||
// start time counting
|
||||
_engineStartTime = _system->getMillis() / 1000;
|
||||
}
|
||||
|
||||
_dialogStartTime = _system->getMillis() / 1000;
|
||||
|
||||
// Due to a bug in scummvm up to and including 0.3.0, save games could be saved
|
||||
// in the V8/V9 format but were tagged with a V7 mark. Ouch. So we just pretend V7 == V8 here
|
||||
if (hdr.ver == VER(7))
|
||||
|
@ -359,6 +395,9 @@ bool ScummEngine::loadState(int slot, bool compat) {
|
|||
|
||||
_sound->pauseSounds(false);
|
||||
|
||||
_engineStartTime += _system->getMillis() / 1000 - _dialogStartTime;
|
||||
_dialogStartTime = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -440,6 +479,115 @@ Graphics::Surface *ScummEngine::loadThumbnailFromSlot(int slot) {
|
|||
return thumb;
|
||||
}
|
||||
|
||||
bool ScummEngine::loadInfosFromSlot(int slot, InfoStuff *stuff) {
|
||||
char filename[256];
|
||||
Common::InSaveFile *in;
|
||||
SaveGameHeader hdr;
|
||||
int len;
|
||||
|
||||
makeSavegameName(filename, slot, false);
|
||||
if (!(in = _saveFileMan->openForLoading(filename))) {
|
||||
return false;
|
||||
}
|
||||
len = in->read(&hdr, sizeof(hdr));
|
||||
|
||||
if (len != sizeof(hdr) || hdr.type != MKID('SCVM')) {
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hdr.ver > CURRENT_VER)
|
||||
hdr.ver = TO_LE_32(hdr.ver);
|
||||
if (hdr.ver < VER(56)) {
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 type;
|
||||
in->read(&type, 4);
|
||||
|
||||
// Check for the THMB header. Also, work around a bug which caused
|
||||
// the chunk type (incorrectly) to be written in LE on LE machines.
|
||||
if (! (type == MKID('THMB') || (hdr.ver < VER(55) && type == MKID('BMHT')))){
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
uint32 size = in->readUint32BE();
|
||||
in->skip(size - 8);
|
||||
|
||||
if (!loadInfos(in, stuff)) {
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete in;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScummEngine::loadInfos(Common::InSaveFile *file, InfoStuff *stuff) {
|
||||
memset(stuff, 0, sizeof(InfoStuff));
|
||||
|
||||
SaveInfoSection section;
|
||||
file->read(§ion.type, 4);
|
||||
if (section.type != MKID('INFO')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
section.version = file->readUint32BE();
|
||||
section.size = file->readUint32BE();
|
||||
|
||||
// if we extend this we should add a table for the special sizes at the versions to check it
|
||||
if (section.version == INFOSECTION_VERSION && section.size != sizeof(SaveInfoSection)) {
|
||||
warning("Info section is corrupt");
|
||||
file->skip(section.size);
|
||||
return false;
|
||||
}
|
||||
|
||||
section.timeTValue = file->readUint32BE();
|
||||
section.playtime = file->readUint32BE();
|
||||
|
||||
time_t curTime_ = section.timeTValue;
|
||||
tm *curTime = localtime(&curTime_);
|
||||
stuff->date = (curTime->tm_mday & 0xFF) << 24 | ((curTime->tm_mon + 1) & 0xFF) << 16 | (curTime->tm_year + 1900) & 0xFFFF;
|
||||
stuff->time = (curTime->tm_hour & 0xFF) << 8 | (curTime->tm_min) & 0xFF;
|
||||
stuff->playtime = section.playtime;
|
||||
|
||||
// if we extend the header we should check here for the version
|
||||
// e.g.:
|
||||
// if (header.version == 2) {
|
||||
// // load some things here
|
||||
// }
|
||||
//
|
||||
// if (header.version == 3) {
|
||||
// // ...
|
||||
// }
|
||||
// and so on...
|
||||
|
||||
// skip all newer features, this could make problems if some older version uses more space for
|
||||
// saving informations, but this should NOT happen
|
||||
if (section.size > sizeof(SaveInfoSection)) {
|
||||
file->skip(section.size - sizeof(SaveInfoSection));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScummEngine::saveInfos(Common::OutSaveFile* file) {
|
||||
SaveInfoSection section;
|
||||
section.type = MKID('INFO');
|
||||
section.version = INFOSECTION_VERSION;
|
||||
section.size = sizeof(SaveInfoSection);
|
||||
|
||||
section.timeTValue = time(0);
|
||||
section.playtime = _system->getMillis() / 1000 - _engineStartTime;
|
||||
|
||||
file->write(§ion.type, 4);
|
||||
file->writeUint32BE(section.version);
|
||||
file->writeUint32BE(section.size);
|
||||
file->writeUint32BE(section.timeTValue);
|
||||
file->writeUint32BE(section.playtime);
|
||||
}
|
||||
|
||||
void ScummEngine::saveOrLoad(Serializer *s, uint32 savegameVersion) {
|
||||
const SaveLoadEntry objectEntries[] = {
|
||||
MKLINE(ObjectData, OBIMoffset, sleUint32, VER(8)),
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Scumm {
|
|||
* only saves/loads those which are valid for the version of the savegame
|
||||
* which is being loaded/saved currently.
|
||||
*/
|
||||
#define CURRENT_VER 55
|
||||
#define CURRENT_VER 56
|
||||
|
||||
/**
|
||||
* An auxillary macro, used to specify savegame versions. We use this instead
|
||||
|
|
|
@ -2109,6 +2109,8 @@ void ScummEngine::setupVolumes() {
|
|||
#pragma mark -
|
||||
|
||||
int ScummEngine::go() {
|
||||
_engineStartTime = _system->getMillis() / 1000;
|
||||
|
||||
// If requested, load a save game instead of running the boot script
|
||||
if (_saveLoadFlag != 2 || !loadState(_saveLoadSlot, _saveTemporaryState)) {
|
||||
int args[16];
|
||||
|
@ -2550,6 +2552,8 @@ void ScummEngine::startManiac() {
|
|||
#pragma mark -
|
||||
|
||||
int ScummEngine::runDialog(Dialog &dialog) {
|
||||
_dialogStartTime = _system->getMillis() / 1000;
|
||||
|
||||
// Pause sound & video
|
||||
bool old_soundsPaused = _sound->_soundsPaused;
|
||||
_sound->pauseSounds(true);
|
||||
|
@ -2566,6 +2570,9 @@ int ScummEngine::runDialog(Dialog &dialog) {
|
|||
_sound->pauseSounds(old_soundsPaused);
|
||||
_smushPaused = oldSmushPaused;
|
||||
|
||||
_engineStartTime += (_system->getMillis() / 1000) - _dialogStartTime;
|
||||
_dialogStartTime = 0;
|
||||
|
||||
// Return the result
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -309,6 +309,12 @@ struct AuxEntry {
|
|||
int subIndex;
|
||||
};
|
||||
|
||||
struct InfoStuff {
|
||||
uint32 date;
|
||||
uint16 time;
|
||||
uint32 playtime;
|
||||
};
|
||||
|
||||
class ResourceManager {
|
||||
friend class ScummDebugger;
|
||||
friend class ScummEngine;
|
||||
|
@ -583,13 +589,19 @@ public:
|
|||
void requestSave(int slot, const char *name, bool temporary = false);
|
||||
void requestLoad(int slot);
|
||||
|
||||
// thumbnail stuff
|
||||
// thumbnail + info stuff
|
||||
public:
|
||||
Graphics::Surface *loadThumbnailFromSlot(int slot);
|
||||
bool loadInfosFromSlot(int slot, InfoStuff *stuff);
|
||||
|
||||
protected:
|
||||
Graphics::Surface *loadThumbnail(Common::InSaveFile *file);
|
||||
bool loadInfos(Common::InSaveFile *file, InfoStuff *stuff);
|
||||
void saveThumbnail(Common::OutSaveFile *file);
|
||||
void saveInfos(Common::OutSaveFile* file);
|
||||
|
||||
int32 _engineStartTime;
|
||||
int32 _dialogStartTime;
|
||||
|
||||
protected:
|
||||
/* Script VM - should be in Script class */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue