STARTREK: Preliminary saving/loading
This commit is contained in:
parent
c17bef8285
commit
84a30e4dce
15 changed files with 639 additions and 34 deletions
370
engines/startrek/saveload.cpp
Normal file
370
engines/startrek/saveload.cpp
Normal file
|
@ -0,0 +1,370 @@
|
|||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/saveload.h"
|
||||
|
||||
#include "graphics/thumbnail.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "startrek/startrek.h"
|
||||
|
||||
namespace StarTrek {
|
||||
|
||||
bool StarTrekEngine::showSaveMenu() {
|
||||
GUI::SaveLoadChooser *dialog;
|
||||
Common::String desc;
|
||||
int slot;
|
||||
|
||||
dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
|
||||
|
||||
slot = dialog->runModalWithCurrentTarget();
|
||||
desc = dialog->getResultString();
|
||||
|
||||
if (desc.empty()) {
|
||||
// create our own description for the saved game, the user didnt enter it
|
||||
desc = dialog->createDefaultSaveDescription(slot);
|
||||
}
|
||||
|
||||
if (desc.size() > 28)
|
||||
desc = Common::String(desc.c_str(), 28);
|
||||
|
||||
/*
|
||||
dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
|
||||
slot = dialog->runModalWithCurrentTarget();
|
||||
*/
|
||||
|
||||
delete dialog;
|
||||
|
||||
if (slot < 0)
|
||||
return true;
|
||||
|
||||
return saveGame(slot, desc);
|
||||
}
|
||||
|
||||
bool StarTrekEngine::showLoadMenu() {
|
||||
GUI::SaveLoadChooser *dialog;
|
||||
int slot;
|
||||
|
||||
dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
|
||||
slot = dialog->runModalWithCurrentTarget();
|
||||
|
||||
delete dialog;
|
||||
|
||||
if (slot < 0)
|
||||
return true;
|
||||
|
||||
return loadGame(slot);
|
||||
}
|
||||
|
||||
const uint32 CURRENT_SAVEGAME_VERSION = 0;
|
||||
|
||||
bool StarTrekEngine::saveGame(int slot, Common::String desc) {
|
||||
Common::String filename = getSavegameFilename(slot);
|
||||
Common::OutSaveFile *out;
|
||||
|
||||
if (!(out = _saveFileMan->openForSaving(filename))) {
|
||||
warning("Can't create file '%s', game not saved", filename.c_str());
|
||||
return false;
|
||||
} else {
|
||||
debug(3, "Successfully opened %s for writing", filename.c_str());
|
||||
}
|
||||
|
||||
SavegameMetadata meta;
|
||||
meta.version = CURRENT_SAVEGAME_VERSION;
|
||||
memset(meta.description, 0, sizeof(meta.description));
|
||||
strncpy(meta.description, desc.c_str(), SAVEGAME_DESCRIPTION_LEN);
|
||||
|
||||
TimeDate curTime;
|
||||
_system->getTimeAndDate(curTime);
|
||||
meta.setSaveTimeAndDate(curTime);
|
||||
meta.playTime = g_engine->getTotalPlayTime();
|
||||
|
||||
if (!saveOrLoadMetadata(nullptr, out, &meta)) {
|
||||
delete out;
|
||||
return false;
|
||||
}
|
||||
if (!saveOrLoadGameData(nullptr, out, &meta)) {
|
||||
delete out;
|
||||
return false;
|
||||
}
|
||||
|
||||
out->finalize();
|
||||
delete out;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StarTrekEngine::loadGame(int slot) {
|
||||
Common::String filename = getSavegameFilename(slot);
|
||||
Common::InSaveFile *in;
|
||||
|
||||
if (!(in = _saveFileMan->openForLoading(filename))) {
|
||||
warning("Can't open file '%s', game not loaded", filename.c_str());
|
||||
return false;
|
||||
} else {
|
||||
debug(3, "Successfully opened %s for loading", filename.c_str());
|
||||
}
|
||||
|
||||
SavegameMetadata meta;
|
||||
if (!saveOrLoadMetadata(in, nullptr, &meta)) {
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (meta.version > CURRENT_SAVEGAME_VERSION) {
|
||||
delete in;
|
||||
error("Savegame version (%d) is newer than current version (%d). A newer version of ScummVM is needed", meta.version, CURRENT_SAVEGAME_VERSION);
|
||||
}
|
||||
|
||||
if (!saveOrLoadGameData(in, nullptr, &meta)) {
|
||||
delete in;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete in;
|
||||
|
||||
_lastGameMode = _gameMode;
|
||||
|
||||
if (_gameMode == GAMEMODE_AWAYMISSION) {
|
||||
for (int i = 0; i < NUM_ACTORS; i++) {
|
||||
Actor *a = &_actorList[i];
|
||||
if (a->spriteDrawn) {
|
||||
if (a->animType != 1)
|
||||
a->animFile = loadFile(Common::String(a->animFilename) + ".anm");
|
||||
_gfx->addSprite(&a->sprite);
|
||||
a->sprite.setBitmap(loadAnimationFrame(a->bitmapFilename, a->scale));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_gameMode == -1) {
|
||||
initBridge(true);
|
||||
_lastGameMode = GAMEMODE_BRIDGE;
|
||||
// TODO: mode change
|
||||
}
|
||||
else {
|
||||
_txtFilename = _missionToLoad;
|
||||
initBridge(false);
|
||||
// TODO: mode change
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after loading "saveOrLoadMetadata" to load all the data pertaining to game
|
||||
* execution.
|
||||
*/
|
||||
bool StarTrekEngine::saveOrLoadGameData(Common::SeekableReadStream *in, Common::WriteStream *out, SavegameMetadata *meta) {
|
||||
Common::Serializer ser(in, out);
|
||||
|
||||
if (ser.isLoading()) {
|
||||
if (_lastGameMode == GAMEMODE_BRIDGE)
|
||||
cleanupBridge();
|
||||
else // Assume GAMEMODE_AWAYMISSION
|
||||
unloadRoom();
|
||||
}
|
||||
|
||||
ser.syncAsUint16LE(_gameMode);
|
||||
// TODO: sub_1d8eb (save) / sub_1d958 (load) (probably bridge / space combat state)
|
||||
|
||||
ser.syncString(_sound->_loadedMidiFilename);
|
||||
ser.syncAsSint16LE(_sound->_loopingMidiTrack);
|
||||
|
||||
if (ser.isLoading()) {
|
||||
if (_sound->_loadedMidiFilename.empty())
|
||||
_sound->clearAllMidiSlots();
|
||||
else {
|
||||
_sound->loadMusicFile(_sound->_loadedMidiFilename);
|
||||
_sound->playMidiMusicTracks(_sound->_loopingMidiTrack, _sound->_loopingMidiTrack);
|
||||
}
|
||||
}
|
||||
|
||||
ser.syncAsUint16LE(_frameIndex);
|
||||
ser.syncAsUint16LE(_mouseControllingShip);
|
||||
// TODO: word_45aa8
|
||||
// TODO: word_45aaa
|
||||
// TODO: word_45aac
|
||||
// TODO: word_5082e
|
||||
// TODO: dword_519b0
|
||||
// TODO: word_45ab2
|
||||
// TODO: word_45ab4
|
||||
// TODO: word_45ab8
|
||||
|
||||
ser.syncString(_missionToLoad);
|
||||
// TODO: word_4b032
|
||||
// TODO: word_519bc
|
||||
// TODO: word_45c5c
|
||||
// TODO: unk_52afe
|
||||
ser.syncString(_sound->_loopingAudioName);
|
||||
|
||||
if (ser.isLoading()) {
|
||||
if (!_sound->_loopingAudioName.empty())
|
||||
_sound->playVoc(_sound->_loopingAudioName);
|
||||
}
|
||||
|
||||
// TODO: word_45a50
|
||||
|
||||
for (int i = 0; i < NUM_OBJECTS; i++) {
|
||||
ser.syncAsByte(_itemList[i].have);
|
||||
}
|
||||
|
||||
if (_gameMode == GAMEMODE_AWAYMISSION) {
|
||||
ser.syncString(_missionName);
|
||||
ser.syncAsSint16LE(_roomIndex);
|
||||
|
||||
if (ser.isLoading()) {
|
||||
_gfx->fadeoutScreen();
|
||||
_txtFilename = "ground";
|
||||
|
||||
// This must be done before loading the actor variables, since this clears
|
||||
// them.
|
||||
loadRoom(_missionName, _roomIndex);
|
||||
}
|
||||
|
||||
ser.syncAsUint32LE(_roomFrameCounter);
|
||||
ser.syncAsUint32LE(_frameIndex); // FIXME: redundant
|
||||
|
||||
// Serialize the "actor" class
|
||||
for (int i = 0; i < NUM_ACTORS; i++) {
|
||||
Actor *a = &_actorList[i];
|
||||
ser.syncAsUint16LE(a->spriteDrawn);
|
||||
ser.syncBytes((byte *)a->animFilename, 16);
|
||||
ser.syncAsUint16LE(a->animType);
|
||||
|
||||
a->sprite.saveLoadWithSerializer(ser);
|
||||
|
||||
ser.syncBytes((byte *)a->bitmapFilename, 10);
|
||||
ser.syncAsUint16LE(a->scale);
|
||||
// Can't save "animFile" (will be reloaded)
|
||||
ser.syncAsUint16LE(a->numAnimFrames);
|
||||
ser.syncAsUint16LE(a->animFrame);
|
||||
ser.syncAsUint32LE(a->frameToStartNextAnim);
|
||||
ser.syncAsSint16LE(a->pos.x);
|
||||
ser.syncAsSint16LE(a->pos.y);
|
||||
ser.syncAsUint16LE(a->field60);
|
||||
ser.syncAsUint16LE(a->field62);
|
||||
ser.syncAsUint16LE(a->triggerActionWhenAnimFinished);
|
||||
ser.syncAsUint16LE(a->finishedAnimActionParam);
|
||||
ser.syncBytes((byte *)a->animationString2, 8);
|
||||
ser.syncAsUint16LE(a->field70);
|
||||
ser.syncAsUint16LE(a->field72);
|
||||
ser.syncAsUint16LE(a->field74);
|
||||
ser.syncAsUint16LE(a->field76);
|
||||
ser.syncAsSint16LE(a->iwSrcPosition);
|
||||
ser.syncAsSint16LE(a->iwDestPosition);
|
||||
ser.syncAsSint32LE(a->granularPosX);
|
||||
ser.syncAsSint32LE(a->granularPosY);
|
||||
ser.syncAsSint32LE(a->speedX);
|
||||
ser.syncAsSint32LE(a->speedY);
|
||||
ser.syncAsSint16LE(a->dest.x);
|
||||
ser.syncAsSint16LE(a->dest.y);
|
||||
ser.syncAsUint16LE(a->field90);
|
||||
ser.syncAsByte(a->field92);
|
||||
ser.syncAsByte(a->direction);
|
||||
ser.syncAsUint16LE(a->field94);
|
||||
ser.syncAsUint16LE(a->field96);
|
||||
ser.syncBytes((byte *)a->animationString, 10);
|
||||
ser.syncAsUint16LE(a->fielda2);
|
||||
ser.syncAsUint16LE(a->fielda4);
|
||||
ser.syncAsUint16LE(a->fielda6);
|
||||
}
|
||||
|
||||
ser.syncString(_mapFilename);
|
||||
// TODO: awayMissionStruct
|
||||
|
||||
// The action queue
|
||||
if (ser.isLoading()) {
|
||||
_actionQueue = Common::Queue<Action>();
|
||||
int16 n;
|
||||
ser.syncAsSint16LE(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
Action a;
|
||||
a.saveLoadWithSerializer(ser);
|
||||
_actionQueue.push(a);
|
||||
}
|
||||
}
|
||||
else { // Saving
|
||||
int16 n = _actionQueue.size();
|
||||
ser.syncAsSint16LE(n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
Action a = _actionQueue.pop();
|
||||
a.saveLoadWithSerializer(ser);
|
||||
_actionQueue.push(a);
|
||||
}
|
||||
}
|
||||
|
||||
// Original game located changes in RDF files and saved them. Since RDF files
|
||||
// aren't modified directly here, that's skipped.
|
||||
|
||||
ser.syncAsSint16LE(_objectHasWalkPosition);
|
||||
ser.syncAsSint16LE(_objectWalkPosition.x);
|
||||
ser.syncAsSint16LE(_objectWalkPosition.y);
|
||||
|
||||
for (int i = 0; i < MAX_BUFFERED_WALK_ACTIONS; i++) {
|
||||
_actionOnWalkCompletion[i].saveLoadWithSerializer(ser);
|
||||
ser.syncAsByte(_actionOnWalkCompletionInUse[i]);
|
||||
}
|
||||
|
||||
ser.syncAsSint16LE(_warpHotspotsActive);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::String StarTrekEngine::getSavegameFilename(int slotId) const {
|
||||
Common::String saveLoadSlot = _targetName;
|
||||
saveLoadSlot += Common::String::format(".%.3d", slotId);
|
||||
return saveLoadSlot;
|
||||
}
|
||||
|
||||
|
||||
// Static function (reused in detection.cpp)
|
||||
bool saveOrLoadMetadata(Common::SeekableReadStream *in, Common::WriteStream *out, SavegameMetadata *meta) {
|
||||
Common::Serializer ser(in, out);
|
||||
|
||||
ser.syncAsUint32LE(meta->version);
|
||||
ser.syncBytes((byte *)meta->description, SAVEGAME_DESCRIPTION_LEN + 1);
|
||||
|
||||
// Thumbnail
|
||||
if (ser.isLoading()) {
|
||||
if (!::Graphics::loadThumbnail(*in, meta->thumbnail))
|
||||
meta->thumbnail = nullptr;
|
||||
}
|
||||
else
|
||||
::Graphics::saveThumbnail(*out);
|
||||
|
||||
// Creation date/time
|
||||
ser.syncAsUint32LE(meta->saveDate);
|
||||
debugC(5, kDebugSavegame, "Save date: %d", meta->saveDate);
|
||||
ser.syncAsUint16LE(meta->saveTime);
|
||||
debugC(5, kDebugSavegame, "Save time: %d", meta->saveTime);
|
||||
ser.syncAsByte(meta->saveTimeSecs); // write seconds of save time as well
|
||||
ser.syncAsUint32LE(meta->playTime);
|
||||
debugC(5, kDebugSavegame, "Play time: %d", meta->playTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue