TOLTECS: - Listing savestates via command line or Launcher

- Loading/Saving during run time
Other savestate functions yet todo.
I'll probably remove the "original" in-game menu and move everything to the GMM.
This commit is contained in:
Benjamin Haisch 2008-11-13 00:16:13 +00:00 committed by Willem Jan Palenstijn
parent 47ae908589
commit 9e78b5d393
5 changed files with 250 additions and 31 deletions

View File

@ -56,7 +56,7 @@ namespace Toltecs {
static const ToltecsGameDescription gameDescriptions[] = {
{
// Toltecs English version
// 3 Skulls of the Toltecs English version
{
"toltecs",
0,
@ -67,8 +67,8 @@ static const ToltecsGameDescription gameDescriptions[] = {
},
},
{
// 3 Skulls of the Toltecs Russian version
{
"toltecs",
0,
@ -115,9 +115,30 @@ public:
return "Toltecs Engine (C) 1996";
}
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
SaveStateList listSaves(const char *target) const;
virtual int getMaximumSaveSlot() const;
void removeSaveState(const char *target, int slot) const;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};
bool ToltecsMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
// (f == kSupportsLoadingDuringStartup) ||
// (f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail);
}
bool Toltecs::ToltecsEngine::hasFeature(EngineFeature f) const {
return
// (f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
bool ToltecsMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
const Toltecs::ToltecsGameDescription *gd = (const Toltecs::ToltecsGameDescription *)desc;
if (gd) {
@ -126,6 +147,100 @@ bool ToltecsMetaEngine::createInstance(OSystem *syst, Engine **engine, const Com
return gd != 0;
}
SaveStateList ToltecsMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Toltecs::ToltecsEngine::SaveHeader header;
Common::String pattern = target;
pattern += ".???";
Common::StringList filenames;
filenames = saveFileMan->listSavefiles(pattern.c_str());
Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 3);
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
if (in) {
if (Toltecs::ToltecsEngine::readSaveHeader(in, false, header) == Toltecs::ToltecsEngine::kRSHENoError) {
saveList.push_back(SaveStateDescriptor(slotNum, header.description));
}
delete in;
}
}
}
return saveList;
}
int ToltecsMetaEngine::getMaximumSaveSlot() const {
return 999;
}
void ToltecsMetaEngine::removeSaveState(const char *target, int slot) const {
// Slot 0 can't be deleted, it's for restarting the game(s)
if (slot == 0)
return;
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::String filename = Toltecs::ToltecsEngine::getSavegameFilename(target, slot);
saveFileMan->removeSavefile(filename.c_str());
Common::StringList filenames;
Common::String pattern = target;
pattern += ".???";
filenames = saveFileMan->listSavefiles(pattern.c_str());
Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 3);
// Rename every slot greater than the deleted slot,
// Also do not rename quicksaves.
if (slotNum > slot && slotNum < 990) {
// FIXME: Our savefile renaming done here is inconsitent with what we do in
// GUI_v2::deleteMenu. While here we rename every slot with a greater equal
// number of the deleted slot to deleted slot, deleted slot + 1 etc.,
// we only rename the following slots in GUI_v2::deleteMenu until a slot
// is missing.
saveFileMan->renameSavefile(file->c_str(), filename.c_str());
filename = Toltecs::ToltecsEngine::getSavegameFilename(target, ++slot);
}
}
}
SaveStateDescriptor ToltecsMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String filename = Toltecs::ToltecsEngine::getSavegameFilename(target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
if (in) {
Toltecs::ToltecsEngine::SaveHeader header;
Toltecs::ToltecsEngine::kReadSaveHeaderError error;
error = Toltecs::ToltecsEngine::readSaveHeader(in, true, header);
delete in;
if (error == Toltecs::ToltecsEngine::kRSHENoError) {
SaveStateDescriptor desc(slot, header.description);
desc.setDeletableFlag(false);
desc.setWriteProtectedFlag(false);
desc.setThumbnail(header.thumbnail);
return desc;
}
}
return SaveStateDescriptor();
}
#if PLUGIN_ENABLED_DYNAMIC(TOLTECS)
REGISTER_PLUGIN_DYNAMIC(TOLTECS, PLUGIN_TYPE_ENGINE, ToltecsMetaEngine);
#else

