2009-02-17 15:02:16 +00:00
|
|
|
/* 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.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-21 22:50:35 +00:00
|
|
|
#include "common/stream.h"
|
|
|
|
#include "common/system.h"
|
2009-04-27 12:31:27 +00:00
|
|
|
#include "common/func.h"
|
2009-03-15 20:31:29 +00:00
|
|
|
#include "common/serializer.h"
|
2009-10-11 15:51:43 +00:00
|
|
|
#include "graphics/thumbnail.h"
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2009-05-13 16:52:41 +00:00
|
|
|
#include "sci/sci.h"
|
2009-12-04 17:42:32 +00:00
|
|
|
#include "sci/event.h"
|
2009-11-12 09:24:46 +00:00
|
|
|
|
2010-02-13 17:44:58 +00:00
|
|
|
#include "sci/engine/features.h"
|
2009-02-27 02:23:40 +00:00
|
|
|
#include "sci/engine/state.h"
|
2009-10-10 02:16:23 +00:00
|
|
|
#include "sci/engine/message.h"
|
2009-03-12 03:26:21 +00:00
|
|
|
#include "sci/engine/savegame.h"
|
2010-06-15 07:20:53 +00:00
|
|
|
#include "sci/engine/selector.h"
|
2009-11-12 09:24:46 +00:00
|
|
|
#include "sci/engine/vm_types.h"
|
2010-01-29 11:05:06 +00:00
|
|
|
#include "sci/engine/script.h" // for SCI_OBJ_EXPORTS and SCI_OBJ_SYNONYMS
|
2010-01-31 12:35:15 +00:00
|
|
|
#include "sci/graphics/ports.h"
|
2010-01-05 01:22:16 +00:00
|
|
|
#include "sci/sound/audio.h"
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2010-01-05 01:22:16 +00:00
|
|
|
#include "sci/sound/iterator/core.h"
|
|
|
|
#include "sci/sound/iterator/iterator.h"
|
2009-12-25 13:18:48 +00:00
|
|
|
#else
|
2010-01-05 01:22:16 +00:00
|
|
|
#include "sci/sound/music.h"
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-15 08:25:51 +00:00
|
|
|
#include "gui/message.h"
|
|
|
|
|
2009-02-21 10:23:36 +00:00
|
|
|
namespace Sci {
|
|
|
|
|
2009-09-06 12:59:56 +00:00
|
|
|
|
|
|
|
#define VER(x) Common::Serializer::Version(x)
|
|
|
|
|
2009-09-21 21:38:43 +00:00
|
|
|
|
|
|
|
// OBSOLETE: This const is used for backward compatibility only.
|
|
|
|
const uint32 INTMAPPER_MAGIC_KEY = 0xDEADBEEF;
|
|
|
|
|
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-03-15 20:31:29 +00:00
|
|
|
// from ksound.cpp:
|
2009-11-12 15:24:11 +00:00
|
|
|
SongIterator *build_iterator(ResourceManager *resMan, int song_nr, SongIteratorType type, songit_id_t id);
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
|
|
|
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
#pragma mark -
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
// TODO: Many of the following sync_*() methods should be turned into member funcs
|
|
|
|
// of the classes they are syncing.
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-12-25 13:18:48 +00:00
|
|
|
static void sync_songlib(Common::Serializer &s, SongLibrary &obj);
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-20 20:31:08 +00:00
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-12-25 13:18:48 +00:00
|
|
|
static void syncSong(Common::Serializer &s, Song &obj) {
|
2009-06-07 17:06:32 +00:00
|
|
|
s.syncAsSint32LE(obj._handle);
|
|
|
|
s.syncAsSint32LE(obj._resourceNum);
|
|
|
|
s.syncAsSint32LE(obj._priority);
|
|
|
|
s.syncAsSint32LE(obj._status);
|
|
|
|
s.syncAsSint32LE(obj._restoreBehavior);
|
|
|
|
s.syncAsSint32LE(obj._restoreTime);
|
|
|
|
s.syncAsSint32LE(obj._loops);
|
|
|
|
s.syncAsSint32LE(obj._hold);
|
2009-05-20 17:53:31 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
if (s.isLoading()) {
|
2009-06-07 17:06:32 +00:00
|
|
|
obj._it = 0;
|
2009-03-15 20:31:29 +00:00
|
|
|
obj._delay = 0;
|
2009-06-07 17:06:32 +00:00
|
|
|
obj._next = 0;
|
|
|
|
obj._nextPlaying = 0;
|
|
|
|
obj._nextStopping = 0;
|
2009-03-15 20:31:29 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-12-25 13:18:48 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
#define DEFROBNICATE_HANDLE(handle) (make_reg((handle >> 16) & 0xffff, handle & 0xffff))
|
|
|
|
|
2009-12-28 21:03:13 +00:00
|
|
|
void MusicEntry::saveLoadWithSerializer(Common::Serializer &s) {
|
2009-12-25 13:18:48 +00:00
|
|
|
if (s.getVersion() < 14) {
|
2009-12-26 00:22:21 +00:00
|
|
|
// Old sound system data. This data is only loaded, never saved (as we're never
|
|
|
|
// saving in the older version format)
|
2009-12-25 13:18:48 +00:00
|
|
|
uint32 handle = 0;
|
|
|
|
s.syncAsSint32LE(handle);
|
2009-12-28 21:03:13 +00:00
|
|
|
soundObj = DEFROBNICATE_HANDLE(handle);
|
2010-05-19 14:19:16 +00:00
|
|
|
s.syncAsSint32LE(resourceId);
|
|
|
|
s.syncAsSint32LE(priority);
|
2009-12-28 21:03:13 +00:00
|
|
|
s.syncAsSint32LE(status);
|
2009-12-25 13:18:48 +00:00
|
|
|
s.skip(4); // restoreBehavior
|
2009-12-26 00:22:21 +00:00
|
|
|
uint32 restoreTime = 0;
|
|
|
|
s.syncAsSint32LE(restoreTime);
|
2009-12-28 21:03:13 +00:00
|
|
|
ticker = restoreTime * 60 / 1000;
|
SCI/new music code:
- Resolved a deadlock with the mixer, and added appropriate mutexes (a result of the fact that SCI mixes MIDI and digital audio in the same list)
- Fixed sound playing when loading games, by properly resetting the MIDI driver
- Reverted savegame version to 14 - the changes in versions 15 and 16 don't have any effect on the currently enabled old music code, and the new music code is disabled by default, and is still prone to changes
- Now saving/loading signal, loop and hold for each sound, as well as reverb
- Added stub code for setting reverb and channel hold
- The signal, loop and hold values of each song are cached, like in SSCI and like what happens in Greg's SCI implementation. This allows a clear separation of the engine code from the rest of the engine. Reverted commits 46792 and 46797
- Removed duplicate song list accessing code
- Song cues are now updated in kAnimate for SCI0, like the old music code does, to compensate for the fact that SCI0 didn't poll for music changes via cmdUpdateCues, like what SCI01 and newer do
- Cleanup
svn-id: r46812
2010-01-01 06:41:52 +00:00
|
|
|
s.syncAsSint32LE(loop);
|
|
|
|
s.syncAsSint32LE(hold);
|
2009-12-25 13:18:48 +00:00
|
|
|
// volume and dataInc will be synced from the sound objects
|
2009-12-26 00:22:21 +00:00
|
|
|
// when the sound list is reconstructed in gamestate_restore()
|
2010-01-01 21:04:20 +00:00
|
|
|
volume = MUSIC_VOLUME_MAX;
|
2009-12-28 21:03:13 +00:00
|
|
|
dataInc = 0;
|
2009-12-25 13:18:48 +00:00
|
|
|
// No fading info
|
2009-12-28 21:03:13 +00:00
|
|
|
fadeTo = 0;
|
|
|
|
fadeStep = 0;
|
|
|
|
fadeTicker = 0;
|
|
|
|
fadeTickerStep = 0;
|
2009-12-25 13:18:48 +00:00
|
|
|
} else {
|
|
|
|
// A bit more optimized saving
|
2010-06-15 07:20:53 +00:00
|
|
|
soundObj.saveLoadWithSerializer(s);
|
2010-05-19 14:19:16 +00:00
|
|
|
s.syncAsSint16LE(resourceId);
|
2009-12-28 21:03:13 +00:00
|
|
|
s.syncAsSint16LE(dataInc);
|
|
|
|
s.syncAsSint16LE(ticker);
|
2010-01-01 14:22:07 +00:00
|
|
|
s.syncAsSint16LE(signal, VER(17));
|
2010-05-19 14:19:16 +00:00
|
|
|
s.syncAsByte(priority);
|
2010-01-01 14:22:07 +00:00
|
|
|
s.syncAsSint16LE(loop, VER(17));
|
2009-12-28 21:03:13 +00:00
|
|
|
s.syncAsByte(volume);
|
2010-01-01 14:22:07 +00:00
|
|
|
s.syncAsByte(hold, VER(17));
|
2009-12-28 21:03:13 +00:00
|
|
|
s.syncAsByte(fadeTo);
|
|
|
|
s.syncAsSint16LE(fadeStep);
|
|
|
|
s.syncAsSint32LE(fadeTicker);
|
|
|
|
s.syncAsSint32LE(fadeTickerStep);
|
|
|
|
s.syncAsByte(status);
|
2009-12-25 13:18:48 +00:00
|
|
|
}
|
2009-12-25 13:26:09 +00:00
|
|
|
|
2009-12-26 00:22:21 +00:00
|
|
|
// pMidiParser and pStreamAud will be initialized when the
|
|
|
|
// sound list is reconstructed in gamestate_restore()
|
|
|
|
if (s.isLoading()) {
|
2009-12-28 21:03:13 +00:00
|
|
|
soundRes = 0;
|
|
|
|
pMidiParser = 0;
|
|
|
|
pStreamAud = 0;
|
2009-12-26 00:22:21 +00:00
|
|
|
}
|
2009-12-25 13:18:48 +00:00
|
|
|
}
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-03-24 11:31:16 +00:00
|
|
|
|
2009-05-04 15:05:11 +00:00
|
|
|
// Experimental hack: Use syncWithSerializer to sync. By default, this assume
|
|
|
|
// the object to be synced is a subclass of Serializable and thus tries to invoke
|
|
|
|
// the saveLoadWithSerializer() method. But it is possible to specialize this
|
|
|
|
// template function to handle stuff that is not implementing that interface.
|
|
|
|
template<typename T>
|
|
|
|
void syncWithSerializer(Common::Serializer &s, T &obj) {
|
|
|
|
obj.saveLoadWithSerializer(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
// By default, sync using syncWithSerializer, which in turn can easily be overloaded.
|
|
|
|
template <typename T>
|
|
|
|
struct DefaultSyncer : Common::BinaryFunction<Common::Serializer, T, void> {
|
|
|
|
void operator()(Common::Serializer &s, T &obj) const {
|
|
|
|
//obj.saveLoadWithSerializer(s);
|
|
|
|
syncWithSerializer(s, obj);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-03-24 11:31:16 +00:00
|
|
|
/**
|
|
|
|
* Sync a Common::Array using a Common::Serializer.
|
|
|
|
* When saving, this writes the length of the array, then syncs (writes) all entries.
|
|
|
|
* When loading, it loads the length of the array, then resizes it accordingly, before
|
|
|
|
* syncing all entries.
|
|
|
|
*
|
2009-05-04 15:05:11 +00:00
|
|
|
* Note: This shouldn't be in common/array.h nor in common/serializer.h, after
|
|
|
|
* all, not all code using arrays wants to use the serializer, and vice versa.
|
|
|
|
* But we could put this into a separate header file in common/ at some point.
|
|
|
|
* Something like common/serializer-extras.h or so.
|
2009-03-24 11:31:16 +00:00
|
|
|
*
|
|
|
|
* TODO: Add something like this for lists, queues....
|
|
|
|
*/
|
2009-05-04 15:05:11 +00:00
|
|
|
template <typename T, class Syncer = DefaultSyncer<T> >
|
|
|
|
struct ArraySyncer : Common::BinaryFunction<Common::Serializer, T, void> {
|
|
|
|
void operator()(Common::Serializer &s, Common::Array<T> &arr) const {
|
|
|
|
uint len = arr.size();
|
|
|
|
s.syncAsUint32LE(len);
|
|
|
|
Syncer sync;
|
|
|
|
|
|
|
|
// Resize the array if loading.
|
|
|
|
if (s.isLoading())
|
|
|
|
arr.resize(len);
|
|
|
|
|
|
|
|
typename Common::Array<T>::iterator i;
|
|
|
|
for (i = arr.begin(); i != arr.end(); ++i) {
|
|
|
|
sync(s, *i);
|
|
|
|
}
|
2009-03-24 11:31:16 +00:00
|
|
|
}
|
2009-05-04 15:05:11 +00:00
|
|
|
};
|
2009-02-28 11:07:36 +00:00
|
|
|
|
2009-05-04 15:05:11 +00:00
|
|
|
// Convenience wrapper
|
2009-04-27 12:31:27 +00:00
|
|
|
template<typename T>
|
2009-05-04 15:05:11 +00:00
|
|
|
void syncArray(Common::Serializer &s, Common::Array<T> &arr) {
|
|
|
|
ArraySyncer<T> sync;
|
|
|
|
sync(s, arr);
|
2009-04-27 12:31:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-12 23:30:42 +00:00
|
|
|
template <>
|
|
|
|
void syncWithSerializer(Common::Serializer &s, reg_t &obj) {
|
2010-06-15 07:20:53 +00:00
|
|
|
obj.saveLoadWithSerializer(s);
|
2009-05-12 23:30:42 +00:00
|
|
|
}
|
|
|
|
|
2009-05-03 09:25:15 +00:00
|
|
|
void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
|
2010-05-19 08:50:24 +00:00
|
|
|
s.skip(4, VER(9), VER(9)); // OBSOLETE: Used to be reserved_id
|
2010-05-19 09:39:11 +00:00
|
|
|
s.skip(4, VER(9), VER(18)); // OBSOLETE: Used to be _exportsAreWide
|
2010-05-19 08:50:24 +00:00
|
|
|
s.skip(4, VER(9), VER(9)); // OBSOLETE: Used to be gc_mark_bits
|
2009-05-03 09:25:15 +00:00
|
|
|
|
2009-09-06 13:00:30 +00:00
|
|
|
if (s.isLoading()) {
|
|
|
|
// Reset _scriptSegMap, to be restored below
|
|
|
|
_scriptSegMap.clear();
|
|
|
|
|
|
|
|
if (s.getVersion() <= 9) {
|
2009-09-21 21:38:43 +00:00
|
|
|
// OBSOLETE: Skip over the old id_seg_map when loading (we now
|
|
|
|
// regenerate the equivalent data, in _scriptSegMap, from scratch).
|
2009-09-06 13:00:30 +00:00
|
|
|
|
|
|
|
s.skip(4); // base_value
|
|
|
|
while (true) {
|
2009-09-08 22:03:07 +00:00
|
|
|
uint32 key = 0;
|
2009-09-06 13:00:30 +00:00
|
|
|
s.syncAsSint32LE(key);
|
|
|
|
if (key == INTMAPPER_MAGIC_KEY)
|
|
|
|
break;
|
|
|
|
s.skip(4); // idx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-03 09:25:15 +00:00
|
|
|
|
2009-05-11 13:32:00 +00:00
|
|
|
uint sync_heap_size = _heap.size();
|
|
|
|
s.syncAsUint32LE(sync_heap_size);
|
2009-05-03 22:46:11 +00:00
|
|
|
_heap.resize(sync_heap_size);
|
2009-09-06 13:00:30 +00:00
|
|
|
for (uint i = 0; i < sync_heap_size; ++i) {
|
2009-09-17 00:45:12 +00:00
|
|
|
SegmentObj *&mobj = _heap[i];
|
2009-09-06 13:00:30 +00:00
|
|
|
|
2009-09-17 13:22:46 +00:00
|
|
|
// Sync the segment type
|
2009-09-17 00:45:12 +00:00
|
|
|
SegmentType type = (s.isSaving() && mobj) ? mobj->getType() : SEG_TYPE_INVALID;
|
2009-09-06 13:00:30 +00:00
|
|
|
s.syncAsUint32LE(type);
|
|
|
|
|
|
|
|
// If we were saving and mobj == 0, or if we are loading and this is an
|
|
|
|
// entry marked as empty -> skip to next
|
2009-09-17 00:45:12 +00:00
|
|
|
if (type == SEG_TYPE_INVALID) {
|
2009-09-06 13:00:30 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-10-13 18:54:20 +00:00
|
|
|
s.skip(4, VER(9), VER(9)); // OBSOLETE: Used to be _segManagerId
|
|
|
|
|
2009-10-13 20:50:59 +00:00
|
|
|
// Don't save or load HunkTable segments
|
|
|
|
if (type == SEG_TYPE_HUNK) {
|
2009-10-13 18:54:20 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle the OBSOLETE type SEG_TYPE_STRING_FRAG -- just ignore it
|
|
|
|
if (s.isLoading() && type == SEG_TYPE_STRING_FRAG) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-09-06 13:00:30 +00:00
|
|
|
if (s.isLoading()) {
|
2009-09-17 00:45:12 +00:00
|
|
|
mobj = SegmentObj::createSegmentObj(type);
|
2009-09-06 13:00:30 +00:00
|
|
|
}
|
|
|
|
assert(mobj);
|
|
|
|
|
|
|
|
// Let the object sync custom data
|
|
|
|
mobj->saveLoadWithSerializer(s);
|
|
|
|
|
|
|
|
// If we are loading a script, hook it up in the script->segment map.
|
2009-09-17 00:45:12 +00:00
|
|
|
if (s.isLoading() && type == SEG_TYPE_SCRIPT) {
|
2009-09-16 23:32:27 +00:00
|
|
|
_scriptSegMap[((Script *)mobj)->_nr] = i;
|
2009-09-06 13:00:30 +00:00
|
|
|
}
|
|
|
|
}
|
2009-05-03 09:25:15 +00:00
|
|
|
|
|
|
|
s.syncAsSint32LE(Clones_seg_id);
|
|
|
|
s.syncAsSint32LE(Lists_seg_id);
|
|
|
|
s.syncAsSint32LE(Nodes_seg_id);
|
2009-02-28 11:12:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-05-04 15:05:11 +00:00
|
|
|
template <>
|
|
|
|
void syncWithSerializer(Common::Serializer &s, Class &obj) {
|
2009-03-15 20:31:29 +00:00
|
|
|
s.syncAsSint32LE(obj.script);
|
2010-06-15 07:20:53 +00:00
|
|
|
obj.reg.saveLoadWithSerializer(s);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj) {
|
|
|
|
// TODO: It would be a good idea to store a magic number & a header size here,
|
|
|
|
// so that we can implement backward compatibility if the savegame format changes.
|
2009-02-20 20:31:08 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
s.syncString(obj.savegame_name);
|
2009-09-06 12:59:56 +00:00
|
|
|
s.syncVersion(CURRENT_SAVEGAME_VERSION);
|
|
|
|
obj.savegame_version = s.getVersion();
|
2009-03-15 20:31:29 +00:00
|
|
|
s.syncString(obj.game_version);
|
2009-09-06 12:59:56 +00:00
|
|
|
s.skip(4, VER(9), VER(9)); // obsolete: used to be game version
|
2009-03-15 20:31:29 +00:00
|
|
|
s.syncAsSint32LE(obj.savegame_date);
|
|
|
|
s.syncAsSint32LE(obj.savegame_time);
|
2010-06-15 08:25:51 +00:00
|
|
|
if (s.getVersion() < 22) {
|
|
|
|
obj.game_object_offset = 0;
|
|
|
|
obj.script0_size = 0;
|
|
|
|
} else {
|
|
|
|
s.syncAsUint16LE(obj.game_object_offset);
|
|
|
|
s.syncAsUint16LE(obj.script0_size);
|
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
|
2009-09-21 21:38:43 +00:00
|
|
|
s.skip(4, VER(9), VER(9)); // OBSOLETE: Used to be savegame_version
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-09-25 13:02:11 +00:00
|
|
|
Common::String tmp;
|
|
|
|
s.syncString(tmp); // OBSOLETE: Used to be game_version
|
2009-09-21 21:38:43 +00:00
|
|
|
s.skip(4, VER(9), VER(9)); // OBSOLETE: Used to be version
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-11-12 09:24:46 +00:00
|
|
|
// OBSOLETE: Saved menus. Skip all of the saved data
|
2009-12-25 13:18:48 +00:00
|
|
|
if (s.getVersion() < 14) {
|
|
|
|
int totalMenus = 0;
|
|
|
|
s.syncAsUint32LE(totalMenus);
|
|
|
|
|
|
|
|
// Now iterate through the obsolete saved menu data
|
|
|
|
for (int i = 0; i < totalMenus; i++) {
|
|
|
|
s.syncString(tmp); // OBSOLETE: Used to be _title
|
|
|
|
s.skip(4, VER(12), VER(12)); // OBSOLETE: Used to be _titleWidth
|
|
|
|
s.skip(4, VER(12), VER(12)); // OBSOLETE: Used to be _width
|
|
|
|
|
|
|
|
int menuLength = 0;
|
|
|
|
s.syncAsUint32LE(menuLength);
|
|
|
|
|
|
|
|
for (int j = 0; j < menuLength; j++) {
|
|
|
|
s.skip(4, VER(12), VER(12)); // OBSOLETE: Used to be _type
|
|
|
|
s.syncString(tmp); // OBSOLETE: Used to be _keytext
|
|
|
|
s.skip(4, VER(9), VER(9)); // OBSOLETE: Used to be keytext_size
|
|
|
|
|
|
|
|
s.skip(4, VER(12), VER(12)); // OBSOLETE: Used to be _flags
|
|
|
|
s.skip(64, VER(12), VER(12)); // OBSOLETE: Used to be MENU_SAID_SPEC_SIZE
|
|
|
|
s.skip(4, VER(12), VER(12)); // OBSOLETE: Used to be _saidPos
|
|
|
|
s.syncString(tmp); // OBSOLETE: Used to be _text
|
|
|
|
s.skip(4, VER(12), VER(12)); // OBSOLETE: Used to be _textPos
|
|
|
|
s.skip(4 * 4, VER(12), VER(12)); // OBSOLETE: Used to be _modifiers, _key, _enabled and _tag
|
|
|
|
}
|
2009-11-12 11:47:28 +00:00
|
|
|
}
|
2009-11-12 09:24:46 +00:00
|
|
|
}
|
2009-02-15 22:28:12 +00:00
|
|
|
|
2009-10-30 14:39:26 +00:00
|
|
|
s.skip(4, VER(12), VER(12)); // obsolete: used to be status_bar_foreground
|
|
|
|
s.skip(4, VER(12), VER(12)); // obsolete: used to be status_bar_background
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2010-06-10 10:27:13 +00:00
|
|
|
if (s.getVersion() >= 13 && getSciVersion() <= SCI_VERSION_1_1) {
|
|
|
|
// Save/Load picPort as well for SCI0-SCI1.1. Necessary for Castle of Dr. Brain,
|
|
|
|
// as the picPort has been changed when loading during the intro
|
2009-12-08 20:54:18 +00:00
|
|
|
int16 picPortTop, picPortLeft;
|
|
|
|
Common::Rect picPortRect;
|
2010-01-30 02:03:59 +00:00
|
|
|
|
2010-06-10 10:27:13 +00:00
|
|
|
if (s.isSaving())
|
2010-02-13 17:43:31 +00:00
|
|
|
picPortRect = g_sci->_gfxPorts->kernelGetPicWindow(picPortTop, picPortLeft);
|
2009-12-08 20:54:18 +00:00
|
|
|
|
2009-12-09 07:28:04 +00:00
|
|
|
s.syncAsSint16LE(picPortRect.top);
|
|
|
|
s.syncAsSint16LE(picPortRect.left);
|
|
|
|
s.syncAsSint16LE(picPortRect.bottom);
|
|
|
|
s.syncAsSint16LE(picPortRect.right);
|
2009-12-08 20:54:18 +00:00
|
|
|
s.syncAsSint16LE(picPortTop);
|
|
|
|
s.syncAsSint16LE(picPortLeft);
|
2010-06-10 10:15:32 +00:00
|
|
|
|
2010-06-10 10:27:13 +00:00
|
|
|
if (s.isLoading())
|
2010-06-10 10:15:32 +00:00
|
|
|
g_sci->_gfxPorts->kernelSetPicWindow(picPortRect, picPortTop, picPortLeft, false);
|
2009-12-08 20:54:18 +00:00
|
|
|
}
|
|
|
|
|
2010-06-08 18:23:38 +00:00
|
|
|
s.skip(1, VER(9), VER(9)); // obsolete: used to be a flag indicating if we got sci11 or not
|
|
|
|
|
|
|
|
if (s.isLoading())
|
|
|
|
_segMan->resetSegMan();
|
|
|
|
|
|
|
|
_segMan->saveLoadWithSerializer(s);
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2010-05-29 23:56:37 +00:00
|
|
|
syncArray<Class>(s, _segMan->_classTable);
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-12-25 13:18:48 +00:00
|
|
|
sync_songlib(s, _sound._songlib);
|
2009-12-20 13:28:23 +00:00
|
|
|
#else
|
2009-12-28 20:10:15 +00:00
|
|
|
_soundCmd->syncPlayList(s);
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-05-19 00:34:10 +00:00
|
|
|
void LocalVariables::saveLoadWithSerializer(Common::Serializer &s) {
|
|
|
|
s.syncAsSint32LE(script_id);
|
|
|
|
syncArray<reg_t>(s, _locals);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2009-10-10 15:58:51 +00:00
|
|
|
void Object::saveLoadWithSerializer(Common::Serializer &s) {
|
|
|
|
s.syncAsSint32LE(_flags);
|
2010-06-15 07:20:53 +00:00
|
|
|
_pos.saveLoadWithSerializer(s);
|
2009-10-11 19:23:00 +00:00
|
|
|
s.skip(4, VER(9), VER(12)); // OBSOLETE: Used to be variable_names_nr
|
2009-10-10 15:58:51 +00:00
|
|
|
s.syncAsSint32LE(_methodCount); // that's actually a uint16
|
|
|
|
|
|
|
|
syncArray<reg_t>(s, _variables);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-05-04 15:05:11 +00:00
|
|
|
template <>
|
2009-05-11 13:32:00 +00:00
|
|
|
void syncWithSerializer(Common::Serializer &s, Table<Clone>::Entry &obj) {
|
|
|
|
s.syncAsSint32LE(obj.next_free);
|
|
|
|
|
|
|
|
syncWithSerializer<Object>(s, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void syncWithSerializer(Common::Serializer &s, Table<List>::Entry &obj) {
|
|
|
|
s.syncAsSint32LE(obj.next_free);
|
|
|
|
|
2010-06-15 07:20:53 +00:00
|
|
|
obj.first.saveLoadWithSerializer(s);
|
|
|
|
obj.last.saveLoadWithSerializer(s);
|
2009-02-24 02:59:50 +00:00
|
|
|
}
|
|
|
|
|
2009-05-04 15:05:11 +00:00
|
|
|
template <>
|
2009-05-11 13:32:00 +00:00
|
|
|
void syncWithSerializer(Common::Serializer &s, Table<Node>::Entry &obj) {
|
|
|
|
s.syncAsSint32LE(obj.next_free);
|
|
|
|
|
2010-06-15 07:20:53 +00:00
|
|
|
obj.pred.saveLoadWithSerializer(s);
|
|
|
|
obj.succ.saveLoadWithSerializer(s);
|
|
|
|
obj.key.saveLoadWithSerializer(s);
|
|
|
|
obj.value.saveLoadWithSerializer(s);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2010-01-30 02:03:59 +00:00
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
template <>
|
|
|
|
void syncWithSerializer(Common::Serializer &s, Table<SciArray<reg_t> >::Entry &obj) {
|
|
|
|
s.syncAsSint32LE(obj.next_free);
|
|
|
|
|
|
|
|
byte type = 0;
|
|
|
|
uint32 size = 0;
|
|
|
|
|
|
|
|
if (s.isSaving()) {
|
|
|
|
type = (byte)obj.getType();
|
|
|
|
size = obj.getSize();
|
|
|
|
s.syncAsByte(type);
|
|
|
|
s.syncAsUint32LE(size);
|
|
|
|
} else {
|
|
|
|
s.syncAsByte(type);
|
|
|
|
s.syncAsUint32LE(size);
|
|
|
|
obj.setType((int8)type);
|
|
|
|
|
|
|
|
// HACK: Skip arrays that have a negative type
|
|
|
|
if ((int8)type < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
obj.setSize(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32 i = 0; i < size; i++) {
|
|
|
|
reg_t value;
|
|
|
|
|
|
|
|
if (s.isSaving())
|
|
|
|
value = obj.getValue(i);
|
|
|
|
|
2010-06-15 07:20:53 +00:00
|
|
|
value.saveLoadWithSerializer(s);
|
2010-01-30 02:03:59 +00:00
|
|
|
|
|
|
|
if (s.isLoading())
|
|
|
|
obj.setValue(i, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <>
|
|
|
|
void syncWithSerializer(Common::Serializer &s, Table<SciString>::Entry &obj) {
|
|
|
|
s.syncAsSint32LE(obj.next_free);
|
|
|
|
|
|
|
|
uint32 size = 0;
|
|
|
|
|
|
|
|
if (s.isSaving()) {
|
|
|
|
size = obj.getSize();
|
|
|
|
s.syncAsUint32LE(size);
|
|
|
|
} else {
|
|
|
|
s.syncAsUint32LE(size);
|
|
|
|
obj.setSize(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32 i = 0; i < size; i++) {
|
2010-03-10 11:26:27 +00:00
|
|
|
char value = 0;
|
2010-01-30 02:03:59 +00:00
|
|
|
|
|
|
|
if (s.isSaving())
|
|
|
|
value = obj.getValue(i);
|
|
|
|
|
|
|
|
s.syncAsByte(value);
|
|
|
|
|
|
|
|
if (s.isLoading())
|
|
|
|
obj.setValue(i, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-05-04 15:05:11 +00:00
|
|
|
template <typename T>
|
2009-05-11 13:32:00 +00:00
|
|
|
void sync_Table(Common::Serializer &s, T &obj) {
|
2009-03-15 20:31:29 +00:00
|
|
|
s.syncAsSint32LE(obj.first_free);
|
|
|
|
s.syncAsSint32LE(obj.entries_used);
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-05-11 13:32:00 +00:00
|
|
|
syncArray<typename T::Entry>(s, obj._table);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-05-19 00:34:10 +00:00
|
|
|
void CloneTable::saveLoadWithSerializer(Common::Serializer &s) {
|
|
|
|
sync_Table<CloneTable>(s, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NodeTable::saveLoadWithSerializer(Common::Serializer &s) {
|
|
|
|
sync_Table<NodeTable>(s, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ListTable::saveLoadWithSerializer(Common::Serializer &s) {
|
|
|
|
sync_Table<ListTable>(s, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HunkTable::saveLoadWithSerializer(Common::Serializer &s) {
|
2009-10-13 18:54:20 +00:00
|
|
|
// Do nothing, hunk tables are not actually saved nor loaded.
|
2009-05-19 00:34:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Script::saveLoadWithSerializer(Common::Serializer &s) {
|
2009-09-16 23:32:27 +00:00
|
|
|
s.syncAsSint32LE(_nr);
|
2010-06-22 08:57:25 +00:00
|
|
|
|
|
|
|
if (s.isLoading())
|
|
|
|
init(_nr, g_sci->getResMan());
|
|
|
|
s.skip(4, VER(9), VER(22)); // OBSOLETE: Used to be _bufSize
|
|
|
|
s.skip(4, VER(9), VER(22)); // OBSOLETE: Used to be _scriptSize
|
|
|
|
s.skip(4, VER(9), VER(22)); // OBSOLETE: Used to be _heapSize
|
2009-02-24 02:59:50 +00:00
|
|
|
|
2009-09-21 21:38:43 +00:00
|
|
|
if (s.getVersion() <= 10) {
|
|
|
|
assert((s.isLoading()));
|
|
|
|
// OBSOLETE: Skip over the old _objIndices data when loading
|
|
|
|
s.skip(4); // base_value
|
|
|
|
while (true) {
|
|
|
|
uint32 key = 0;
|
|
|
|
s.syncAsSint32LE(key);
|
|
|
|
if (key == INTMAPPER_MAGIC_KEY)
|
|
|
|
break;
|
|
|
|
s.skip(4); // idx
|
|
|
|
}
|
2009-02-24 02:59:50 +00:00
|
|
|
}
|
2009-05-03 09:25:15 +00:00
|
|
|
|
2010-05-30 21:49:07 +00:00
|
|
|
s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numExports
|
|
|
|
s.skip(4, VER(9), VER(19)); // OBSOLETE: Used to be _numSynonyms
|
2009-09-16 23:32:27 +00:00
|
|
|
s.syncAsSint32LE(_lockers);
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2009-09-21 21:38:43 +00:00
|
|
|
// Sync _objects. This is a hashmap, and we use the following on disk format:
|
|
|
|
// First we store the number of items in the hashmap, then we store each
|
|
|
|
// object (which is an 'Object' instance). For loading, we take advantage
|
|
|
|
// of the fact that the key of each Object obj is just obj._pos.offset !
|
|
|
|
// By "chance" this format is identical to the format used to sync Common::Array<>,
|
|
|
|
// hence we can still old savegames with identical code :).
|
|
|
|
|
|
|
|
uint numObjs = _objects.size();
|
|
|
|
s.syncAsUint32LE(numObjs);
|
|
|
|
|
|
|
|
if (s.isLoading()) {
|
|
|
|
_objects.clear();
|
|
|
|
Object tmp;
|
|
|
|
for (uint i = 0; i < numObjs; ++i) {
|
|
|
|
syncWithSerializer<Object>(s, tmp);
|
2009-10-10 15:58:51 +00:00
|
|
|
_objects[tmp.getPos().offset] = tmp;
|
2009-09-21 21:38:43 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ObjMap::iterator it;
|
|
|
|
const ObjMap::iterator end = _objects.end();
|
|
|
|
for (it = _objects.begin(); it != end; ++it) {
|
|
|
|
syncWithSerializer<Object>(s, it->_value);
|
|
|
|
}
|
|
|
|
}
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2010-06-13 22:15:30 +00:00
|
|
|
s.skip(4, VER(9), VER(20)); // OBSOLETE: Used to be _localsOffset
|
2009-09-16 23:32:27 +00:00
|
|
|
s.syncAsSint32LE(_localsSegment);
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2009-05-19 00:34:10 +00:00
|
|
|
s.syncAsSint32LE(_markedAsDeleted);
|
2009-02-24 02:59:50 +00:00
|
|
|
}
|
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
static void sync_SystemString(Common::Serializer &s, SystemString &obj) {
|
2009-09-22 00:36:05 +00:00
|
|
|
s.syncString(obj._name);
|
2009-09-22 01:08:42 +00:00
|
|
|
s.syncAsSint32LE(obj._maxSize);
|
2009-05-20 17:53:31 +00:00
|
|
|
|
2009-09-22 01:08:42 +00:00
|
|
|
// Sync obj._value. We cannot use syncCStr as we must make sure that
|
|
|
|
// the allocated buffer has the correct size, i.e., obj._maxSize
|
|
|
|
Common::String tmp;
|
|
|
|
if (s.isSaving() && obj._value)
|
|
|
|
tmp = obj._value;
|
|
|
|
s.syncString(tmp);
|
|
|
|
if (s.isLoading()) {
|
2010-05-11 16:16:49 +00:00
|
|
|
if (!obj._maxSize) {
|
|
|
|
obj._value = NULL;
|
|
|
|
} else {
|
|
|
|
//free(*str);
|
|
|
|
obj._value = (char *)calloc(obj._maxSize, sizeof(char));
|
|
|
|
strncpy(obj._value, tmp.c_str(), obj._maxSize);
|
|
|
|
}
|
2009-09-22 01:08:42 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2009-05-19 00:34:10 +00:00
|
|
|
void SystemStrings::saveLoadWithSerializer(Common::Serializer &s) {
|
2009-03-15 20:31:29 +00:00
|
|
|
for (int i = 0; i < SYS_STRINGS_MAX; ++i)
|
2009-09-22 01:08:42 +00:00
|
|
|
sync_SystemString(s, _strings[i]);
|
2009-03-15 20:31:29 +00:00
|
|
|
}
|
|
|
|
|
2009-05-19 00:34:10 +00:00
|
|
|
void DynMem::saveLoadWithSerializer(Common::Serializer &s) {
|
|
|
|
s.syncAsSint32LE(_size);
|
2009-09-14 22:34:53 +00:00
|
|
|
s.syncString(_description);
|
2009-05-19 00:34:10 +00:00
|
|
|
if (!_buf && _size) {
|
|
|
|
_buf = (byte *)calloc(_size, 1);
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-05-19 00:34:10 +00:00
|
|
|
if (_size)
|
|
|
|
s.syncBytes(_buf, _size);
|
2009-03-15 20:31:29 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-05-19 00:34:10 +00:00
|
|
|
void DataStack::saveLoadWithSerializer(Common::Serializer &s) {
|
2009-09-22 00:35:46 +00:00
|
|
|
s.syncAsUint32LE(_capacity);
|
2009-05-11 13:32:00 +00:00
|
|
|
if (s.isLoading()) {
|
2010-06-06 23:00:33 +00:00
|
|
|
free(_entries);
|
2009-09-22 00:35:46 +00:00
|
|
|
_entries = (reg_t *)calloc(_capacity, sizeof(reg_t));
|
2009-05-11 13:32:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
#pragma mark -
|
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-12-25 13:18:48 +00:00
|
|
|
static void sync_songlib(Common::Serializer &s, SongLibrary &obj) {
|
2009-03-15 20:31:29 +00:00
|
|
|
int songcount = 0;
|
|
|
|
if (s.isSaving())
|
2009-06-07 17:06:51 +00:00
|
|
|
songcount = obj.countSongs();
|
2009-03-15 20:31:29 +00:00
|
|
|
s.syncAsUint32LE(songcount);
|
2009-05-20 17:53:31 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
if (s.isLoading()) {
|
2009-06-07 17:07:25 +00:00
|
|
|
obj._lib = 0;
|
2009-03-15 20:31:29 +00:00
|
|
|
while (songcount--) {
|
2009-10-17 17:59:09 +00:00
|
|
|
Song *newsong = new Song;
|
2009-12-25 13:18:48 +00:00
|
|
|
syncSong(s, *newsong);
|
2009-06-07 17:06:51 +00:00
|
|
|
obj.addSong(newsong);
|
2009-02-20 20:31:08 +00:00
|
|
|
}
|
2009-03-15 20:31:29 +00:00
|
|
|
} else {
|
2009-06-07 17:07:25 +00:00
|
|
|
Song *seeker = obj._lib;
|
2009-03-15 20:31:29 +00:00
|
|
|
while (seeker) {
|
2009-06-07 17:06:32 +00:00
|
|
|
seeker->_restoreTime = seeker->_it->getTimepos();
|
2009-12-25 13:18:48 +00:00
|
|
|
syncSong(s, *seeker);
|
2009-06-07 17:06:32 +00:00
|
|
|
seeker = seeker->_next;
|
2009-02-20 20:31:08 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-15 20:31:29 +00:00
|
|
|
}
|
2009-12-27 12:21:12 +00:00
|
|
|
#else
|
2009-12-27 11:43:34 +00:00
|
|
|
void SciMusic::saveLoadWithSerializer(Common::Serializer &s) {
|
2009-12-26 00:22:21 +00:00
|
|
|
// Sync song lib data. When loading, the actual song lib will be initialized
|
|
|
|
// afterwards in gamestate_restore()
|
2009-12-27 23:46:11 +00:00
|
|
|
Common::StackLock lock(_mutex);
|
2009-12-27 11:43:34 +00:00
|
|
|
|
2009-12-25 13:18:48 +00:00
|
|
|
int songcount = 0;
|
2009-12-27 14:11:26 +00:00
|
|
|
byte masterVolume = soundGetMasterVolume();
|
2010-01-22 12:26:12 +00:00
|
|
|
byte reverb = _pMidiDrv->getReverb();
|
2009-12-27 14:11:26 +00:00
|
|
|
|
|
|
|
if (s.isSaving()) {
|
|
|
|
s.syncAsByte(_soundOn);
|
|
|
|
s.syncAsByte(masterVolume);
|
2010-01-22 12:26:12 +00:00
|
|
|
s.syncAsByte(reverb, VER(17));
|
2009-12-27 14:11:26 +00:00
|
|
|
} else if (s.isLoading()) {
|
2010-01-01 14:22:07 +00:00
|
|
|
if (s.getVersion() >= 15) {
|
2009-12-27 14:11:26 +00:00
|
|
|
s.syncAsByte(_soundOn);
|
|
|
|
s.syncAsByte(masterVolume);
|
2010-01-22 12:26:12 +00:00
|
|
|
reverb = 0;
|
|
|
|
s.syncAsByte(reverb, VER(17));
|
2009-12-27 14:11:26 +00:00
|
|
|
} else {
|
|
|
|
_soundOn = true;
|
|
|
|
masterVolume = 15;
|
2010-01-22 12:26:12 +00:00
|
|
|
reverb = 0;
|
2009-12-27 14:11:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
soundSetSoundOn(_soundOn);
|
|
|
|
soundSetMasterVolume(masterVolume);
|
2010-01-22 12:26:12 +00:00
|
|
|
setReverb(reverb);
|
2009-12-27 14:11:26 +00:00
|
|
|
}
|
|
|
|
|
2009-12-25 13:18:48 +00:00
|
|
|
if (s.isSaving())
|
2009-12-27 11:43:34 +00:00
|
|
|
songcount = _playList.size();
|
2009-12-25 13:18:48 +00:00
|
|
|
s.syncAsUint32LE(songcount);
|
2009-12-26 00:22:21 +00:00
|
|
|
|
2009-12-25 13:18:48 +00:00
|
|
|
if (s.isLoading()) {
|
2009-12-27 23:46:11 +00:00
|
|
|
clearPlayList();
|
2009-12-25 13:18:48 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < songcount; i++) {
|
|
|
|
MusicEntry *curSong = new MusicEntry();
|
2009-12-28 21:03:13 +00:00
|
|
|
curSong->saveLoadWithSerializer(s);
|
2009-12-27 11:43:34 +00:00
|
|
|
_playList.push_back(curSong);
|
2009-12-25 13:18:48 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < songcount; i++) {
|
2009-12-28 21:03:13 +00:00
|
|
|
_playList[i]->saveLoadWithSerializer(s);
|
2009-12-25 13:18:48 +00:00
|
|
|
}
|
|
|
|
}
|
2009-12-27 12:12:14 +00:00
|
|
|
}
|
2009-12-27 12:21:12 +00:00
|
|
|
#endif
|
2009-03-15 20:31:29 +00:00
|
|
|
|
2010-06-15 07:20:53 +00:00
|
|
|
void SoundCommandParser::syncPlayList(Common::Serializer &s) {
|
|
|
|
#ifndef USE_OLD_MUSIC_FUNCTIONS
|
|
|
|
_music->saveLoadWithSerializer(s);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void SoundCommandParser::reconstructPlayList(int savegame_version) {
|
|
|
|
#ifndef USE_OLD_MUSIC_FUNCTIONS
|
|
|
|
Common::StackLock lock(_music->_mutex);
|
|
|
|
|
|
|
|
const MusicList::iterator end = _music->getPlayListEnd();
|
|
|
|
for (MusicList::iterator i = _music->getPlayListStart(); i != end; ++i) {
|
|
|
|
if ((*i)->resourceId && _resMan->testResource(ResourceId(kResourceTypeSound, (*i)->resourceId))) {
|
|
|
|
(*i)->soundRes = new SoundResource((*i)->resourceId, _resMan, _soundVersion);
|
|
|
|
_music->soundInitSnd(*i);
|
|
|
|
} else {
|
|
|
|
(*i)->soundRes = 0;
|
|
|
|
}
|
|
|
|
if ((*i)->status == kSoundPlaying) {
|
|
|
|
if (savegame_version < 14) {
|
|
|
|
(*i)->dataInc = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(dataInc));
|
|
|
|
(*i)->signal = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(signal));
|
|
|
|
|
|
|
|
if (_soundVersion >= SCI_VERSION_1_LATE)
|
|
|
|
(*i)->volume = readSelectorValue(_segMan, (*i)->soundObj, SELECTOR(vol));
|
|
|
|
}
|
|
|
|
|
|
|
|
cmdPlaySound((*i)->soundObj, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2010-01-30 02:03:59 +00:00
|
|
|
#ifdef ENABLE_SCI32
|
|
|
|
void ArrayTable::saveLoadWithSerializer(Common::Serializer &ser) {
|
|
|
|
if (ser.getVersion() < 18)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sync_Table<ArrayTable>(ser, *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void StringTable::saveLoadWithSerializer(Common::Serializer &ser) {
|
|
|
|
if (ser.getVersion() < 18)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sync_Table<StringTable>(ser, *this);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-06-15 07:20:53 +00:00
|
|
|
void SegManager::reconstructStack(EngineState *s) {
|
|
|
|
DataStack *stack = (DataStack *)(_heap[findSegmentByType(SEG_TYPE_STACK)]);
|
|
|
|
s->stack_base = stack->_entries;
|
|
|
|
s->stack_top = s->stack_base + stack->_capacity;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Move this function to a more appropriate place, such as vm.cpp or script.cpp
|
2009-10-08 22:03:55 +00:00
|
|
|
void SegManager::reconstructScripts(EngineState *s) {
|
2009-09-22 09:00:32 +00:00
|
|
|
uint i;
|
2009-08-17 05:55:21 +00:00
|
|
|
|
2009-10-08 22:03:55 +00:00
|
|
|
for (i = 0; i < _heap.size(); i++) {
|
2010-05-31 00:04:38 +00:00
|
|
|
if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
|
2009-10-08 22:03:55 +00:00
|
|
|
continue;
|
|
|
|
|
2010-05-31 00:04:38 +00:00
|
|
|
Script *scr = (Script *)_heap[i];
|
2010-05-30 16:38:08 +00:00
|
|
|
scr->load(g_sci->getResMan());
|
2009-10-08 22:03:55 +00:00
|
|
|
scr->_localsBlock = (scr->_localsSegment == 0) ? NULL : (LocalVariables *)(_heap[scr->_localsSegment]);
|
|
|
|
|
2010-05-31 11:25:59 +00:00
|
|
|
for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it)
|
|
|
|
it->_value._baseObj = scr->_buf + it->_value.getPos().offset;
|
2009-02-20 19:08:38 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-10-08 22:03:55 +00:00
|
|
|
for (i = 0; i < _heap.size(); i++) {
|
2010-05-31 00:04:38 +00:00
|
|
|
if (!_heap[i] || _heap[i]->getType() != SEG_TYPE_SCRIPT)
|
2009-10-08 22:03:55 +00:00
|
|
|
continue;
|
|
|
|
|
2010-05-31 00:04:38 +00:00
|
|
|
Script *scr = (Script *)_heap[i];
|
2009-10-08 22:03:55 +00:00
|
|
|
|
2010-05-31 11:25:59 +00:00
|
|
|
for (ObjMap::iterator it = scr->_objects.begin(); it != scr->_objects.end(); ++it) {
|
|
|
|
reg_t addr = it->_value.getPos();
|
|
|
|
Object *obj = scr->scriptObjInit(addr, false);
|
2009-10-08 22:03:55 +00:00
|
|
|
|
2010-05-31 11:25:59 +00:00
|
|
|
if (getSciVersion() < SCI_VERSION_1_1) {
|
2010-06-22 08:57:25 +00:00
|
|
|
if (!obj->isFreed()) {
|
|
|
|
if (!obj->initBaseObject(this, addr, false)) {
|
|
|
|
warning("Failed to locate base object for object at %04X:%04X; skipping", PRINT_REG(addr));
|
|
|
|
//scr->scriptObjRemove(addr);
|
|
|
|
}
|
2010-05-31 11:25:59 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
}
|
2009-02-20 19:08:38 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-02-20 19:08:38 +00:00
|
|
|
|
2010-06-15 07:20:53 +00:00
|
|
|
void SegManager::reconstructClones() {
|
|
|
|
for (uint i = 0; i < _heap.size(); i++) {
|
|
|
|
SegmentObj *mobj = _heap[i];
|
|
|
|
if (mobj && mobj->getType() == SEG_TYPE_CLONES) {
|
|
|
|
CloneTable *ct = (CloneTable *)mobj;
|
|
|
|
|
|
|
|
for (uint j = 0; j < ct->_table.size(); j++) {
|
|
|
|
// Check if the clone entry is used
|
|
|
|
uint entryNum = (uint)ct->first_free;
|
|
|
|
bool isUsed = true;
|
|
|
|
while (entryNum != ((uint) CloneTable::HEAPENTRY_INVALID)) {
|
|
|
|
if (entryNum == j) {
|
|
|
|
isUsed = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
entryNum = ct->_table[entryNum].next_free;
|
|
|
|
}
|
2010-06-08 13:16:30 +00:00
|
|
|
|
2010-06-15 07:20:53 +00:00
|
|
|
if (!isUsed)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
CloneTable::Entry &seeker = ct->_table[j];
|
|
|
|
const Object *baseObj = getObject(seeker.getSpeciesSelector());
|
|
|
|
seeker.cloneFromObject(baseObj);
|
|
|
|
if (!baseObj)
|
2010-06-17 23:50:28 +00:00
|
|
|
error("Clone entry without a base class: %d", j);
|
2010-06-15 07:20:53 +00:00
|
|
|
} // end for
|
|
|
|
} // end if
|
|
|
|
} // end for
|
2010-06-08 13:16:30 +00:00
|
|
|
}
|
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-02-21 10:47:56 +00:00
|
|
|
static void reconstruct_sounds(EngineState *s) {
|
2009-06-07 17:06:32 +00:00
|
|
|
Song *seeker;
|
2009-08-16 19:18:19 +00:00
|
|
|
SongIteratorType it_type;
|
|
|
|
|
2009-09-23 10:55:35 +00:00
|
|
|
if (getSciVersion() > SCI_VERSION_01)
|
2009-08-16 19:18:19 +00:00
|
|
|
it_type = SCI_SONG_ITERATOR_TYPE_SCI1;
|
|
|
|
else
|
|
|
|
it_type = SCI_SONG_ITERATOR_TYPE_SCI0;
|
2009-02-20 19:08:38 +00:00
|
|
|
|
2009-06-07 17:07:25 +00:00
|
|
|
seeker = s->_sound._songlib._lib;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-20 19:08:38 +00:00
|
|
|
while (seeker) {
|
2009-12-20 13:28:23 +00:00
|
|
|
SongIterator *base, *ff = 0;
|
2009-02-20 19:08:38 +00:00
|
|
|
int oldstatus;
|
2009-03-10 02:42:22 +00:00
|
|
|
SongIterator::Message msg;
|
2009-02-20 19:08:38 +00:00
|
|
|
|
2010-02-13 17:44:19 +00:00
|
|
|
base = ff = build_iterator(g_sci->getResMan(), seeker->_resourceNum, it_type, seeker->_handle);
|
2009-06-07 17:06:32 +00:00
|
|
|
if (seeker->_restoreBehavior == RESTORE_BEHAVIOR_CONTINUE)
|
|
|
|
ff = new_fast_forward_iterator(base, seeker->_restoreTime);
|
2009-03-06 07:25:48 +00:00
|
|
|
ff->init();
|
2009-02-20 19:08:38 +00:00
|
|
|
|
2009-06-07 17:06:32 +00:00
|
|
|
msg = SongIterator::Message(seeker->_handle, SIMSG_SET_LOOPS(seeker->_loops));
|
2009-02-20 19:08:38 +00:00
|
|
|
songit_handle_message(&ff, msg);
|
2009-06-07 17:06:32 +00:00
|
|
|
msg = SongIterator::Message(seeker->_handle, SIMSG_SET_HOLD(seeker->_hold));
|
2009-02-20 19:08:38 +00:00
|
|
|
songit_handle_message(&ff, msg);
|
|
|
|
|
2009-06-07 17:06:32 +00:00
|
|
|
oldstatus = seeker->_status;
|
|
|
|
seeker->_status = SOUND_STATUS_STOPPED;
|
|
|
|
seeker->_it = ff;
|
|
|
|
s->_sound.sfx_song_set_status(seeker->_handle, oldstatus);
|
|
|
|
seeker = seeker->_next;
|
2009-02-20 19:08:38 +00:00
|
|
|
}
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-15 07:25:09 +00:00
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
2010-06-15 08:39:03 +00:00
|
|
|
bool gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename, const char *version) {
|
2010-06-15 07:25:09 +00:00
|
|
|
TimeDate curTime;
|
|
|
|
g_system->getTimeAndDate(curTime);
|
|
|
|
|
|
|
|
SavegameMetadata meta;
|
|
|
|
meta.savegame_version = CURRENT_SAVEGAME_VERSION;
|
|
|
|
meta.savegame_name = savename;
|
|
|
|
meta.game_version = version;
|
|
|
|
meta.savegame_date = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
|
|
|
|
meta.savegame_time = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
|
|
|
|
|
2010-06-15 08:25:51 +00:00
|
|
|
Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false);
|
|
|
|
meta.script0_size = script0->size;
|
|
|
|
meta.game_object_offset = g_sci->getGameObject().offset;
|
|
|
|
|
2010-06-15 07:25:09 +00:00
|
|
|
if (s->executionStackBase) {
|
|
|
|
warning("Cannot save from below kernel function");
|
2010-06-15 08:39:03 +00:00
|
|
|
return false;
|
2010-06-15 07:25:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::Serializer ser(0, fh);
|
|
|
|
sync_SavegameMetadata(ser, meta);
|
|
|
|
Graphics::saveThumbnail(*fh);
|
|
|
|
s->saveLoadWithSerializer(ser); // FIXME: Error handling?
|
|
|
|
|
2010-06-15 08:39:03 +00:00
|
|
|
return true;
|
2010-06-15 07:25:09 +00:00
|
|
|
}
|
|
|
|
|
2010-01-31 01:26:06 +00:00
|
|
|
void gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-06-07 17:06:32 +00:00
|
|
|
SongLibrary temp;
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-28 11:07:36 +00:00
|
|
|
SavegameMetadata meta;
|
2009-02-20 23:41:15 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
Common::Serializer ser(fh, 0);
|
|
|
|
sync_SavegameMetadata(ser, meta);
|
2009-02-27 19:50:22 +00:00
|
|
|
|
2010-01-31 01:26:06 +00:00
|
|
|
if (fh->eos()) {
|
|
|
|
s->r_acc = make_reg(0, 1); // signal failure
|
|
|
|
return;
|
|
|
|
}
|
2009-02-28 11:07:36 +00:00
|
|
|
|
2009-03-17 08:03:42 +00:00
|
|
|
if ((meta.savegame_version < MINIMUM_SAVEGAME_VERSION) ||
|
|
|
|
(meta.savegame_version > CURRENT_SAVEGAME_VERSION)) {
|
2010-06-15 08:25:51 +00:00
|
|
|
/*
|
2009-03-17 08:03:42 +00:00
|
|
|
if (meta.savegame_version < MINIMUM_SAVEGAME_VERSION)
|
2010-06-15 08:25:51 +00:00
|
|
|
warning("Old savegame version detected, unable to load it");
|
2009-02-20 23:41:15 +00:00
|
|
|
else
|
2010-06-15 08:25:51 +00:00
|
|
|
warning("Savegame version is %d, maximum supported is %0d", meta.savegame_version, CURRENT_SAVEGAME_VERSION);
|
|
|
|
*/
|
|
|
|
|
|
|
|
GUI::MessageDialog dialog("The format of this saved game is obsolete, unable to load it", "OK");
|
|
|
|
dialog.runModal();
|
2009-02-20 23:41:15 +00:00
|
|
|
|
2010-01-31 01:26:06 +00:00
|
|
|
s->r_acc = make_reg(0, 1); // signal failure
|
|
|
|
return;
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
|
|
|
|
2010-06-15 08:25:51 +00:00
|
|
|
if (meta.game_object_offset > 0 && meta.script0_size > 0) {
|
|
|
|
Resource *script0 = g_sci->getResMan()->findResource(ResourceId(kResourceTypeScript, 0), false);
|
|
|
|
if (script0->size != meta.script0_size || g_sci->getGameObject().offset != meta.game_object_offset) {
|
|
|
|
//warning("This saved game was created with a different version of the game, unable to load it");
|
|
|
|
|
|
|
|
GUI::MessageDialog dialog("This saved game was created with a different version of the game, unable to load it", "OK");
|
|
|
|
dialog.runModal();
|
|
|
|
|
|
|
|
s->r_acc = make_reg(0, 1); // signal failure
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-11 15:51:43 +00:00
|
|
|
if (meta.savegame_version >= 12) {
|
|
|
|
// We don't need the thumbnail here, so just read it and discard it
|
|
|
|
Graphics::Surface *thumbnail = new Graphics::Surface();
|
|
|
|
assert(thumbnail);
|
|
|
|
Graphics::loadThumbnail(*fh, *thumbnail);
|
|
|
|
delete thumbnail;
|
|
|
|
thumbnail = 0;
|
|
|
|
}
|
|
|
|
|
2010-06-01 15:48:17 +00:00
|
|
|
s->reset(true);
|
|
|
|
s->saveLoadWithSerializer(ser); // FIXME: Error handling?
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2009-05-28 22:48:15 +00:00
|
|
|
s->_sound.sfx_exit();
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-20 19:08:38 +00:00
|
|
|
// Now copy all current state information
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2010-06-01 15:48:17 +00:00
|
|
|
temp = s->_sound._songlib;
|
|
|
|
s->_sound.sfx_init(g_sci->getResMan(), s->sfx_init_flags, g_sci->_features->detectDoSoundType());
|
|
|
|
s->sfx_init_flags = s->sfx_init_flags;
|
|
|
|
s->_sound._songlib.freeSounds();
|
|
|
|
s->_sound._songlib = temp;
|
2010-06-09 14:06:16 +00:00
|
|
|
s->_soundCmd->updateSfxState(&s->_sound);
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2010-06-08 13:16:30 +00:00
|
|
|
s->_segMan->reconstructStack(s);
|
2010-06-01 15:48:17 +00:00
|
|
|
s->_segMan->reconstructScripts(s);
|
|
|
|
s->_segMan->reconstructClones();
|
2010-06-09 09:17:48 +00:00
|
|
|
s->initGlobals();
|
2010-06-10 11:43:20 +00:00
|
|
|
s->gcCountDown = GC_INTERVAL - 1;
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-02-20 19:08:38 +00:00
|
|
|
// Time state:
|
2010-06-10 11:18:10 +00:00
|
|
|
s->lastWaitTime = g_system->getMillis();
|
2010-06-10 11:43:20 +00:00
|
|
|
s->gameStartTime = g_system->getMillis();
|
2010-06-14 08:36:52 +00:00
|
|
|
s->_screenUpdateTime = g_system->getMillis();
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-12-20 13:28:23 +00:00
|
|
|
#ifdef USE_OLD_MUSIC_FUNCTIONS
|
2010-06-01 15:48:17 +00:00
|
|
|
s->_sound._it = NULL;
|
|
|
|
s->_sound._flags = s->_sound._flags;
|
|
|
|
s->_sound._song = NULL;
|
|
|
|
s->_sound._suspended = s->_sound._suspended;
|
|
|
|
reconstruct_sounds(s);
|
2009-12-25 13:18:48 +00:00
|
|
|
#else
|
2010-06-01 15:48:17 +00:00
|
|
|
s->_soundCmd->reconstructPlayList(meta.savegame_version);
|
2009-12-20 13:28:23 +00:00
|
|
|
#endif
|
2009-02-15 06:10:59 +00:00
|
|
|
|
2009-05-26 11:33:18 +00:00
|
|
|
// Message state:
|
2010-06-01 15:48:17 +00:00
|
|
|
s->_msgState = new MessageState(s->_segMan);
|
2009-05-26 11:33:18 +00:00
|
|
|
|
2010-06-15 13:34:40 +00:00
|
|
|
g_sci->initGraphics();
|
2009-10-08 07:57:26 +00:00
|
|
|
|
2010-06-08 21:05:46 +00:00
|
|
|
s->abortScriptProcessing = kAbortLoadGame;
|
2010-06-15 09:11:26 +00:00
|
|
|
s->shrinkStackToBase();
|
2009-02-15 06:10:59 +00:00
|
|
|
}
|
2009-02-20 23:41:15 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
bool get_savegame_metadata(Common::SeekableReadStream *stream, SavegameMetadata *meta) {
|
|
|
|
assert(stream);
|
|
|
|
assert(meta);
|
|
|
|
|
|
|
|
Common::Serializer ser(stream, 0);
|
|
|
|
sync_SavegameMetadata(ser, *meta);
|
2009-02-20 23:41:15 +00:00
|
|
|
|
2009-03-15 20:31:29 +00:00
|
|
|
if (stream->eos())
|
2009-02-20 23:41:15 +00:00
|
|
|
return false;
|
|
|
|
|
2009-03-17 08:03:42 +00:00
|
|
|
if ((meta->savegame_version < MINIMUM_SAVEGAME_VERSION) ||
|
|
|
|
(meta->savegame_version > CURRENT_SAVEGAME_VERSION)) {
|
|
|
|
if (meta->savegame_version < MINIMUM_SAVEGAME_VERSION)
|
2009-07-06 10:39:22 +00:00
|
|
|
warning("Old savegame version detected- can't load");
|
2009-02-20 23:41:15 +00:00
|
|
|
else
|
2009-07-06 10:39:22 +00:00
|
|
|
warning("Savegame version is %d- maximum supported is %0d", meta->savegame_version, CURRENT_SAVEGAME_VERSION);
|
2009-02-20 23:41:15 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2009-02-21 10:23:36 +00:00
|
|
|
} // End of namespace Sci
|