View File

@ -52,6 +52,8 @@ void MoviePlayer::playMovie(uint resIndex) {
uint32 subtitleSlot;
byte moviePalette[768];
_vm->_isSaveAllowed = false;
memset(moviePalette, 0, sizeof(moviePalette));
_vm->_screen->finishTalkTextItems();
@ -176,6 +178,8 @@ void MoviePlayer::playMovie(uint resIndex) {
debug(0, "playMovie() done");
_vm->_isSaveAllowed = true;
}
void MoviePlayer::fetchAudioChunks() {

View File

@ -30,6 +30,8 @@
#include "base/plugins.h"
#include "base/version.h"
#include "graphics/thumbnail.h"
#include "sound/mixer.h"
#include "toltecs/toltecs.h"
@ -44,14 +46,43 @@ namespace Toltecs {
/* TODO:
- Saveload is working so far but only one slot is supported until the game menu is implemented
- Save with F6; Load with F9
- Save with F7; Load with F9
- Saving during an animation (AnimationPlayer) is not working correctly yet
- Maybe switch to SCUMM/Tinsel serialization approach?
*/
#define SAVEGAME_VERSION 0 // 0 is dev version until in official SVN
void ToltecsEngine::savegame(const char *filename) {
ToltecsEngine::kReadSaveHeaderError ToltecsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
header.version = in->readUint32LE();
if (header.version != SAVEGAME_VERSION)
return kRSHEInvalidVersion;
byte descriptionLen = in->readByte();
header.description = "";
while (descriptionLen--)
header.description += (char)in->readByte();
if (loadThumbnail) {
header.thumbnail = new Graphics::Surface();
assert(header.thumbnail);
if (!Graphics::loadThumbnail(*in, *header.thumbnail)) {
delete header.thumbnail;
header.thumbnail = 0;
}
} else {
Graphics::skipThumbnailHeader(*in);
}
// Not used yet, reserved for future usage
header.gameID = in->readByte();
header.flags = in->readUint32LE();
return (in->ioFailed() ? kRSHEIoError : kRSHENoError);
}
void ToltecsEngine::savegame(const char *filename, const char *description) {
Common::OutSaveFile *out;
if (!(out = g_system->getSavefileManager()->openForSaving(filename))) {
@ -61,6 +92,16 @@ void ToltecsEngine::savegame(const char *filename) {
out->writeUint32LE(SAVEGAME_VERSION);
byte descriptionLen = strlen(description);
out->writeByte(descriptionLen);
out->write(description, descriptionLen);
Graphics::saveThumbnail(*out);
// Not used yet, reserved for future usage
out->writeByte(0);
out->writeUint32LE(0);
out->writeUint16LE(_cameraX);
out->writeUint16LE(_cameraY);
out->writeUint16LE(_cameraHeight);
@ -99,10 +140,14 @@ void ToltecsEngine::loadgame(const char *filename) {
warning("Can't open file '%s', game not loaded", filename);
return;
}
SaveHeader header;
kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
uint32 version = in->readUint32LE();
if (version != SAVEGAME_VERSION) {
warning("Savegame '%s' too old, game not loaded (got v%d, need v%d)", filename, version, SAVEGAME_VERSION);
if (errorCode != kRSHENoError) {
warning("Error loading savegame '%s'", filename);
delete in;
return;
}
@ -145,4 +190,29 @@ void ToltecsEngine::loadgame(const char *filename) {
}
Common::Error ToltecsEngine::loadGameState(int slot) {
const char *fileName = getSavegameFilename(slot);
loadgame(fileName);
}
Common::Error ToltecsEngine::saveGameState(int slot, const char *description) {
const char *fileName = getSavegameFilename(slot);
savegame(fileName, description);
}
const char *ToltecsEngine::getSavegameFilename(int num) {
static Common::String filename;
filename = getSavegameFilename(_targetName, num);
return filename.c_str();
}
Common::String ToltecsEngine::getSavegameFilename(const Common::String &target, int num) {
assert(num >= 0 && num <= 999);
char extension[5];
sprintf(extension, "%03d", num);
return target + "." + extension;
}
} // End of namespace Toltecs

View File

@ -79,16 +79,28 @@ ToltecsEngine::~ToltecsEngine() {
delete _rnd;
}
int ToltecsEngine::init() {
Common::Error ToltecsEngine::init() {
// Initialize backend
_system->beginGFXTransaction();
initCommonGFX(true);
_system->initSize(640, 400);
_system->endGFXTransaction();
return 0;
return Common::kNoError;
}
int ToltecsEngine::go() {
void ToltecsEngine::syncSoundSettings() {
/*
_music->setVolume(ConfMan.getInt("music_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
*/
}
Common::Error ToltecsEngine::go() {
_isSaveAllowed = true;
_quitGame = false;
_counter01 = 0;
@ -140,16 +152,6 @@ int ToltecsEngine::go() {
_system->showMouse(true);
//#define TEST_MOVIE
#ifdef TEST_MOVIE
_screen->registerFont(0, 0x0D);
_screen->registerFont(1, 0x0E);
//_moviePlayer->playMovie(0x000012D8);
//_moviePlayer->playMovie(0x000012D7);
//_moviePlayer->playMovie(0x);
_moviePlayer->playMovie(0x000012E0);
#endif
//#define TEST_MENU
#ifdef TEST_MENU
_screen->registerFont(0, 0x0D);
@ -183,7 +185,7 @@ int ToltecsEngine::go() {
delete _sound;
return 0;
return Common::kNoError;
}
void ToltecsEngine::loadScene(uint resIndex) {
@ -259,7 +261,7 @@ void ToltecsEngine::updateInput() {
// FIXME: This is just for debugging
switch (event.kbd.keycode) {
case Common::KEYCODE_F7:
savegame("toltecs.001");
savegame("toltecs.001", "Quicksave");
break;
case Common::KEYCODE_F9:
loadgame("toltecs.001");

View File

@ -43,10 +43,6 @@
namespace Toltecs {
enum ToltecsGameFeatures {
GF_PACKED = (1 << 0)
};
struct ToltecsGameDescription;
class AnimationPlayer;
@ -65,14 +61,17 @@ class ToltecsEngine : public ::Engine {
Common::KeyState _keyPressed;
protected:
int init();
int go();
Common::Error init();
Common::Error go();
// void shutdown();
public:
ToltecsEngine(OSystem *syst, const ToltecsGameDescription *gameDesc);
virtual ~ToltecsEngine();
virtual bool hasFeature(EngineFeature f) const;
virtual void syncSoundSettings();
Common::RandomSource *_rnd;
const ToltecsGameDescription *_gameDescription;
uint32 getFeatures() const;
@ -99,10 +98,8 @@ public:
int16 findRectAtPoint(byte *rectData, int16 x, int16 y, int16 index, int16 itemSize);
void savegame(const char *filename);
void loadgame(const char *filename);
public:
AnimationPlayer *_anim;
ArchiveReader *_arc;
Input *_input;
@ -140,6 +137,37 @@ public:
int16 _mouseDisabled;
bool _leftButtonDown, _rightButtonDown;
/* Save/load */
enum kReadSaveHeaderError {
kRSHENoError = 0,
kRSHEInvalidType = 1,
kRSHEInvalidVersion = 2,
kRSHEIoError = 3
};
struct SaveHeader {
Common::String description;
uint32 version;
byte gameID;
uint32 flags;
Graphics::Surface *thumbnail;
};
bool _isSaveAllowed;
bool canLoadGameStateCurrently() { return _isSaveAllowed; }
bool canSaveGameStateCurrently() { return _isSaveAllowed; }
Common::Error loadGameState(int slot);
Common::Error saveGameState(int slot, const char *description);
void savegame(const char *filename, const char *description);
void loadgame(const char *filename);
const char *getSavegameFilename(int num);
static Common::String getSavegameFilename(const Common::String &target, int num);
static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
};
} // End of namespace Toltecs