[Scummvm-git-logs] scummvm master -> 2e061d95c5aeed11b20999baa62418ef3c53141c

sev- sev at scummvm.org
Wed Jan 31 17:58:06 CET 2018


This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
157ee95f64 COMMON: Add support for array serialization to Serializer
9916b26383 SCUMM: Replace UB-triggering serialization code with Common::Serializer
2e061d95c5 COMMON: Move VER macro for serializer into common code


Commit: 157ee95f64380215c3e6b1fed53be99607479582
    https://github.com/scummvm/scummvm/commit/157ee95f64380215c3e6b1fed53be99607479582
Author: Colin Snover (github.com at zetafleet.com)
Date: 2018-01-31T17:58:01+01:00

Commit Message:
COMMON: Add support for array serialization to Serializer

SCUMM engine does quite a bit of direct array serialization.

Changed paths:
    common/serializer.h


diff --git a/common/serializer.h b/common/serializer.h
index 2def17c..09f36d0 100644
--- a/common/serializer.h
+++ b/common/serializer.h
@@ -43,6 +43,11 @@ namespace Common {
 		_bytesSynced += SIZE; \
 	}
 
+#define SYNC_PRIMITIVE(suffix) \
+	template <typename T> \
+	static inline void suffix(Serializer &s, T &value) { \
+		s.syncAs##suffix(value); \
+	}
 
 /**
  * This class allows syncing / serializing data (primarily game savestates)
@@ -67,6 +72,17 @@ public:
 	typedef uint32 Version;
 	static const Version kLastVersion = 0xFFFFFFFF;
 
+	SYNC_PRIMITIVE(Uint32LE)
+	SYNC_PRIMITIVE(Uint32BE)
+	SYNC_PRIMITIVE(Sint32LE)
+	SYNC_PRIMITIVE(Sint32BE)
+	SYNC_PRIMITIVE(Uint16LE)
+	SYNC_PRIMITIVE(Uint16BE)
+	SYNC_PRIMITIVE(Sint16LE)
+	SYNC_PRIMITIVE(Sint16BE)
+	SYNC_PRIMITIVE(Byte)
+	SYNC_PRIMITIVE(SByte)
+
 protected:
 	SeekableReadStream *_loadStream;
 	WriteStream *_saveStream;
@@ -94,6 +110,7 @@ public:
 	// in the line "syncAsUint32LE(_version);" of
 	// "bool syncVersion(Version currentVersion)".
 	SYNC_AS(Byte, byte, 1)
+	SYNC_AS(SByte, int8, 1)
 
 	SYNC_AS(Uint16LE, uint16, 2)
 	SYNC_AS(Uint16BE, uint16, 2)
@@ -237,8 +254,18 @@ public:
 		}
 	}
 
+	template <typename T>
+	void syncArray(T *arr, size_t entries, void (*serializer)(Serializer &, T &), Version minVersion = 0, Version maxVersion = kLastVersion) {
+		if (_version < minVersion || _version > maxVersion)
+			return;
+
+		for (size_t i = 0; i < entries; ++i) {
+			serializer(*this, arr[i]);
+		}
+	}
 };
 
+#undef SYNC_PRIMITIVE
 #undef SYNC_AS
 
 


Commit: 9916b263831f20e5841275051a8ed014de1f24eb
    https://github.com/scummvm/scummvm/commit/9916b263831f20e5841275051a8ed014de1f24eb
Author: Colin Snover (github.com at zetafleet.com)
Date: 2018-01-31T17:58:01+01:00

Commit Message:
SCUMM: Replace UB-triggering serialization code with Common::Serializer

Fixes Trac#10342.

Changed paths:
    engines/scumm/actor.cpp
    engines/scumm/actor.h
    engines/scumm/charset.cpp
    engines/scumm/charset.h
    engines/scumm/he/intern_he.h
    engines/scumm/he/sprite_he.cpp
    engines/scumm/he/sprite_he.h
    engines/scumm/imuse/imuse.cpp
    engines/scumm/imuse/imuse.h
    engines/scumm/imuse/imuse_internal.h
    engines/scumm/imuse/imuse_part.cpp
    engines/scumm/imuse/imuse_player.cpp
    engines/scumm/imuse/instrument.cpp
    engines/scumm/imuse/instrument.h
    engines/scumm/imuse_digi/dimuse.cpp
    engines/scumm/imuse_digi/dimuse.h
    engines/scumm/music.h
    engines/scumm/players/player_ad.cpp
    engines/scumm/players/player_ad.h
    engines/scumm/players/player_mac.cpp
    engines/scumm/players/player_mac.h
    engines/scumm/players/player_towns.cpp
    engines/scumm/players/player_towns.h
    engines/scumm/saveload.cpp
    engines/scumm/saveload.h
    engines/scumm/scumm.h
    engines/scumm/scumm_v0.h
    engines/scumm/scumm_v2.h
    engines/scumm/scumm_v5.h
    engines/scumm/scumm_v7.h
    engines/scumm/sound.cpp
    engines/scumm/sound.h


diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index 66a7d90..c00e38e 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -3437,43 +3437,38 @@ void Actor_v0::actorSetWalkTo() {
 	}
 }
 
-void Actor_v0::saveLoadWithSerializer(Serializer *ser) {
-	Actor::saveLoadWithSerializer(ser);
-
-	static const SaveLoadEntry actorEntries[] = {
-		MKLINE(Actor_v0, _costCommand, sleByte, VER(84)),
-		MK_OBSOLETE(Actor_v0, _costFrame, sleByte, VER(84), VER(89)),
-		MKLINE(Actor_v0, _miscflags, sleByte, VER(84)),
-		MKLINE(Actor_v0, _speaking, sleByte, VER(84)),
-		MK_OBSOLETE(Actor_v0, _speakingPrev, sleByte, VER(84), VER(89)),
-		MK_OBSOLETE(Actor_v0, _limbTemp, sleByte, VER(89), VER(89)),
-		MKLINE(Actor_v0, _animFrameRepeat, sleByte, VER(89)),
-		MKARRAY(Actor_v0, _limbFrameRepeatNew[0], sleInt8, 8, VER(89)),
-		MKARRAY(Actor_v0, _limbFrameRepeat[0], sleInt8, 8, VER(90)),
-		MKLINE(Actor_v0, _CurrentWalkTo.x, sleInt16, VER(97)),
-		MKLINE(Actor_v0, _CurrentWalkTo.y, sleInt16, VER(97)),
-		MKLINE(Actor_v0, _NewWalkTo.x, sleInt16, VER(97)),
-		MKLINE(Actor_v0, _NewWalkTo.y, sleInt16, VER(97)),
-		MKLINE(Actor_v0, _walkCountModulo, sleInt8, VER(97)),
-		MKLINE(Actor_v0, _newWalkBoxEntered, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkDirX, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkDirY, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkYCountGreaterThanXCount, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkXCount, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkXCountInc, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkYCount, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkYCountInc, sleByte, VER(97)),
-		MKLINE(Actor_v0, _walkMaxXYCountInc, sleByte, VER(97)),
-
-		MKARRAY(Actor_v0, _walkboxQueue[0], sleByte, 16, VER(98)),
-		MKLINE(Actor_v0, _walkboxQueueIndex, sleByte, VER(98)),
-		MKEND()
-	};
-
-	ser->saveLoadEntries(this, actorEntries);
+void Actor_v0::saveLoadWithSerializer(Common::Serializer &s) {
+	Actor::saveLoadWithSerializer(s);
+
+	s.syncAsByte(_costCommand, VER(84));
+	s.skip(1, VER(84), VER(89)); // _costFrame
+	s.syncAsByte(_miscflags, VER(84));
+	s.syncAsByte(_speaking, VER(84));
+	s.skip(1, VER(84), VER(89)); // _speakingPrev
+	s.skip(1, VER(89), VER(89)); // _limbTemp
+	s.syncAsByte(_animFrameRepeat, VER(89));
+	s.syncArray(_limbFrameRepeatNew, 8, Common::Serializer::SByte, VER(89));
+	s.syncArray(_limbFrameRepeat, 8, Common::Serializer::SByte, VER(90));
+	s.syncAsSint16LE(_CurrentWalkTo.x, VER(97));
+	s.syncAsSint16LE(_CurrentWalkTo.y, VER(97));
+	s.syncAsSint16LE(_NewWalkTo.x, VER(97));
+	s.syncAsSint16LE(_NewWalkTo.y, VER(97));
+	s.syncAsSByte(_walkCountModulo, VER(97));
+	s.syncAsByte(_newWalkBoxEntered, VER(97));
+	s.syncAsByte(_walkDirX, VER(97));
+	s.syncAsByte(_walkDirY, VER(97));
+	s.syncAsByte(_walkYCountGreaterThanXCount, VER(97));
+	s.syncAsByte(_walkXCount, VER(97));
+	s.syncAsByte(_walkXCountInc, VER(97));
+	s.syncAsByte(_walkYCount, VER(97));
+	s.syncAsByte(_walkYCountInc, VER(97));
+	s.syncAsByte(_walkMaxXYCountInc, VER(97));
+
+	s.syncBytes(_walkboxQueue, 16, VER(98));
+	s.syncAsByte(_walkboxQueueIndex, VER(98));
 
 	// When loading, we need to ensure the limbs are restarted
-	if (ser->isLoading()) {
+	if (s.isLoading()) {
 
 		// valid costume command?
 		if (_costCommand != 0xFF) {
@@ -3498,124 +3493,119 @@ void Actor_v0::saveLoadWithSerializer(Serializer *ser) {
 	}
 }
 
-void Actor::saveLoadWithSerializer(Serializer *ser) {
-	static const SaveLoadEntry actorEntries[] = {
-		MKLINE(Actor, _pos.x, sleInt16, VER(8)),
-		MKLINE(Actor, _pos.y, sleInt16, VER(8)),
-		MKLINE(Actor, _heOffsX, sleInt16, VER(32)),
-		MKLINE(Actor, _heOffsY, sleInt16, VER(32)),
-		MKLINE(Actor, _top, sleInt16, VER(8)),
-		MKLINE(Actor, _bottom, sleInt16, VER(8)),
-		MKLINE(Actor, _elevation, sleInt16, VER(8)),
-		MKLINE(Actor, _width, sleUint16, VER(8)),
-		MKLINE(Actor, _facing, sleUint16, VER(8)),
-		MKLINE(Actor, _costume, sleUint16, VER(8)),
-		MKLINE(Actor, _room, sleByte, VER(8)),
-		MKLINE(Actor, _talkColor, sleByte, VER(8)),
-		MKLINE(Actor, _talkFrequency, sleInt16, VER(16)),
-		MKLINE(Actor, _talkPan, sleInt16, VER(24)),
-		MKLINE(Actor, _talkVolume, sleInt16, VER(29)),
-		MKLINE(Actor, _boxscale, sleUint16, VER(34)),
-		MKLINE(Actor, _scalex, sleByte, VER(8)),
-		MKLINE(Actor, _scaley, sleByte, VER(8)),
-		MKLINE(Actor, _charset, sleByte, VER(8)),
-
-		// Actor sound grew from 8 to 32 bytes and switched to uint16 in HE games
-		MKARRAY_OLD(Actor, _sound[0], sleByte, 8, VER(8), VER(36)),
-		MKARRAY_OLD(Actor, _sound[0], sleByte, 32, VER(37), VER(61)),
-		MKARRAY(Actor, _sound[0], sleUint16, 32, VER(62)),
-
-		// Actor animVariable grew from 8 to 27
-		MKARRAY_OLD(Actor, _animVariable[0], sleUint16, 8, VER(8), VER(40)),
-		MKARRAY(Actor, _animVariable[0], sleUint16, 27, VER(41)),
-
-		MKLINE(Actor, _targetFacing, sleUint16, VER(8)),
-		MKLINE(Actor, _moving, sleByte, VER(8)),
-		MKLINE(Actor, _ignoreBoxes, sleByte, VER(8)),
-		MKLINE(Actor, _forceClip, sleByte, VER(8)),
-		MKLINE(Actor, _initFrame, sleByte, VER(8)),
-		MKLINE(Actor, _walkFrame, sleByte, VER(8)),
-		MKLINE(Actor, _standFrame, sleByte, VER(8)),
-		MKLINE(Actor, _talkStartFrame, sleByte, VER(8)),
-		MKLINE(Actor, _talkStopFrame, sleByte, VER(8)),
-		MKLINE(Actor, _speedx, sleUint16, VER(8)),
-		MKLINE(Actor, _speedy, sleUint16, VER(8)),
-		MKLINE(Actor, _cost.animCounter, sleUint16, VER(8)),
-		MKLINE(Actor, _cost.soundCounter, sleByte, VER(8)),
-		MKLINE(Actor, _drawToBackBuf, sleByte, VER(32)),
-		MKLINE(Actor, _flip, sleByte, VER(32)),
-		MKLINE(Actor, _heSkipLimbs, sleByte, VER(32)),
-
-		// Actor palette grew from 64 to 256 bytes and switched to uint16 in HE games
-		MKARRAY_OLD(Actor, _palette[0], sleByte, 64, VER(8), VER(9)),
-		MKARRAY_OLD(Actor, _palette[0], sleByte, 256, VER(10), VER(79)),
-		MKARRAY(Actor, _palette[0], sleUint16, 256, VER(80)),
-
-		MK_OBSOLETE(Actor, _mask, sleByte, VER(8), VER(9)),
-		MKLINE(Actor, _shadowMode, sleByte, VER(8)),
-		MKLINE(Actor, _visible, sleByte, VER(8)),
-		MKLINE(Actor, _frame, sleByte, VER(8)),
-		MKLINE(Actor, _animSpeed, sleByte, VER(8)),
-		MKLINE(Actor, _animProgress, sleByte, VER(8)),
-		MKLINE(Actor, _walkbox, sleByte, VER(8)),
-		MKLINE(Actor, _needRedraw, sleByte, VER(8)),
-		MKLINE(Actor, _needBgReset, sleByte, VER(8)),
-		MKLINE(Actor, _costumeNeedsInit, sleByte, VER(8)),
-		MKLINE(Actor, _heCondMask, sleUint32, VER(38)),
-		MKLINE(Actor, _hePaletteNum, sleUint32, VER(59)),
-		MKLINE(Actor, _heXmapNum, sleUint32, VER(59)),
-
-		MKLINE(Actor, _talkPosY, sleInt16, VER(8)),
-		MKLINE(Actor, _talkPosX, sleInt16, VER(8)),
-		MKLINE(Actor, _ignoreTurns, sleByte, VER(8)),
-
-		// Actor layer switched to int32 in HE games
-		MKLINE_OLD(Actor, _layer, sleByte, VER(8), VER(57)),
-		MKLINE(Actor, _layer, sleInt32, VER(58)),
-
-		MKLINE(Actor, _talkScript, sleUint16, VER(8)),
-		MKLINE(Actor, _walkScript, sleUint16, VER(8)),
-
-		MKLINE(Actor, _walkdata.dest.x, sleInt16, VER(8)),
-		MKLINE(Actor, _walkdata.dest.y, sleInt16, VER(8)),
-		MKLINE(Actor, _walkdata.destbox, sleByte, VER(8)),
-		MKLINE(Actor, _walkdata.destdir, sleUint16, VER(8)),
-		MKLINE(Actor, _walkdata.curbox, sleByte, VER(8)),
-		MKLINE(Actor, _walkdata.cur.x, sleInt16, VER(8)),
-		MKLINE(Actor, _walkdata.cur.y, sleInt16, VER(8)),
-		MKLINE(Actor, _walkdata.next.x, sleInt16, VER(8)),
-		MKLINE(Actor, _walkdata.next.y, sleInt16, VER(8)),
-		MKLINE(Actor, _walkdata.deltaXFactor, sleInt32, VER(8)),
-		MKLINE(Actor, _walkdata.deltaYFactor, sleInt32, VER(8)),
-		MKLINE(Actor, _walkdata.xfrac, sleUint16, VER(8)),
-		MKLINE(Actor, _walkdata.yfrac, sleUint16, VER(8)),
-
-		MKLINE(Actor, _walkdata.point3.x, sleUint16, VER(42)),
-		MKLINE(Actor, _walkdata.point3.y, sleUint16, VER(42)),
-
-		MKARRAY(Actor, _cost.active[0], sleByte, 16, VER(8)),
-		MKLINE(Actor, _cost.stopped, sleUint16, VER(8)),
-		MKARRAY(Actor, _cost.curpos[0], sleUint16, 16, VER(8)),
-		MKARRAY(Actor, _cost.start[0], sleUint16, 16, VER(8)),
-		MKARRAY(Actor, _cost.end[0], sleUint16, 16, VER(8)),
-		MKARRAY(Actor, _cost.frame[0], sleUint16, 16, VER(8)),
-
-		MKARRAY(Actor, _cost.heJumpOffsetTable[0], sleUint16, 16, VER(65)),
-		MKARRAY(Actor, _cost.heJumpCountTable[0], sleUint16, 16, VER(65)),
-		MKARRAY(Actor, _cost.heCondMaskTable[0], sleUint32, 16, VER(65)),
-		MKEND()
-	};
-
-	if (ser->isLoading()) {
+void Actor::saveLoadWithSerializer(Common::Serializer &s) {
+	if (s.isLoading()) {
 		// Not all actor data is saved; so when loading, we first reset
 		// the actor, to ensure completely reproducible behavior (else,
 		// some not saved value in the actor class can cause odd things)
 		initActor(-1);
 	}
 
-	ser->saveLoadEntries(this, actorEntries);
-
-	if (ser->isLoading() && _vm->_game.version <= 2 && ser->getVersion() < VER(70)) {
+	s.syncAsSint16LE(_pos.x, VER(8));
+	s.syncAsSint16LE(_pos.y, VER(8));
+	s.syncAsSint16LE(_heOffsX, VER(32));
+	s.syncAsSint16LE(_heOffsY, VER(32));
+	s.syncAsSint16LE(_top, VER(8));
+	s.syncAsSint16LE(_bottom, VER(8));
+	s.syncAsSint16LE(_elevation, VER(8));
+	s.syncAsUint16LE(_width, VER(8));
+	s.syncAsUint16LE(_facing, VER(8));
+	s.syncAsUint16LE(_costume, VER(8));
+	s.syncAsByte(_room, VER(8));
+	s.syncAsByte(_talkColor, VER(8));
+	s.syncAsSint16LE(_talkFrequency, VER(16));
+	s.syncAsSint16LE(_talkPan, VER(24));
+	s.syncAsSint16LE(_talkVolume, VER(29));
+	s.syncAsUint16LE(_boxscale, VER(34));
+	s.syncAsByte(_scalex, VER(8));
+	s.syncAsByte(_scaley, VER(8));
+	s.syncAsByte(_charset, VER(8));
+
+	// Actor sound grew from 8 to 32 bytes and switched to uint16 in HE games
+	s.syncArray(_sound, 8, Common::Serializer::Byte, VER(8), VER(36));
+	s.syncArray(_sound, 32, Common::Serializer::Byte, VER(37), VER(61));
+	s.syncArray(_sound, 32, Common::Serializer::Uint16LE, VER(62));
+
+	// Actor animVariable grew from 8 to 27
+	s.syncArray(_animVariable, 8, Common::Serializer::Uint16LE, VER(8), VER(40));
+	s.syncArray(_animVariable, 27, Common::Serializer::Uint16LE, VER(41));
+
+	s.syncAsUint16LE(_targetFacing, VER(8));
+	s.syncAsByte(_moving, VER(8));
+	s.syncAsByte(_ignoreBoxes, VER(8));
+	s.syncAsByte(_forceClip, VER(8));
+	s.syncAsByte(_initFrame, VER(8));
+	s.syncAsByte(_walkFrame, VER(8));
+	s.syncAsByte(_standFrame, VER(8));
+	s.syncAsByte(_talkStartFrame, VER(8));
+	s.syncAsByte(_talkStopFrame, VER(8));
+	s.syncAsUint16LE(_speedx, VER(8));
+	s.syncAsUint16LE(_speedy, VER(8));
+	s.syncAsUint16LE(_cost.animCounter, VER(8));
+	s.syncAsByte(_cost.soundCounter, VER(8));
+	s.syncAsByte(_drawToBackBuf, VER(32));
+	s.syncAsByte(_flip, VER(32));
+	s.syncAsByte(_heSkipLimbs, VER(32));
+
+	// Actor palette grew from 64 to 256 bytes and switched to uint16 in HE games
+	s.syncArray(_palette, 64, Common::Serializer::Byte, VER(8), VER(9));
+	s.syncArray(_palette, 256, Common::Serializer::Byte, VER(10), VER(79));
+	s.syncArray(_palette, 256, Common::Serializer::Uint16LE, VER(80));
+
+	s.skip(1, VER(8), VER(9)); // _mask
+	s.syncAsByte(_shadowMode, VER(8));
+	s.syncAsByte(_visible, VER(8));
+	s.syncAsByte(_frame, VER(8));
+	s.syncAsByte(_animSpeed, VER(8));
+	s.syncAsByte(_animProgress, VER(8));
+	s.syncAsByte(_walkbox, VER(8));
+	s.syncAsByte(_needRedraw, VER(8));
+	s.syncAsByte(_needBgReset, VER(8));
+	s.syncAsByte(_costumeNeedsInit, VER(8));
+	s.syncAsUint32LE(_heCondMask, VER(38));
+	s.syncAsUint32LE(_hePaletteNum, VER(59));
+	s.syncAsUint32LE(_heXmapNum, VER(59));
+
+	s.syncAsSint16LE(_talkPosY, VER(8));
+	s.syncAsSint16LE(_talkPosX, VER(8));
+	s.syncAsByte(_ignoreTurns, VER(8));
+
+	// Actor layer switched to int32 in HE games
+	s.syncAsByte(_layer, VER(8), VER(57));
+	s.syncAsSint32LE(_layer, VER(58));
+
+	s.syncAsUint16LE(_talkScript, VER(8));
+	s.syncAsUint16LE(_walkScript, VER(8));
+
+	s.syncAsSint16LE(_walkdata.dest.x, VER(8));
+	s.syncAsSint16LE(_walkdata.dest.y, VER(8));
+	s.syncAsByte(_walkdata.destbox, VER(8));
+	s.syncAsUint16LE(_walkdata.destdir, VER(8));
+	s.syncAsByte(_walkdata.curbox, VER(8));
+	s.syncAsSint16LE(_walkdata.cur.x, VER(8));
+	s.syncAsSint16LE(_walkdata.cur.y, VER(8));
+	s.syncAsSint16LE(_walkdata.next.x, VER(8));
+	s.syncAsSint16LE(_walkdata.next.y, VER(8));
+	s.syncAsSint32LE(_walkdata.deltaXFactor, VER(8));
+	s.syncAsSint32LE(_walkdata.deltaYFactor, VER(8));
+	s.syncAsUint16LE(_walkdata.xfrac, VER(8));
+	s.syncAsUint16LE(_walkdata.yfrac, VER(8));
+
+	s.syncAsUint16LE(_walkdata.point3.x, VER(42));
+	s.syncAsUint16LE(_walkdata.point3.y, VER(42));
+
+	s.syncBytes(_cost.active, 16, VER(8));
+	s.syncAsUint16LE(_cost.stopped, VER(8));
+	s.syncArray(_cost.curpos, 16, Common::Serializer::Uint16LE, VER(8));
+	s.syncArray(_cost.start, 16, Common::Serializer::Uint16LE, VER(8));
+	s.syncArray(_cost.end, 16, Common::Serializer::Uint16LE, VER(8));
+	s.syncArray(_cost.frame, 16, Common::Serializer::Uint16LE, VER(8));
+
+	s.syncArray(_cost.heJumpOffsetTable, 16, Common::Serializer::Uint16LE, VER(65));
+	s.syncArray(_cost.heJumpCountTable, 16, Common::Serializer::Uint16LE, VER(65));
+	s.syncArray(_cost.heCondMaskTable, 16, Common::Serializer::Uint32LE, VER(65));
+
+	if (s.isLoading() && _vm->_game.version <= 2 && s.getVersion() < VER(70)) {
 		_pos.x >>= V12_X_SHIFT;
 		_pos.y >>= V12_Y_SHIFT;
 
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index 62ba161..c059d08 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -25,6 +25,7 @@
 #define SCUMM_ACTOR_H
 
 #include "common/scummsys.h"
+#include "common/serializer.h"
 #include "scumm/saveload.h"
 #include "scumm/scumm.h"
 
@@ -82,7 +83,7 @@ enum {
 	kNewInavlidBox = 0
 };
 
-class Actor : public Serializable {
+class Actor : public Common::Serializable {
 public:
 	static byte kInvalidBox;
 
@@ -300,8 +301,7 @@ public:
 
 	void classChanged(int cls, bool value);
 
-	// Used by the save/load system:
-	virtual void saveLoadWithSerializer(Serializer *ser);
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
 
 protected:
 	bool isInClass(int cls);
@@ -421,8 +421,7 @@ public:
 	void setTmpFromActor();
 	void setActorFromTmp();
 
-	// Used by the save/load system:
-	virtual void saveLoadWithSerializer(Serializer *ser);
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
 };
 
 
diff --git a/engines/scumm/charset.cpp b/engines/scumm/charset.cpp
index e546c80..214eeb7 100644
--- a/engines/scumm/charset.cpp
+++ b/engines/scumm/charset.cpp
@@ -708,17 +708,12 @@ void CharsetRenderer::translateColor() {
 	}
 }
 
-void CharsetRenderer::saveLoadWithSerializer(Serializer *ser) {
-	static const SaveLoadEntry charsetRendererEntries[] = {
-		MKLINE_OLD(CharsetRenderer, _curId, sleByte, VER(73), VER(73)),
-		MKLINE(CharsetRenderer, _curId, sleInt32, VER(74)),
-		MKLINE(CharsetRenderer, _color, sleByte, VER(73)),
-		MKEND()
-	};
+void CharsetRenderer::saveLoadWithSerializer(Common::Serializer &ser) {
+	ser.syncAsByte(_curId, VER(73), VER(73));
+	ser.syncAsSint32LE(_curId, VER(74));
+	ser.syncAsByte(_color, VER(73));
 
-	ser->saveLoadEntries(this, charsetRendererEntries);
-
-	if (ser->isLoading()) {
+	if (ser.isLoading()) {
 		setCurID(_curId);
 		setColor(_color);
 	}
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index b4b3d88..7f3a8ba 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -89,7 +89,7 @@ public:
 
 	virtual void setColor(byte color) { _color = color; translateColor(); }
 
-	void saveLoadWithSerializer(Serializer *ser);
+	void saveLoadWithSerializer(Common::Serializer &ser);
 };
 
 class CharsetRendererCommon : public CharsetRenderer {
diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index bd3cdb2..25dd31f 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -73,7 +73,7 @@ public:
 protected:
 	virtual void setupOpcodes();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	void localizeArray(int slot, byte scriptSlot);
 	void redimArray(int arrayId, int newX, int newY, int d);
@@ -163,7 +163,7 @@ protected:
 	virtual void setupScummVars();
 	virtual void resetScummVars();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void readRoomsOffsets();
 	virtual void readGlobalObjects();
@@ -222,7 +222,7 @@ public:
 protected:
 	virtual void setupOpcodes();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void redrawBGAreas();
 
@@ -490,7 +490,7 @@ protected:
 	virtual void processInput();
 	virtual void clearClickedStatus();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void readMAXS(int blockSize);
 	void setResourceOffHeap(int typeId, int resId, int val);
@@ -581,7 +581,7 @@ protected:
 
 	virtual void readMAXS(int blockSize);
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void copyPalColor(int dst, int src);
 	virtual void darkenPalette(int redScale, int greenScale, int blueScale, int startColor, int endColor);
@@ -613,7 +613,7 @@ public:
 protected:
 	virtual void setupOpcodes();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void decodeParseString(int a, int b);
 
diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp
index bef1c0b..16c3b50 100644
--- a/engines/scumm/he/sprite_he.cpp
+++ b/engines/scumm/he/sprite_he.cpp
@@ -1389,80 +1389,79 @@ void Sprite::processImages(bool arg) {
 	}
 }
 
-void Sprite::saveOrLoadSpriteData(Serializer *s) {
-	static const SaveLoadEntry spriteEntries[] = {
-		MKLINE(SpriteInfo, id, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, zorder, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, flags, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, image, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, imageState, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, group, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, palette, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, priority, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, bbox.left, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, bbox.top, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, bbox.right, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, bbox.bottom, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, dx, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, dy, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, pos.x, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, pos.y, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, tx, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, ty, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, userValue, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, curImageState, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, curImage, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, imglistNum, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, shadow, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, imageStateCount, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, angle, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, scale, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, animProgress, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, curAngle, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, curScale, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, curImgFlags, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, animIndex, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, animSpeed, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, sourceImage, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, maskImage, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, zbufferImage, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, classFlags, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, imgFlags, sleInt32, VER(48)),
-		MKLINE(SpriteInfo, conditionBits, sleInt32, VER(48)),
-		MKEND()
-	};
-
-	static const SaveLoadEntry spriteGroupEntries[] = {
-		MKLINE(SpriteGroup, bbox.left, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, bbox.top, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, bbox.right, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, bbox.bottom, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, priority, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, flags, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, tx, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, ty, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, image, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, scaling, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, scale_x_ratio_mul, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, scale_x_ratio_div, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, scale_y_ratio_mul, sleInt32, VER(48)),
-		MKLINE(SpriteGroup, scale_y_ratio_div, sleInt32, VER(48)),
-		MKEND()
-	};
-
-	if (s->getVersion() >= VER(64)) {
-		s->saveLoadArrayOf(_spriteTable, _varNumSprites + 1, sizeof(_spriteTable[0]), spriteEntries);
-		s->saveLoadArrayOf(_spriteGroups, _varNumSpriteGroups + 1, sizeof(_spriteGroups[0]), spriteGroupEntries);
+static void syncWithSerializer(Common::Serializer &s, SpriteInfo &si) {
+	s.syncAsSint32LE(si.id, VER(48));
+	s.syncAsSint32LE(si.zorder, VER(48));
+	s.syncAsSint32LE(si.flags, VER(48));
+	s.syncAsSint32LE(si.image, VER(48));
+	s.syncAsSint32LE(si.imageState, VER(48));
+	s.syncAsSint32LE(si.group, VER(48));
+	s.syncAsSint32LE(si.palette, VER(48));
+	s.syncAsSint32LE(si.priority, VER(48));
+	s.syncAsSint32LE(si.bbox.left, VER(48));
+	s.syncAsSint32LE(si.bbox.top, VER(48));
+	s.syncAsSint32LE(si.bbox.right, VER(48));
+	s.syncAsSint32LE(si.bbox.bottom, VER(48));
+	s.syncAsSint32LE(si.dx, VER(48));
+	s.syncAsSint32LE(si.dy, VER(48));
+	s.syncAsSint32LE(si.pos.x, VER(48));
+	s.syncAsSint32LE(si.pos.y, VER(48));
+	s.syncAsSint32LE(si.tx, VER(48));
+	s.syncAsSint32LE(si.ty, VER(48));
+	s.syncAsSint32LE(si.userValue, VER(48));
+	s.syncAsSint32LE(si.curImageState, VER(48));
+	s.syncAsSint32LE(si.curImage, VER(48));
+	s.syncAsSint32LE(si.imglistNum, VER(48));
+	s.syncAsSint32LE(si.shadow, VER(48));
+	s.syncAsSint32LE(si.imageStateCount, VER(48));
+	s.syncAsSint32LE(si.angle, VER(48));
+	s.syncAsSint32LE(si.scale, VER(48));
+	s.syncAsSint32LE(si.animProgress, VER(48));
+	s.syncAsSint32LE(si.curAngle, VER(48));
+	s.syncAsSint32LE(si.curScale, VER(48));
+	s.syncAsSint32LE(si.curImgFlags, VER(48));
+	s.syncAsSint32LE(si.animIndex, VER(48));
+	s.syncAsSint32LE(si.animSpeed, VER(48));
+	s.syncAsSint32LE(si.sourceImage, VER(48));
+	s.syncAsSint32LE(si.maskImage, VER(48));
+	s.syncAsSint32LE(si.zbufferImage, VER(48));
+	s.syncAsSint32LE(si.classFlags, VER(48));
+	s.syncAsSint32LE(si.imgFlags, VER(48));
+	s.syncAsSint32LE(si.conditionBits, VER(48));
+}
+
+static void syncWithSerializer(Common::Serializer &s, SpriteGroup &sg) {
+	s.syncAsSint32LE(sg.bbox.left, VER(48));
+	s.syncAsSint32LE(sg.bbox.top, VER(48));
+	s.syncAsSint32LE(sg.bbox.right, VER(48));
+	s.syncAsSint32LE(sg.bbox.bottom, VER(48));
+	s.syncAsSint32LE(sg.priority, VER(48));
+	s.syncAsSint32LE(sg.flags, VER(48));
+	s.syncAsSint32LE(sg.tx, VER(48));
+	s.syncAsSint32LE(sg.ty, VER(48));
+	s.syncAsSint32LE(sg.image, VER(48));
+	s.syncAsSint32LE(sg.scaling, VER(48));
+	s.syncAsSint32LE(sg.scale_x_ratio_mul, VER(48));
+	s.syncAsSint32LE(sg.scale_x_ratio_div, VER(48));
+	s.syncAsSint32LE(sg.scale_y_ratio_mul, VER(48));
+	s.syncAsSint32LE(sg.scale_y_ratio_div, VER(48));
+}
+
+void Sprite::saveLoadWithSerializer(Common::Serializer &s) {
+	if (s.getVersion() >= VER(64)) {
+		s.syncArray(_spriteTable, _varNumSprites + 1, syncWithSerializer);
+		s.syncArray(_spriteGroups, _varNumSpriteGroups + 1, syncWithSerializer);
 	} else {
-		s->saveLoadArrayOf(_activeSpritesTable, _varNumSprites, sizeof(_activeSpritesTable[0]), spriteEntries);
-		s->saveLoadArrayOf(_spriteTable, _varNumSprites, sizeof(_spriteTable[0]), spriteEntries);
-		s->saveLoadArrayOf(_spriteGroups, _varNumSpriteGroups, sizeof(_spriteGroups[0]), spriteGroupEntries);
+		// TODO: This had been bogus, what is it really supposed to do?
+//		s->saveLoadArrayOf(_activeSpritesTable, _varNumSprites, sizeof(_activeSpritesTable[0]), spriteEntries);
+		s.syncArray(*_activeSpritesTable, _varNumSprites, syncWithSerializer);
+		s.syncArray(_spriteTable, _varNumSprites, syncWithSerializer);
+		s.syncArray(_spriteGroups, _varNumSpriteGroups, syncWithSerializer);
 	}
 
 	// Reset active sprite table
-	if (s->isLoading())
+	if (s.isLoading())
 		_numSpritesToProcess = 0;
-
 }
 
 } // End of namespace Scumm
diff --git a/engines/scumm/he/sprite_he.h b/engines/scumm/he/sprite_he.h
index 3ea6bb9..77e527b 100644
--- a/engines/scumm/he/sprite_he.h
+++ b/engines/scumm/he/sprite_he.h
@@ -23,6 +23,8 @@
 #if !defined(SCUMM_HE_SPRITE_HE_H) && defined(ENABLE_HE)
 #define SCUMM_HE_SPRITE_HE_H
 
+#include "common/serializer.h"
+
 namespace Scumm {
 
 enum SpriteFlags {
@@ -98,7 +100,7 @@ struct SpriteGroup {
 
 class ScummEngine_v90he;
 
-class Sprite {
+class Sprite : public Common::Serializable {
 public:
 	Sprite(ScummEngine_v90he *vm);
 	virtual ~Sprite();
@@ -112,7 +114,7 @@ public:
 	int32 _varNumSprites;
 	int32 _varMaxSprites;
 
-	void saveOrLoadSpriteData(Serializer *s);
+	void saveLoadWithSerializer(Common::Serializer &s);
 	void resetBackground();
 	void setRedrawFlags(bool checkZOrder);
 	void sortActiveSprites();
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index b7b72ba..d083dc8 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -362,70 +362,50 @@ void IMuseInternal::pause(bool paused) {
 	_paused = paused;
 }
 
-int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAfterLoad) {
-	Common::StackLock lock(_mutex, "IMuseInternal::save_or_load()");
-	const SaveLoadEntry mainEntries[] = {
-		MKLINE(IMuseInternal, _queue_end, sleUint8, VER(8)),
-		MKLINE(IMuseInternal, _queue_pos, sleUint8, VER(8)),
-		MKLINE(IMuseInternal, _queue_sound, sleUint16, VER(8)),
-		MKLINE(IMuseInternal, _queue_adding, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _queue_marker, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _queue_cleared, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _master_volume, sleByte, VER(8)),
-		MKLINE(IMuseInternal, _trigger_count, sleUint16, VER(8)),
-		MKLINE(IMuseInternal, _snm_trigger_index, sleUint16, VER(54)),
-		MKARRAY(IMuseInternal, _channel_volume[0], sleUint16, 8, VER(8)),
-		MKARRAY(IMuseInternal, _volchan_table[0], sleUint16, 8, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry cmdQueueEntries[] = {
-		MKARRAY(CommandQueue, array[0], sleUint16, 8, VER(23)),
-		MKEND()
-	};
+static void syncWithSerializer(Common::Serializer &s, CommandQueue &cq) {
+	s.syncArray(cq.array, 8, Common::Serializer::Uint16LE, VER(23));
+}
 
-	// VolumeFader is obsolete.
-	const SaveLoadEntry volumeFaderEntries[] = {
-		MK_OBSOLETE(VolumeFader, player, sleUint16, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, active, sleUint8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, curvol, sleUint8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_lo_max, sleUint16, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, num_steps, sleUint16, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_hi, sleInt8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, direction, sleInt8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_lo, sleInt8, VER(8), VER(16)),
-		MK_OBSOLETE(VolumeFader, speed_lo_counter, sleUint16, VER(8), VER(16)),
-		MKEND()
-	};
+static void syncWithSerializer(Common::Serializer &s, ImTrigger &it) {
+	s.syncAsSint16LE(it.sound, VER(54));
+	s.syncAsByte(it.id, VER(54));
+	s.syncAsUint16LE(it.expire, VER(54));
+	s.syncArray(it.command, 8, Common::Serializer::Uint16LE, VER(54));
+}
 
-	const SaveLoadEntry snmTriggerEntries[] = {
-		MKLINE(ImTrigger, sound, sleInt16, VER(54)),
-		MKLINE(ImTrigger, id, sleByte, VER(54)),
-		MKLINE(ImTrigger, expire, sleUint16, VER(54)),
-		MKARRAY(ImTrigger, command[0], sleUint16, 8, VER(54)),
-		MKEND()
-	};
+void IMuseInternal::saveLoadWithSerializer(Common::Serializer &s, ScummEngine *scumm, bool fixAfterLoad) {
+	Common::StackLock lock(_mutex, "IMuseInternal::saveLoadWithSerializer()");
 
 	int i;
 
-	ser->saveLoadEntries(this, mainEntries);
-	ser->saveLoadArrayOf(_cmd_queue, ARRAYSIZE(_cmd_queue), sizeof(_cmd_queue[0]), cmdQueueEntries);
-	ser->saveLoadArrayOf(_snm_triggers, ARRAYSIZE(_snm_triggers), sizeof(_snm_triggers[0]), snmTriggerEntries);
+	s.syncAsByte(_queue_end, VER(8));
+	s.syncAsByte(_queue_pos, VER(8));
+	s.syncAsUint16LE(_queue_sound, VER(8));
+	s.syncAsByte(_queue_adding, VER(8));
+	s.syncAsByte(_queue_marker, VER(8));
+	s.syncAsByte(_queue_cleared, VER(8));
+	s.syncAsByte(_master_volume, VER(8));
+	s.syncAsUint16LE(_trigger_count, VER(8));
+	s.syncAsUint16LE(_snm_trigger_index, VER(54));
+	s.syncArray(_channel_volume, 8, Common::Serializer::Uint16LE, VER(8));
+	s.syncArray(_volchan_table, 8, Common::Serializer::Uint16LE, VER(8));
+	s.syncArray(_cmd_queue, ARRAYSIZE(_cmd_queue), syncWithSerializer);
+	s.syncArray(_snm_triggers, ARRAYSIZE(_snm_triggers), syncWithSerializer);
 
 	// The players
 	for (i = 0; i < ARRAYSIZE(_players); ++i)
-		_players[i].saveLoadWithSerializer(ser);
+		_players[i].saveLoadWithSerializer(s);
 
 	// The parts
 	for (i = 0; i < ARRAYSIZE(_parts); ++i)
-		_parts[i].saveLoadWithSerializer(ser);
+		_parts[i].saveLoadWithSerializer(s);
 
 	{
 		// Load/save the instrument definitions, which were revamped with V11.
 		Part *part = &_parts[0];
-		if (ser->getVersion() >= VER(11)) {
+		if (s.getVersion() >= VER(11)) {
 			for (i = ARRAYSIZE(_parts); i; --i, ++part) {
-				part->_instrument.saveOrLoad(ser);
+				part->_instrument.saveLoadWithSerializer(s);
 			}
 		} else {
 			for (i = ARRAYSIZE(_parts); i; --i, ++part)
@@ -434,10 +414,7 @@ int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAft
 	}
 
 	// VolumeFader has been replaced with the more generic ParameterFader.
-	// FIXME: replace this loop by something like
-	// if (loading && version <= 16)  ser->skip(XXX bytes);
-	for (i = 0; i < 8; ++i)
-		ser->saveLoadEntries(0, volumeFaderEntries);
+	s.skip(13 * 8, VER(8), VER(16));
 
 	// Normally, we have to fix up the data structures after loading a
 	// saved game. But there are cases where we don't. For instance, The
@@ -448,7 +425,7 @@ int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAft
 	// dummy iMUSE object, but since the resource is no longer recognizable
 	// to iMUSE, the fixup fails hard. So yes, this is a bit of a hack.
 
-	if (ser->isLoading() && fixAfterLoad) {
+	if (s.isLoading() && fixAfterLoad) {
 		// Load all sounds that we need
 		fix_players_after_load(scumm);
 		fix_parts_after_load();
@@ -459,8 +436,6 @@ int IMuseInternal::save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAft
 		if (_midi_adlib)
 			reallocateMidiChannels(_midi_adlib);
 	}
-
-	return 0;
 }
 
 bool IMuseInternal::get_sound_active(int sound) const {
diff --git a/engines/scumm/imuse/imuse.h b/engines/scumm/imuse/imuse.h
index 35ccc93..513d27e 100644
--- a/engines/scumm/imuse/imuse.h
+++ b/engines/scumm/imuse/imuse.h
@@ -24,6 +24,7 @@
 #define SCUMM_IMUSE_H
 
 #include "common/scummsys.h"
+#include "common/serializer.h"
 #include "common/mutex.h"
 #include "scumm/music.h"
 
@@ -35,7 +36,6 @@ namespace Scumm {
 class IMuseInternal;
 class Player;
 class ScummEngine;
-class Serializer;
 
 typedef void (*sysexfunc)(Player *, const byte *, uint16);
 
@@ -62,7 +62,7 @@ public:
 public:
 	virtual void on_timer(MidiDriver *midi) = 0;
 	virtual void pause(bool paused) = 0;
-	virtual int save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAfterLoad = true) = 0;
+	virtual void saveLoadWithSerializer(Common::Serializer &ser, ScummEngine *scumm, bool fixAfterLoad = true) = 0;
 	virtual bool get_sound_active(int sound) const = 0;
 	virtual int32 doCommand(int numargs, int args[]) = 0;
 	virtual int clear_queue() = 0;
diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index fed716e..7b1d2f6 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -24,6 +24,7 @@
 #define SCUMM_IMUSE_INTERNAL
 
 #include "common/scummsys.h"
+#include "common/serializer.h"
 #include "scumm/imuse/imuse.h"
 #include "scumm/imuse/instrument.h"
 #include "scumm/saveload.h"
@@ -153,7 +154,7 @@ struct CommandQueue {
 //
 //////////////////////////////////////////////////
 
-class Player : public MidiDriver_BASE {
+class Player : public MidiDriver_BASE, public Common::Serializable {
 	/*
 	 * External SysEx handler functions shall each be defined in
 	 * a separate file. This header file shall be included at the
@@ -267,7 +268,7 @@ public:
 	void onTimer();
 	void removePart(Part *part);
 	int scan(uint totrack, uint tobeat, uint totick);
-	void saveLoadWithSerializer(Serializer *ser);
+	void saveLoadWithSerializer(Common::Serializer &ser);
 	int setHook(byte cls, byte value, byte chan) { return _hook.set(cls, value, chan); }
 	void setDetune(int detune);
 	void setOffsetNote(int offset);
@@ -295,7 +296,7 @@ public:
 //
 //////////////////////////////////////////////////
 
-struct Part : public Serializable {
+struct Part : public Common::Serializable {
 	IMuseInternal *_se;
 	int _slot;
 	Part *_next, *_prev;
@@ -360,7 +361,7 @@ struct Part : public Serializable {
 
 	Part();
 
-	void saveLoadWithSerializer(Serializer *ser);
+	void saveLoadWithSerializer(Common::Serializer &ser);
 
 private:
 	void sendPitchBend();
@@ -518,7 +519,7 @@ protected:
 public:
 	// IMuse interface
 	void pause(bool paused);
-	int save_or_load(Serializer *ser, ScummEngine *scumm, bool fixAfterLoad = true);
+	void saveLoadWithSerializer(Common::Serializer &ser, ScummEngine *scumm, bool fixAfterLoad = true);
 	bool get_sound_active(int sound) const;
 	int32 doCommand(int numargs, int args[]);
 	uint32 property(int prop, uint32 value);
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 937523d..ca0eaa4 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -66,48 +66,44 @@ Part::Part() {
 	_unassigned_instrument = false;
 }
 
-void Part::saveLoadWithSerializer(Serializer *ser) {
-	const SaveLoadEntry partEntries[] = {
-		MKLINE(Part, _pitchbend, sleInt16, VER(8)),
-		MKLINE(Part, _pitchbend_factor, sleUint8, VER(8)),
-		MKLINE(Part, _transpose, sleInt8, VER(8)),
-		MKLINE(Part, _vol, sleUint8, VER(8)),
-		MKLINE(Part, _detune, sleInt8, VER(8)),
-		MKLINE(Part, _pan, sleInt8, VER(8)),
-		MKLINE(Part, _on, sleUint8, VER(8)),
-		MKLINE(Part, _modwheel, sleUint8, VER(8)),
-		MKLINE(Part, _pedal, sleUint8, VER(8)),
-		MK_OBSOLETE(Part, _program, sleUint8, VER(8), VER(16)),
-		MKLINE(Part, _pri, sleUint8, VER(8)),
-		MKLINE(Part, _chan, sleUint8, VER(8)),
-		MKLINE(Part, _effect_level, sleUint8, VER(8)),
-		MKLINE(Part, _chorus, sleUint8, VER(8)),
-		MKLINE(Part, _percussion, sleUint8, VER(8)),
-		MKLINE(Part, _bank, sleUint8, VER(8)),
-		MKEND()
-	};
-
+void Part::saveLoadWithSerializer(Common::Serializer &ser) {
 	int num;
-	if (ser->isSaving()) {
+	if (ser.isSaving()) {
 		num = (_next ? (_next - _se->_parts + 1) : 0);
-		ser->saveUint16(num);
+		ser.syncAsUint16LE(num);
 
 		num = (_prev ? (_prev - _se->_parts + 1) : 0);
-		ser->saveUint16(num);
+		ser.syncAsUint16LE(num);
 
 		num = (_player ? (_player - _se->_players + 1) : 0);
-		ser->saveUint16(num);
+		ser.syncAsUint16LE(num);
 	} else {
-		num = ser->loadUint16();
+		ser.syncAsUint16LE(num);
 		_next = (num ? &_se->_parts[num - 1] : 0);
 
-		num = ser->loadUint16();
+		ser.syncAsUint16LE(num);
 		_prev = (num ? &_se->_parts[num - 1] : 0);
 
-		num = ser->loadUint16();
+		ser.syncAsUint16LE(num);
 		_player = (num ? &_se->_players[num - 1] : 0);
 	}
-	ser->saveLoadEntries(this, partEntries);
+
+	ser.syncAsSint16LE(_pitchbend, VER(8));
+	ser.syncAsByte(_pitchbend_factor, VER(8));
+	ser.syncAsSByte(_transpose, VER(8));
+	ser.syncAsByte(_vol, VER(8));
+	ser.syncAsSByte(_detune, VER(8));
+	ser.syncAsSByte(_pan, VER(8));
+	ser.syncAsByte(_on, VER(8));
+	ser.syncAsByte(_modwheel, VER(8));
+	ser.syncAsByte(_pedal, VER(8));
+	ser.skip(1, VER(8), VER(16)); // _program
+	ser.syncAsByte(_pri, VER(8));
+	ser.syncAsByte(_chan, VER(8));
+	ser.syncAsByte(_effect_level, VER(8));
+	ser.syncAsByte(_chorus, VER(8));
+	ser.syncAsByte(_percussion, VER(8));
+	ser.syncAsByte(_bank, VER(8));
 }
 
 void Part::set_detune(int8 detune) {
diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp
index 33b38ee..a4b79f7 100644
--- a/engines/scumm/imuse/imuse_player.cpp
+++ b/engines/scumm/imuse/imuse_player.cpp
@@ -1033,70 +1033,63 @@ void Player::metaEvent(byte type, byte *msg, uint16 len) {
 //
 ////////////////////////////////////////
 
-void Player::saveLoadWithSerializer(Serializer *ser) {
-	static const SaveLoadEntry playerEntries[] = {
-		MKLINE(Player, _active, sleByte, VER(8)),
-		MKLINE(Player, _id, sleUint16, VER(8)),
-		MKLINE(Player, _priority, sleByte, VER(8)),
-		MKLINE(Player, _volume, sleByte, VER(8)),
-		MKLINE(Player, _pan, sleInt8, VER(8)),
-		MKLINE(Player, _transpose, sleByte, VER(8)),
-		MKLINE(Player, _detune, sleInt8, VER(8)),
-		MKLINE(Player, _vol_chan, sleUint16, VER(8)),
-		MKLINE(Player, _vol_eff, sleByte, VER(8)),
-		MKLINE(Player, _speed, sleByte, VER(8)),
-		MK_OBSOLETE(Player, _song_index, sleUint16, VER(8), VER(19)),
-		MKLINE(Player, _track_index, sleUint16, VER(8)),
-		MK_OBSOLETE(Player, _timer_counter, sleUint16, VER(8), VER(17)),
-		MKLINE(Player, _loop_to_beat, sleUint16, VER(8)),
-		MKLINE(Player, _loop_from_beat, sleUint16, VER(8)),
-		MKLINE(Player, _loop_counter, sleUint16, VER(8)),
-		MKLINE(Player, _loop_to_tick, sleUint16, VER(8)),
-		MKLINE(Player, _loop_from_tick, sleUint16, VER(8)),
-		MK_OBSOLETE(Player, _tempo, sleUint32, VER(8), VER(19)),
-		MK_OBSOLETE(Player, _cur_pos, sleUint32, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _next_pos, sleUint32, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _song_offset, sleUint32, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _tick_index, sleUint16, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _beat_index, sleUint16, VER(8), VER(17)),
-		MK_OBSOLETE(Player, _ticks_per_beat, sleUint16, VER(8), VER(17)),
-		MKLINE(Player, _music_tick, sleUint32, VER(19)),
-		MKLINE(Player, _hook._jump[0], sleByte, VER(8)),
-		MKLINE(Player, _hook._transpose, sleByte, VER(8)),
-		MKARRAY(Player, _hook._part_onoff[0], sleByte, 16, VER(8)),
-		MKARRAY(Player, _hook._part_volume[0], sleByte, 16, VER(8)),
-		MKARRAY(Player, _hook._part_program[0], sleByte, 16, VER(8)),
-		MKARRAY(Player, _hook._part_transpose[0], sleByte, 16, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry parameterFaderEntries[] = {
-		MKLINE(ParameterFader, param,        sleInt16,  VER(17)),
-		MKLINE(ParameterFader, start,        sleInt16,  VER(17)),
-		MKLINE(ParameterFader, end,          sleInt16,  VER(17)),
-		MKLINE(ParameterFader, total_time,   sleUint32, VER(17)),
-		MKLINE(ParameterFader, current_time, sleUint32, VER(17)),
-		MKEND()
-	};
-
-	if (!ser->isSaving() && _parser) {
+static void syncWithSerializer(Common::Serializer &s, ParameterFader &pf) {
+	s.syncAsSint16LE(pf.param, VER(17));
+	s.syncAsSint16LE(pf.start, VER(17));
+	s.syncAsSint16LE(pf.end, VER(17));
+	s.syncAsUint32LE(pf.total_time, VER(17));
+	s.syncAsUint32LE(pf.current_time, VER(17));
+}
+
+void Player::saveLoadWithSerializer(Common::Serializer &s) {
+	if (!s.isSaving() && _parser) {
 		delete _parser;
 		_parser = 0;
 	}
 	_music_tick = _parser ? _parser->getTick() : 0;
 
 	int num;
-	if (ser->isSaving()) {
+	if (s.isSaving()) {
 		num = (_parts ? (_parts - _se->_parts + 1) : 0);
-		ser->saveUint16(num);
+		s.syncAsUint16LE(num);
 	} else {
-		num = ser->loadUint16();
+		s.syncAsUint16LE(num);
 		_parts = (num ? &_se->_parts[num - 1] : 0);
 	}
-	ser->saveLoadEntries(this, playerEntries);
-	ser->saveLoadArrayOf(_parameterFaders, ARRAYSIZE(_parameterFaders),
-	                     sizeof(ParameterFader), parameterFaderEntries);
-	return;
+
+	s.syncAsByte(_active, VER(8));
+	s.syncAsUint16LE(_id, VER(8));
+	s.syncAsByte(_priority, VER(8));
+	s.syncAsByte(_volume, VER(8));
+	s.syncAsSByte(_pan, VER(8));
+	s.syncAsByte(_transpose, VER(8));
+	s.syncAsSByte(_detune, VER(8));
+	s.syncAsUint16LE(_vol_chan, VER(8));
+	s.syncAsByte(_vol_eff, VER(8));
+	s.syncAsByte(_speed, VER(8));
+	s.skip(2, VER(8), VER(19)); // _song_index
+	s.syncAsUint16LE(_track_index, VER(8));
+	s.skip(2, VER(8), VER(17)); // _timer_counter
+	s.syncAsUint16LE(_loop_to_beat, VER(8));
+	s.syncAsUint16LE(_loop_from_beat, VER(8));
+	s.syncAsUint16LE(_loop_counter, VER(8));
+	s.syncAsUint16LE(_loop_to_tick, VER(8));
+	s.syncAsUint16LE(_loop_from_tick, VER(8));
+	s.skip(4, VER(8), VER(19)); // _tempo
+	s.skip(4, VER(8), VER(17)); // _cur_pos
+	s.skip(4, VER(8), VER(17)); // _next_pos
+	s.skip(4, VER(8), VER(17)); // _song_offset
+	s.skip(2, VER(8), VER(17)); // _tick_index
+	s.skip(2, VER(8), VER(17)); // _beat_index
+	s.skip(2, VER(8), VER(17)); // _ticks_per_beat
+	s.syncAsUint32LE(_music_tick, VER(19));
+	s.syncAsByte(_hook._jump[0], VER(8));
+	s.syncAsByte(_hook._transpose, VER(8));
+	s.syncBytes(_hook._part_onoff, 16, VER(8));
+	s.syncBytes(_hook._part_volume, 16, VER(8));
+	s.syncBytes(_hook._part_program, 16, VER(8));
+	s.syncBytes(_hook._part_transpose, 16, VER(8));
+	s.syncArray(_parameterFaders, ARRAYSIZE(_parameterFaders), syncWithSerializer);
 }
 
 } // End of namespace Scumm
diff --git a/engines/scumm/imuse/instrument.cpp b/engines/scumm/imuse/instrument.cpp
index 670b364..708a980 100644
--- a/engines/scumm/imuse/instrument.cpp
+++ b/engines/scumm/imuse/instrument.cpp
@@ -20,7 +20,6 @@
  *
  */
 
-
 #include "scumm/scumm.h"
 #include "scumm/saveload.h"
 #include "scumm/imuse/instrument.h"
@@ -132,8 +131,8 @@ private:
 
 public:
 	Instrument_Program(byte program, bool mt32);
-	Instrument_Program(Serializer *s);
-	void saveOrLoad(Serializer *s);
+	Instrument_Program(Common::Serializer &s);
+	void saveLoadWithSerializer(Common::Serializer &s);
 	void send(MidiChannel *mc);
 	void copy_to(Instrument *dest) { dest->program(_program, _mt32); }
 	bool is_valid() {
@@ -178,8 +177,8 @@ private:
 
 public:
 	Instrument_AdLib(const byte *data);
-	Instrument_AdLib(Serializer *s);
-	void saveOrLoad(Serializer *s);
+	Instrument_AdLib(Common::Serializer &s);
+	void saveLoadWithSerializer(Common::Serializer &s);
 	void send(MidiChannel *mc);
 	void copy_to(Instrument *dest) { dest->adlib((byte *)&_instrument); }
 	bool is_valid() { return true; }
@@ -259,8 +258,8 @@ private:
 
 public:
 	Instrument_Roland(const byte *data);
-	Instrument_Roland(Serializer *s);
-	void saveOrLoad(Serializer *s);
+	Instrument_Roland(Common::Serializer &s);
+	void saveLoadWithSerializer(Common::Serializer &s);
 	void send(MidiChannel *mc);
 	void copy_to(Instrument *dest) { dest->roland((byte *)&_instrument); }
 	bool is_valid() { return (_native_mt32 ? true : (_instrument_name[0] != '\0')); }
@@ -269,8 +268,8 @@ public:
 class Instrument_PcSpk : public InstrumentInternal {
 public:
 	Instrument_PcSpk(const byte *data);
-	Instrument_PcSpk(Serializer *s);
-	void saveOrLoad(Serializer *s);
+	Instrument_PcSpk(Common::Serializer &s);
+	void saveLoadWithSerializer(Common::Serializer &s);
 	void send(MidiChannel *mc);
 	void copy_to(Instrument *dest) { dest->pcspk((byte *)&_instrument); }
 	bool is_valid() { return true; }
@@ -285,8 +284,8 @@ private:
 
 public:
 	Instrument_MacSfx(byte program);
-	Instrument_MacSfx(Serializer *s);
-	void saveOrLoad(Serializer *s);
+	Instrument_MacSfx(Common::Serializer &s);
+	void saveLoadWithSerializer(Common::Serializer &s);
 	void send(MidiChannel *mc);
 	void copy_to(Instrument *dest) { dest->macSfx(_program); }
 	bool is_valid() {
@@ -350,14 +349,14 @@ void Instrument::macSfx(byte prog) {
 	_instrument = new Instrument_MacSfx(prog);
 }
 
-void Instrument::saveOrLoad(Serializer *s) {
-	if (s->isSaving()) {
-		s->saveByte(_type);
+void Instrument::saveLoadWithSerializer(Common::Serializer &s) {
+	if (s.isSaving()) {
+		s.syncAsByte(_type);
 		if (_instrument)
-			_instrument->saveOrLoad(s);
+			_instrument->saveLoadWithSerializer(s);
 	} else {
 		clear();
-		_type = s->loadByte();
+		s.syncAsByte(_type);
 		switch (_type) {
 		case itNone:
 			break;
@@ -396,20 +395,21 @@ Instrument_Program::Instrument_Program(byte program, bool mt32) :
 		_program = 255;
 }
 
-Instrument_Program::Instrument_Program(Serializer *s) {
+Instrument_Program::Instrument_Program(Common::Serializer &s) {
 	_program = 255;
 	_mt32 = false;
-	if (!s->isSaving())
-		saveOrLoad(s);
+	if (!s.isSaving())
+		saveLoadWithSerializer(s);
 }
 
-void Instrument_Program::saveOrLoad(Serializer *s) {
-	if (s->isSaving()) {
-		s->saveByte(_program);
-		s->saveByte(_mt32 ? 1 : 0);
+void Instrument_Program::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncAsByte(_program);
+	if (s.isSaving()) {
+		s.syncAsByte(_mt32);
 	} else {
-		_program = s->loadByte();
-		_mt32 = (s->loadByte() > 0);
+		byte tmp;
+		s.syncAsByte(tmp);
+		_mt32 = (tmp > 0);
 	}
 }
 
@@ -434,18 +434,15 @@ Instrument_AdLib::Instrument_AdLib(const byte *data) {
 	memcpy(&_instrument, data, sizeof(_instrument));
 }
 
-Instrument_AdLib::Instrument_AdLib(Serializer *s) {
-	if (!s->isSaving())
-		saveOrLoad(s);
+Instrument_AdLib::Instrument_AdLib(Common::Serializer &s) {
+	if (!s.isSaving())
+		saveLoadWithSerializer(s);
 	else
 		memset(&_instrument, 0, sizeof(_instrument));
 }
 
-void Instrument_AdLib::saveOrLoad(Serializer *s) {
-	if (s->isSaving())
-		s->saveBytes(&_instrument, sizeof(_instrument));
-	else
-		s->loadBytes(&_instrument, sizeof(_instrument));
+void Instrument_AdLib::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncBytes((byte *)(&_instrument), sizeof(_instrument));
 }
 
 void Instrument_AdLib::send(MidiChannel *mc) {
@@ -468,26 +465,24 @@ Instrument_Roland::Instrument_Roland(const byte *data) {
 	}
 }
 
-Instrument_Roland::Instrument_Roland(Serializer *s) {
+Instrument_Roland::Instrument_Roland(Common::Serializer &s) {
 	_instrument_name[0] = '\0';
-	if (!s->isSaving())
-		saveOrLoad(s);
+	if (!s.isSaving())
+		saveLoadWithSerializer(s);
 	else
 		memset(&_instrument, 0, sizeof(_instrument));
 }
 
-void Instrument_Roland::saveOrLoad(Serializer *s) {
-	if (s->isSaving()) {
-		s->saveBytes(&_instrument, sizeof(_instrument));
-	} else {
-		s->loadBytes(&_instrument, sizeof(_instrument));
+void Instrument_Roland::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncBytes((byte *)(&_instrument), sizeof(_instrument));
+	if (!s.isSaving()) {
 		memcpy(&_instrument_name, &_instrument.common.name, sizeof(_instrument.common.name));
 		_instrument_name[10] = '\0';
 		if (!_native_mt32 && getEquivalentGM() >= 128) {
 			debug(2, "MT-32 custom instrument \"%s\" not supported", _instrument_name);
 			_instrument_name[0] = '\0';
 		}
-	} // end if
+	}
 }
 
 void Instrument_Roland::send(MidiChannel *mc) {
@@ -538,18 +533,15 @@ Instrument_PcSpk::Instrument_PcSpk(const byte *data) {
 	memcpy(_instrument, data, sizeof(_instrument));
 }
 
-Instrument_PcSpk::Instrument_PcSpk(Serializer *s) {
-	if (!s->isSaving())
-		saveOrLoad(s);
+Instrument_PcSpk::Instrument_PcSpk(Common::Serializer &s) {
+	if (!s.isSaving())
+		saveLoadWithSerializer(s);
 	else
 		memset(_instrument, 0, sizeof(_instrument));
 }
 
-void Instrument_PcSpk::saveOrLoad(Serializer *s) {
-	if (s->isSaving())
-		s->saveBytes(_instrument, sizeof(_instrument));
-	else
-		s->loadBytes(_instrument, sizeof(_instrument));
+void Instrument_PcSpk::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncBytes(_instrument, sizeof(_instrument));
 }
 
 void Instrument_PcSpk::send(MidiChannel *mc) {
@@ -569,19 +561,15 @@ Instrument_MacSfx::Instrument_MacSfx(byte program) :
 	}
 }
 
-Instrument_MacSfx::Instrument_MacSfx(Serializer *s) {
+Instrument_MacSfx::Instrument_MacSfx(Common::Serializer &s) {
 	_program = 255;
-	if (!s->isSaving()) {
-		saveOrLoad(s);
+	if (!s.isSaving()) {
+		saveLoadWithSerializer(s);
 	}
 }
 
-void Instrument_MacSfx::saveOrLoad(Serializer *s) {
-	if (s->isSaving()) {
-		s->saveByte(_program);
-	} else {
-		_program = s->loadByte();
-	}
+void Instrument_MacSfx::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncAsByte(_program);
 }
 
 void Instrument_MacSfx::send(MidiChannel *mc) {
diff --git a/engines/scumm/imuse/instrument.h b/engines/scumm/imuse/instrument.h
index 47f556b..374b635 100644
--- a/engines/scumm/imuse/instrument.h
+++ b/engines/scumm/imuse/instrument.h
@@ -25,24 +25,23 @@
 
 
 #include "common/scummsys.h"
+#include "common/serializer.h"
 
 class MidiChannel;
 
 namespace Scumm {
 
-class Serializer;
 class Instrument;
 
-class InstrumentInternal {
+class InstrumentInternal : public Common::Serializable {
 public:
 	virtual ~InstrumentInternal() {}
-	virtual void saveOrLoad(Serializer *s) = 0;
 	virtual void send(MidiChannel *mc) = 0;
 	virtual void copy_to(Instrument *dest) = 0;
 	virtual bool is_valid() = 0;
 };
 
-class Instrument {
+class Instrument : public Common::Serializable {
 private:
 	byte _type;
 	InstrumentInternal *_instrument;
@@ -78,7 +77,7 @@ public:
 
 	byte getType() { return _type; }
 	bool isValid() { return (_instrument ? _instrument->is_valid() : false); }
-	void saveOrLoad(Serializer *s);
+	void saveLoadWithSerializer(Common::Serializer &s);
 	void send(MidiChannel *mc) {
 		if (_instrument)
 			_instrument->send(mc);
diff --git a/engines/scumm/imuse_digi/dimuse.cpp b/engines/scumm/imuse_digi/dimuse.cpp
index 3f61946..9dac8b7 100644
--- a/engines/scumm/imuse_digi/dimuse.cpp
+++ b/engines/scumm/imuse_digi/dimuse.cpp
@@ -103,61 +103,55 @@ void IMuseDigital::resetState() {
 	_triggerUsed = false;
 }
 
-void IMuseDigital::saveOrLoad(Serializer *ser) {
-	Common::StackLock lock(_mutex, "IMuseDigital::saveOrLoad()");
-
-	const SaveLoadEntry mainEntries[] = {
-		MK_OBSOLETE(IMuseDigital, _volVoice, sleInt32, VER(31), VER(42)),
-		MK_OBSOLETE(IMuseDigital, _volSfx, sleInt32, VER(31), VER(42)),
-		MK_OBSOLETE(IMuseDigital, _volMusic, sleInt32, VER(31), VER(42)),
-		MKLINE(IMuseDigital, _curMusicState, sleInt32, VER(31)),
-		MKLINE(IMuseDigital, _curMusicSeq, sleInt32, VER(31)),
-		MKLINE(IMuseDigital, _curMusicCue, sleInt32, VER(31)),
-		MKLINE(IMuseDigital, _nextSeqToPlay, sleInt32, VER(31)),
-		MKLINE(IMuseDigital, _radioChatterSFX, sleByte, VER(76)),
-		MKARRAY(IMuseDigital, _attributes[0], sleInt32, 188, VER(31)),
-		MKEND()
-	};
-
-	const SaveLoadEntry trackEntries[] = {
-		MKLINE(Track, pan, sleInt8, VER(31)),
-		MKLINE(Track, vol, sleInt32, VER(31)),
-		MKLINE(Track, volFadeDest, sleInt32, VER(31)),
-		MKLINE(Track, volFadeStep, sleInt32, VER(31)),
-		MKLINE(Track, volFadeDelay, sleInt32, VER(31)),
-		MKLINE(Track, volFadeUsed, sleByte, VER(31)),
-		MKLINE(Track, soundId, sleInt32, VER(31)),
-		MKARRAY(Track, soundName[0], sleByte, 15, VER(31)),
-		MKLINE(Track, used, sleByte, VER(31)),
-		MKLINE(Track, toBeRemoved, sleByte, VER(31)),
-		MKLINE(Track, souStreamUsed, sleByte, VER(31)),
-		MK_OBSOLETE(Track, mixerStreamRunning, sleByte, VER(31), VER(76)),
-		MKLINE(Track, soundPriority, sleInt32, VER(31)),
-		MKLINE(Track, regionOffset, sleInt32, VER(31)),
-		MK_OBSOLETE(Track, trackOffset, sleInt32, VER(31), VER(31)),
-		MKLINE(Track, dataOffset, sleInt32, VER(31)),
-		MKLINE(Track, curRegion, sleInt32, VER(31)),
-		MKLINE(Track, curHookId, sleInt32, VER(31)),
-		MKLINE(Track, volGroupId, sleInt32, VER(31)),
-		MKLINE(Track, soundType, sleInt32, VER(31)),
-		MKLINE(Track, feedSize, sleInt32, VER(31)),
-		MKLINE(Track, dataMod12Bit, sleInt32, VER(31)),
-		MKLINE(Track, mixerFlags, sleInt32, VER(31)),
-		MK_OBSOLETE(Track, mixerVol, sleInt32, VER(31), VER(42)),
-		MK_OBSOLETE(Track, mixerPan, sleInt32, VER(31), VER(42)),
-		MKLINE(Track, sndDataExtComp, sleByte, VER(45)),
-		MKEND()
-	};
-
-	ser->saveLoadEntries(this, mainEntries);
+static void syncWithSerializer(Common::Serializer &s, Track &t) {
+	s.syncAsSByte(t.pan, VER(31));
+	s.syncAsSint32LE(t.vol, VER(31));
+	s.syncAsSint32LE(t.volFadeDest, VER(31));
+	s.syncAsSint32LE(t.volFadeStep, VER(31));
+	s.syncAsSint32LE(t.volFadeDelay, VER(31));
+	s.syncAsByte(t.volFadeUsed, VER(31));
+	s.syncAsSint32LE(t.soundId, VER(31));
+	s.syncArray(t.soundName, 15, Common::Serializer::SByte, VER(31));
+	s.syncAsByte(t.used, VER(31));
+	s.syncAsByte(t.toBeRemoved, VER(31));
+	s.syncAsByte(t.souStreamUsed, VER(31));
+	s.skip(1, VER(31), VER(76)); // mixerStreamRunning
+	s.syncAsSint32LE(t.soundPriority, VER(31));
+	s.syncAsSint32LE(t.regionOffset, VER(31));
+	s.skip(4, VER(31), VER(31)); // trackOffset
+	s.syncAsSint32LE(t.dataOffset, VER(31));
+	s.syncAsSint32LE(t.curRegion, VER(31));
+	s.syncAsSint32LE(t.curHookId, VER(31));
+	s.syncAsSint32LE(t.volGroupId, VER(31));
+	s.syncAsSint32LE(t.soundType, VER(31));
+	s.syncAsSint32LE(t.feedSize, VER(31));
+	s.syncAsSint32LE(t.dataMod12Bit, VER(31));
+	s.syncAsSint32LE(t.mixerFlags, VER(31));
+	s.skip(4, VER(31), VER(42)); // mixerVol
+	s.skip(4, VER(31), VER(42)); // mixerPan
+	s.syncAsByte(t.sndDataExtComp, VER(45));
+}
+
+void IMuseDigital::saveLoadEarly(Common::Serializer &s) {
+	Common::StackLock lock(_mutex, "IMuseDigital::saveLoadEarly()");
+
+	s.skip(4, VER(31), VER(42)); // _volVoice
+	s.skip(4, VER(31), VER(42)); // _volSfx
+	s.skip(4, VER(31), VER(42)); // _volMusic
+	s.syncAsSint32LE(_curMusicState, VER(31));
+	s.syncAsSint32LE(_curMusicSeq, VER(31));
+	s.syncAsSint32LE(_curMusicCue, VER(31));
+	s.syncAsSint32LE(_nextSeqToPlay, VER(31));
+	s.syncAsByte(_radioChatterSFX, VER(76));
+	s.syncArray(_attributes, 188, Common::Serializer::Sint32LE, VER(31));
 
 	for (int l = 0; l < MAX_DIGITAL_TRACKS + MAX_DIGITAL_FADETRACKS; l++) {
 		Track *track = _track[l];
-		if (ser->isLoading()) {
+		if (s.isLoading()) {
 			memset(track, 0, sizeof(Track));
 		}
-		ser->saveLoadEntries(track, trackEntries);
-		if (ser->isLoading()) {
+		syncWithSerializer(s, *track);
+		if (s.isLoading()) {
 			_track[l]->trackId = l;
 			if (!track->used)
 				continue;
diff --git a/engines/scumm/imuse_digi/dimuse.h b/engines/scumm/imuse_digi/dimuse.h
index 02f899d..86c8d21 100644
--- a/engines/scumm/imuse_digi/dimuse.h
+++ b/engines/scumm/imuse_digi/dimuse.h
@@ -25,6 +25,7 @@
 
 #include "common/scummsys.h"
 #include "common/mutex.h"
+#include "common/serializer.h"
 #include "common/textconsole.h"
 #include "common/util.h"
 
@@ -48,7 +49,6 @@ enum {
 
 struct imuseDigTable;
 struct imuseComiTable;
-class Serializer;
 class ScummEngine_v7;
 struct Track;
 
@@ -136,7 +136,7 @@ public:
 	void startSound(int sound)
 		{ error("IMuseDigital::startSound(int) should be never called"); }
 
-	void saveOrLoad(Serializer *ser);
+	void saveLoadEarly(Common::Serializer &ser);
 	void resetState();
 	void setRadioChatterSFX(bool state) {
 		_radioChatterSFX = state;
diff --git a/engines/scumm/music.h b/engines/scumm/music.h
index e170647..9404ce7 100644
--- a/engines/scumm/music.h
+++ b/engines/scumm/music.h
@@ -23,12 +23,11 @@
 #ifndef SCUMM_MUSIC_H
 #define SCUMM_MUSIC_H
 
+#include "common/serializer.h"
 #include "common/scummsys.h"
 
 namespace Scumm {
 
-class Serializer;
-
 /**
  * Pure virtual base class for the various music/sound engines used in Scumm
  * games. In particular, the iMuse code provides a subclass of this. There are
@@ -39,7 +38,7 @@ class Serializer;
  *
  * Instantiated by class Scumm.
  */
-class MusicEngine {
+class MusicEngine : public Common::Serializable {
 public:
 	virtual ~MusicEngine() {}
 
@@ -84,7 +83,7 @@ public:
 	/**
 	 * Save or load the music state.
 	 */
-	virtual void saveLoadWithSerializer(Serializer *ser) {}
+	virtual void saveLoadWithSerializer(Common::Serializer &ser) {}
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index 55bbeee..2de8ac9 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -191,27 +191,27 @@ int Player_AD::getSoundStatus(int sound) const {
 	return false;
 }
 
-void Player_AD::saveLoadWithSerializer(Serializer *ser) {
+void Player_AD::saveLoadWithSerializer(Common::Serializer &s) {
 	Common::StackLock lock(_mutex);
 
-	if (ser->getVersion() < VER(95)) {
+	if (s.getVersion() < VER(95)) {
 		IMuse *dummyImuse = IMuse::create(_vm->_system, NULL, NULL);
-		dummyImuse->save_or_load(ser, _vm, false);
+		dummyImuse->saveLoadWithSerializer(s, _vm, false);
 		delete dummyImuse;
 		return;
 	}
 
-	if (ser->getVersion() >= VER(96)) {
+	if (s.getVersion() >= VER(96)) {
 		int32 res[4] = {
 			_musicResource, _sfx[0].resource, _sfx[1].resource, _sfx[2].resource
 		};
 
 		// The first thing we save is a list of sound resources being played
 		// at the moment.
-		ser->saveLoadArrayOf(res, 4, sizeof(res[0]), sleInt32);
+		s.syncArray(res, 4, Common::Serializer::Sint32LE);
 
 		// If we are loading start the music again at this point.
-		if (ser->isLoading()) {
+		if (s.isLoading()) {
 			if (res[0] != -1) {
 				startSound(res[0]);
 			}
@@ -219,26 +219,21 @@ void Player_AD::saveLoadWithSerializer(Serializer *ser) {
 
 		uint32 musicOffset = _curOffset;
 
-		static const SaveLoadEntry musicData[] = {
-			MKLINE(Player_AD, _engineMusicTimer, sleInt32, VER(96)),
-			MKLINE(Player_AD, _musicTimer, sleUint32, VER(96)),
-			MKLINE(Player_AD, _internalMusicTimer, sleUint32, VER(96)),
-			MKLINE(Player_AD, _curOffset, sleUint32, VER(96)),
-			MKLINE(Player_AD, _nextEventTimer, sleUint32, VER(96)),
-			MKEND()
-		};
-
-		ser->saveLoadEntries(this, musicData);
+		s.syncAsSint32LE(_engineMusicTimer, VER(96));
+		s.syncAsUint32LE(_musicTimer, VER(96));
+		s.syncAsUint32LE(_internalMusicTimer, VER(96));
+		s.syncAsUint32LE(_curOffset, VER(96));
+		s.syncAsUint32LE(_nextEventTimer, VER(96));
 
 		// We seek back to the old music position.
-		if (ser->isLoading()) {
+		if (s.isLoading()) {
 			SWAP(musicOffset, _curOffset);
 			musicSeekTo(musicOffset);
 		}
 
 		// Finally start up the SFX. This makes sure that they are not
 		// accidently stopped while seeking to the old music position.
-		if (ser->isLoading()) {
+		if (s.isLoading()) {
 			for (int i = 1; i < ARRAYSIZE(res); ++i) {
 				if (res[i] != -1) {
 					startSound(res[i]);
diff --git a/engines/scumm/players/player_ad.h b/engines/scumm/players/player_ad.h
index 1e665e8..20c8b3d 100644
--- a/engines/scumm/players/player_ad.h
+++ b/engines/scumm/players/player_ad.h
@@ -26,6 +26,7 @@
 #include "scumm/music.h"
 
 #include "common/mutex.h"
+#include "common/serializer.h"
 
 namespace OPL {
 class OPL;
@@ -34,7 +35,6 @@ class OPL;
 namespace Scumm {
 
 class ScummEngine;
-class Serializer;
 
 /**
  * Sound output for v3/v4 AdLib data.
@@ -52,7 +52,7 @@ public:
 	virtual int  getMusicTimer();
 	virtual int  getSoundStatus(int sound) const;
 
-	virtual void saveLoadWithSerializer(Serializer *ser);
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
 
 	// Timer callback
 	void onTimer();
diff --git a/engines/scumm/players/player_mac.cpp b/engines/scumm/players/player_mac.cpp
index 87406f4..cc65adc 100644
--- a/engines/scumm/players/player_mac.cpp
+++ b/engines/scumm/players/player_mac.cpp
@@ -97,53 +97,46 @@ Player_Mac::~Player_Mac() {
 	delete[] _channel;
 }
 
-void Player_Mac::saveLoadWithSerializer(Serializer *ser) {
+void syncWithSerializer(Common::Serializer &s, Player_Mac::Channel &c) {
+	s.syncAsUint16LE(c._pos, VER(94));
+	s.syncAsSint32LE(c._pitchModifier, VER(94));
+	s.syncAsByte(c._velocity, VER(94));
+	s.syncAsUint32LE(c._remaining, VER(94));
+	s.syncAsByte(c._notesLeft, VER(94));
+}
+
+void syncWithSerializer(Common::Serializer &s, Player_Mac::Instrument &i) {
+	s.syncAsUint32LE(i._pos, VER(94));
+	s.syncAsUint32LE(i._subPos, VER(94));
+}
+
+void Player_Mac::saveLoadWithSerializer(Common::Serializer &s) {
 	Common::StackLock lock(_mutex);
-	if (ser->getVersion() < VER(94)) {
-		if (_vm->_game.id == GID_MONKEY && ser->isLoading()) {
+	if (s.getVersion() < VER(94)) {
+		if (_vm->_game.id == GID_MONKEY && s.isLoading()) {
 			IMuse *dummyImuse = IMuse::create(_vm->_system, NULL, NULL);
-			dummyImuse->save_or_load(ser, _vm, false);
+			dummyImuse->saveLoadWithSerializer(s, _vm, false);
 			delete dummyImuse;
 		}
 	} else {
-		static const SaveLoadEntry musicEntries[] = {
-			MKLINE(Player_Mac, _sampleRate, sleUint32, VER(94)),
-			MKLINE(Player_Mac, _soundPlaying, sleInt16, VER(94)),
-			MKEND()
-		};
-
-		static const SaveLoadEntry channelEntries[] = {
-			MKLINE(Channel, _pos, sleUint16, VER(94)),
-			MKLINE(Channel, _pitchModifier, sleInt32, VER(94)),
-			MKLINE(Channel, _velocity, sleUint8, VER(94)),
-			MKLINE(Channel, _remaining, sleUint32, VER(94)),
-			MKLINE(Channel, _notesLeft, sleUint8, VER(94)),
-			MKEND()
-		};
-
-		static const SaveLoadEntry instrumentEntries[] = {
-			MKLINE(Instrument, _pos, sleUint32, VER(94)),
-			MKLINE(Instrument, _subPos, sleUint32, VER(94)),
-			MKEND()
-		};
-
 		uint32 mixerSampleRate = _sampleRate;
 		int i;
 
-		ser->saveLoadEntries(this, musicEntries);
+		s.syncAsUint32LE(_sampleRate, VER(94));
+		s.syncAsSint16LE(_soundPlaying, VER(94));
 
-		if (ser->isLoading() && _soundPlaying != -1) {
+		if (s.isLoading() && _soundPlaying != -1) {
 			const byte *ptr = _vm->getResourceAddress(rtSound, _soundPlaying);
 			assert(ptr);
 			loadMusic(ptr);
 		}
 
-		ser->saveLoadArrayOf(_channel, _numberOfChannels, sizeof(Channel), channelEntries);
+		s.syncArray(_channel, _numberOfChannels, syncWithSerializer);
 		for (i = 0; i < _numberOfChannels; i++) {
-			ser->saveLoadEntries(&_channel[i], instrumentEntries);
+			syncWithSerializer(s, _channel[i]);
 		}
 
-		if (ser->isLoading()) {
+		if (s.isLoading()) {
 			// If necessary, adjust the channel data to fit the
 			// current sample rate.
 			if (_soundPlaying != -1 && _sampleRate != mixerSampleRate) {
diff --git a/engines/scumm/players/player_mac.h b/engines/scumm/players/player_mac.h
index d247ce9..897960d 100644
--- a/engines/scumm/players/player_mac.h
+++ b/engines/scumm/players/player_mac.h
@@ -63,7 +63,7 @@ public:
 	virtual bool endOfData() const { return false; }
 	virtual int getRate() const { return _sampleRate; }
 
-	virtual void saveLoadWithSerializer(Serializer *ser);
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
 
 private:
 	Common::Mutex _mutex;
@@ -92,6 +92,7 @@ private:
 
 		void generateSamples(int16 *data, int pitchModifier, int volume, int numSamples, int remainingSamplesOnNote, bool fadeNoteEnds);
 	};
+	friend void syncWithSerializer(Common::Serializer &, Instrument &);
 
 	int _pitchTable[128];
 	int _numberOfChannels;
@@ -120,6 +121,7 @@ protected:
 
 		bool loadInstrument(Common::SeekableReadStream *stream);
  	};
+	friend void syncWithSerializer(Common::Serializer &, Channel &);
 
 	ScummEngine *const _vm;
 	Channel *_channel;
diff --git a/engines/scumm/players/player_towns.cpp b/engines/scumm/players/player_towns.cpp
index d540fc4..1608020 100644
--- a/engines/scumm/players/player_towns.cpp
+++ b/engines/scumm/players/player_towns.cpp
@@ -46,19 +46,18 @@ int Player_Towns::getSoundStatus(int sound) const {
 	return 0;
 }
 
-void Player_Towns::saveLoadWithSerializer(Serializer *ser) {
-	static const SaveLoadEntry pcmEntries[] = {
-		MKLINE(PcmCurrentSound, index, sleInt16, VER(81)),
-		MKLINE(PcmCurrentSound, chan, sleInt16, VER(81)),
-		MKLINE(PcmCurrentSound, note, sleUint8, VER(81)),
-		MKLINE(PcmCurrentSound, velo, sleUint8, VER(81)),
-		MKLINE(PcmCurrentSound, pan, sleUint8, VER(81)),
-		MKLINE(PcmCurrentSound, paused, sleUint8, VER(81)),
-		MKLINE(PcmCurrentSound, looping, sleUint8, VER(81)),
-		MKLINE(PcmCurrentSound, priority, sleUint32, VER(81)),
-		MKEND()
-	};
-
+void syncWithSerializer(Common::Serializer &s, Player_Towns::PcmCurrentSound &pcs) {
+	s.syncAsSint16LE(pcs.index, VER(81));
+	s.syncAsSint16LE(pcs.chan, VER(81));
+	s.syncAsByte(pcs.note, VER(81));
+	s.syncAsByte(pcs.velo, VER(81));
+	s.syncAsByte(pcs.pan, VER(81));
+	s.syncAsByte(pcs.paused, VER(81));
+	s.syncAsByte(pcs.looping, VER(81));
+	s.syncAsUint32LE(pcs.priority, VER(81));
+}
+
+void Player_Towns::saveLoadWithSerializer(Common::Serializer &s) {
 	for (int i = 1; i < 9; i++) {
 		if (!_pcmCurrentSound[i].index)
 			continue;
@@ -71,7 +70,7 @@ void Player_Towns::saveLoadWithSerializer(Serializer *ser) {
 		_pcmCurrentSound[i].index = 0;
 	}
 
-	ser->saveLoadArrayOf(_pcmCurrentSound, 9, sizeof(PcmCurrentSound), pcmEntries);
+	s.syncArray(_pcmCurrentSound, 9, syncWithSerializer);
 }
 
 void Player_Towns::restoreAfterLoad() {
@@ -362,34 +361,24 @@ void Player_Towns_v1::setSoundNote(int sound, int note) {
 		_soundOverride[sound].note = note;
 }
 
-void Player_Towns_v1::saveLoadWithSerializer(Serializer *ser) {
+void Player_Towns_v1::saveLoadWithSerializer(Common::Serializer &s) {
 	_cdaCurrentSoundTemp = (_vm->_sound->pollCD() && _cdaNumLoops > 1) ? _cdaCurrentSound & 0xff : 0;
 	_cdaNumLoopsTemp = _cdaNumLoops & 0xff;
 
-	static const SaveLoadEntry cdEntries[] = {
-		MKLINE(Player_Towns_v1, _cdaCurrentSoundTemp, sleUint8, VER(81)),
-		MKLINE(Player_Towns_v1, _cdaNumLoopsTemp, sleUint8, VER(81)),
-		MKLINE(Player_Towns_v1, _cdaVolLeft, sleUint8, VER(81)),
-		MKLINE(Player_Towns_v1, _cdaVolRight, sleUint8, VER(81)),
-		MKEND()
-	};
-
-	ser->saveLoadEntries(this, cdEntries);
+	s.syncAsByte(_cdaCurrentSoundTemp, VER(81));
+	s.syncAsByte(_cdaNumLoopsTemp, VER(81));
+	s.syncAsByte(_cdaVolLeft, VER(81));
+	s.syncAsByte(_cdaVolRight, VER(81));
 
 	if (!_eupLooping && !_player->isPlaying())
 		_eupCurrentSound = 0;
 
-	static const SaveLoadEntry eupEntries[] = {
-		MKLINE(Player_Towns_v1, _eupCurrentSound, sleUint8, VER(81)),
-		MKLINE(Player_Towns_v1, _eupLooping, sleUint8, VER(81)),
-		MKLINE(Player_Towns_v1, _eupVolLeft, sleUint8, VER(81)),
-		MKLINE(Player_Towns_v1, _eupVolRight, sleUint8, VER(81)),
-		MKEND()
-	};
-
-	ser->saveLoadEntries(this, eupEntries);
+	s.syncAsByte(_eupCurrentSound, VER(81));
+	s.syncAsByte(_eupLooping, VER(81));
+	s.syncAsByte(_eupVolLeft, VER(81));
+	s.syncAsByte(_eupVolRight, VER(81));
 
-	Player_Towns::saveLoadWithSerializer(ser);
+	Player_Towns::saveLoadWithSerializer(s);
 }
 
 void Player_Towns_v1::restoreAfterLoad() {
@@ -721,9 +710,9 @@ int32 Player_Towns_v2::doCommand(int numargs, int args[]) {
 	return res;
 }
 
-void Player_Towns_v2::saveLoadWithSerializer(Serializer *ser) {
-	if (ser->getVersion() >= 83)
-		Player_Towns::saveLoadWithSerializer(ser);
+void Player_Towns_v2::saveLoadWithSerializer(Common::Serializer &s) {
+	if (s.getVersion() >= VER(83))
+		Player_Towns::saveLoadWithSerializer(s);
 }
 
 void Player_Towns_v2::playVocTrack(const uint8 *data) {
diff --git a/engines/scumm/players/player_towns.h b/engines/scumm/players/player_towns.h
index 576d17e..ad51c3e 100644
--- a/engines/scumm/players/player_towns.h
+++ b/engines/scumm/players/player_towns.h
@@ -43,7 +43,7 @@ public:
 
 	virtual int32 doCommand(int numargs, int args[]) = 0;
 
-	virtual void saveLoadWithSerializer(Serializer *ser);
+	virtual void saveLoadWithSerializer(Common::Serializer &ser);
 	virtual void restoreAfterLoad();
 
 	// version 1 specific
@@ -69,6 +69,7 @@ protected:
 		uint8 looping;
 		uint32 priority;
 	} _pcmCurrentSound[9];
+	friend void syncWithSerializer(Common::Serializer &, PcmCurrentSound &);
 
 	uint8 _unkFlags;
 
@@ -101,7 +102,7 @@ public:
 	void setSoundVolume(int sound, int left, int right);
 	void setSoundNote(int sound, int note);
 
-	void saveLoadWithSerializer(Serializer *ser);
+	void saveLoadWithSerializer(Common::Serializer &ser);
 	void restoreAfterLoad();
 
 private:
@@ -154,7 +155,7 @@ public:
 
 	int32 doCommand(int numargs, int args[]);
 
-	void saveLoadWithSerializer(Serializer *ser);
+	void saveLoadWithSerializer(Common::Serializer &ser);
 
 private:
 	void playVocTrack(const uint8 *data);
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 06d5646..3e0a7f1 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -23,6 +23,7 @@
 #include "common/config-manager.h"
 #include "common/memstream.h"
 #include "common/savefile.h"
+#include "common/serializer.h"
 #include "common/system.h"
 #include "common/zlib.h"
 
@@ -185,8 +186,9 @@ bool ScummEngine::saveState(Common::WriteStream *out, bool writeHeader) {
 #endif
 	saveInfos(out);
 
-	Serializer ser(0, out, CURRENT_VER);
-	saveOrLoad(&ser);
+	Common::Serializer ser(0, out);
+	ser.setVersion(CURRENT_VER);
+	saveLoadWithSerializer(ser);
 	return true;
 }
 
@@ -442,8 +444,9 @@ bool ScummEngine::loadState(int slot, bool compat, Common::String &filename) {
 	//
 	// Now do the actual loading
 	//
-	Serializer ser(in, 0, hdr.ver);
-	saveOrLoad(&ser);
+	Common::Serializer ser(in, 0);
+	ser.setVersion(hdr.ver);
+	saveLoadWithSerializer(ser);
 	delete in;
 
 	// Update volume settings
@@ -793,334 +796,337 @@ void ScummEngine::saveInfos(Common::WriteStream *file) {
 	file->writeUint16BE(section.time);
 }
 
-void ScummEngine::saveOrLoad(Serializer *s) {
-	const SaveLoadEntry objectEntries[] = {
-		MKLINE(ObjectData, OBIMoffset, sleUint32, VER(8)),
-		MKLINE(ObjectData, OBCDoffset, sleUint32, VER(8)),
-		MKLINE(ObjectData, walk_x, sleUint16, VER(8)),
-		MKLINE(ObjectData, walk_y, sleUint16, VER(8)),
-		MKLINE(ObjectData, obj_nr, sleUint16, VER(8)),
-		MKLINE(ObjectData, x_pos, sleInt16, VER(8)),
-		MKLINE(ObjectData, y_pos, sleInt16, VER(8)),
-		MKLINE(ObjectData, width, sleUint16, VER(8)),
-		MKLINE(ObjectData, height, sleUint16, VER(8)),
-		MKLINE(ObjectData, actordir, sleByte, VER(8)),
-		MKLINE(ObjectData, parentstate, sleByte, VER(8)),
-		MKLINE(ObjectData, parent, sleByte, VER(8)),
-		MKLINE(ObjectData, state, sleByte, VER(8)),
-		MKLINE(ObjectData, fl_object_index, sleByte, VER(8)),
-		MKLINE(ObjectData, flags, sleByte, VER(46)),
-		MKEND()
-	};
-
-	const SaveLoadEntry verbEntries[] = {
-		MKLINE(VerbSlot, curRect.left, sleInt16, VER(8)),
-		MKLINE(VerbSlot, curRect.top, sleInt16, VER(8)),
-		MKLINE(VerbSlot, curRect.right, sleInt16, VER(8)),
-		MKLINE(VerbSlot, curRect.bottom, sleInt16, VER(8)),
-		MKLINE(VerbSlot, oldRect.left, sleInt16, VER(8)),
-		MKLINE(VerbSlot, oldRect.top, sleInt16, VER(8)),
-		MKLINE(VerbSlot, oldRect.right, sleInt16, VER(8)),
-		MKLINE(VerbSlot, oldRect.bottom, sleInt16, VER(8)),
-
-		MKLINE_OLD(VerbSlot, verbid, sleByte, VER(8), VER(11)),
-		MKLINE(VerbSlot, verbid, sleInt16, VER(12)),
-
-		MKLINE(VerbSlot, color, sleByte, VER(8)),
-		MKLINE(VerbSlot, hicolor, sleByte, VER(8)),
-		MKLINE(VerbSlot, dimcolor, sleByte, VER(8)),
-		MKLINE(VerbSlot, bkcolor, sleByte, VER(8)),
-		MKLINE(VerbSlot, type, sleByte, VER(8)),
-		MKLINE(VerbSlot, charset_nr, sleByte, VER(8)),
-		MKLINE(VerbSlot, curmode, sleByte, VER(8)),
-		MKLINE(VerbSlot, saveid, sleByte, VER(8)),
-		MKLINE(VerbSlot, key, sleByte, VER(8)),
-		MKLINE(VerbSlot, center, sleByte, VER(8)),
-		MKLINE(VerbSlot, prep, sleByte, VER(8)),
-		MKLINE(VerbSlot, imgindex, sleUint16, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry mainEntries[] = {
-		MKARRAY(ScummEngine, _gameMD5[0], sleUint8, 16, VER(39)),
-		MK_OBSOLETE(ScummEngine, _roomWidth, sleUint16, VER(8), VER(50)),
-		MK_OBSOLETE(ScummEngine, _roomHeight, sleUint16, VER(8), VER(50)),
-		MK_OBSOLETE(ScummEngine, _ENCD_offs, sleUint32, VER(8), VER(50)),
-		MK_OBSOLETE(ScummEngine, _EXCD_offs, sleUint32, VER(8), VER(50)),
-		MK_OBSOLETE(ScummEngine, _IM00_offs, sleUint32, VER(8), VER(50)),
-		MK_OBSOLETE(ScummEngine, _CLUT_offs, sleUint32, VER(8), VER(50)),
-		MK_OBSOLETE(ScummEngine, _EPAL_offs, sleUint32, VER(8), VER(9)),
-		MK_OBSOLETE(ScummEngine, _PALS_offs, sleUint32, VER(8), VER(50)),
-		MKLINE(ScummEngine, _curPalIndex, sleByte, VER(8)),
-		MKLINE(ScummEngine, _currentRoom, sleByte, VER(8)),
-		MKLINE(ScummEngine, _roomResource, sleByte, VER(8)),
-		MKLINE(ScummEngine, _numObjectsInRoom, sleByte, VER(8)),
-		MKLINE(ScummEngine, _currentScript, sleByte, VER(8)),
-		MK_OBSOLETE_ARRAY(ScummEngine, _localScriptOffsets[0], sleUint32, _numLocalScripts, VER(8), VER(50)),
-
-
-		// vm.localvar grew from 25 to 40 script entries and then from
-		// 16 to 32 bit variables (but that wasn't reflect here)... and
-		// THEN from 16 to 25 variables.
-		MKARRAY2_OLD(ScummEngine, vm.localvar[0][0], sleUint16, 17, 25, (byte *)vm.localvar[1] - (byte *)vm.localvar[0], VER(8), VER(8)),
-		MKARRAY2_OLD(ScummEngine, vm.localvar[0][0], sleUint16, 17, 40, (byte *)vm.localvar[1] - (byte *)vm.localvar[0], VER(9), VER(14)),
-
-		// We used to save 25 * 40 = 1000 blocks; but actually, each 'row consisted of 26 entry,
-		// i.e. 26 * 40 = 1040. Thus the last 40 blocks of localvar where not saved at all. To be
-		// able to load this screwed format, we use a trick: We load 26 * 38 = 988 blocks.
-		// Then, we mark the followin 12 blocks (24 bytes) as obsolete.
-		MKARRAY2_OLD(ScummEngine, vm.localvar[0][0], sleUint16, 26, 38, (byte *)vm.localvar[1] - (byte *)vm.localvar[0], VER(15), VER(17)),
-		MK_OBSOLETE_ARRAY(ScummEngine, vm.localvar[39][0], sleUint16, 12, VER(15), VER(17)),
-
-		// This was the first proper multi dimensional version of the localvars, with 32 bit values
-		MKARRAY2_OLD(ScummEngine, vm.localvar[0][0], sleUint32, 26, 40, (byte *)vm.localvar[1] - (byte *)vm.localvar[0], VER(18), VER(19)),
-
-		// Then we doubled the script slots again, from 40 to 80
-		MKARRAY2(ScummEngine, vm.localvar[0][0], sleUint32, 26, NUM_SCRIPT_SLOT, (byte *)vm.localvar[1] - (byte *)vm.localvar[0], VER(20)),
-
-
-		MKARRAY(ScummEngine, _resourceMapper[0], sleByte, 128, VER(8)),
-		MKARRAY(ScummEngine, _charsetColorMap[0], sleByte, 16, VER(8)),
-
-		// _charsetData grew from 10*16, to 15*16, to 23*16 bytes
-		MKARRAY_OLD(ScummEngine, _charsetData[0][0], sleByte, 10 * 16, VER(8), VER(9)),
-		MKARRAY_OLD(ScummEngine, _charsetData[0][0], sleByte, 15 * 16, VER(10), VER(66)),
-		MKARRAY(ScummEngine, _charsetData[0][0], sleByte, 23 * 16, VER(67)),
-
-		MK_OBSOLETE(ScummEngine, _curExecScript, sleUint16, VER(8), VER(62)),
-
-		MKLINE(ScummEngine, camera._dest.x, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._dest.y, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._cur.x, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._cur.y, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._last.x, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._last.y, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._accel.x, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._accel.y, sleInt16, VER(8)),
-		MKLINE(ScummEngine, _screenStartStrip, sleInt16, VER(8)),
-		MKLINE(ScummEngine, _screenEndStrip, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._mode, sleByte, VER(8)),
-		MKLINE(ScummEngine, camera._follows, sleByte, VER(8)),
-		MKLINE(ScummEngine, camera._leftTrigger, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._rightTrigger, sleInt16, VER(8)),
-		MKLINE(ScummEngine, camera._movingToActor, sleUint16, VER(8)),
-
-		MKLINE(ScummEngine, _actorToPrintStrFor, sleByte, VER(8)),
-		MKLINE(ScummEngine, _charsetColor, sleByte, VER(8)),
-
-		// _charsetBufPos was changed from byte to int
-		MKLINE_OLD(ScummEngine, _charsetBufPos, sleByte, VER(8), VER(9)),
-		MKLINE(ScummEngine, _charsetBufPos, sleInt16, VER(10)),
-
-		MKLINE(ScummEngine, _haveMsg, sleByte, VER(8)),
-		MKLINE(ScummEngine, _haveActorSpeechMsg, sleByte, VER(61)),
-		MKLINE(ScummEngine, _useTalkAnims, sleByte, VER(8)),
-
-		MKLINE(ScummEngine, _talkDelay, sleInt16, VER(8)),
-		MKLINE(ScummEngine, _defaultTalkDelay, sleInt16, VER(8)),
-		MK_OBSOLETE(ScummEngine, _numInMsgStack, sleInt16, VER(8), VER(27)),
-		MKLINE(ScummEngine, _sentenceNum, sleByte, VER(8)),
-
-		MKLINE(ScummEngine, vm.cutSceneStackPointer, sleByte, VER(8)),
-		MKARRAY(ScummEngine, vm.cutScenePtr[0], sleUint32, 5, VER(8)),
-		MKARRAY(ScummEngine, vm.cutSceneScript[0], sleByte, 5, VER(8)),
-		MKARRAY(ScummEngine, vm.cutSceneData[0], sleInt16, 5, VER(8)),
-		MKLINE(ScummEngine, vm.cutSceneScriptIndex, sleInt16, VER(8)),
-
-		MKLINE(ScummEngine, vm.numNestedScripts, sleByte, VER(8)),
-		MKLINE(ScummEngine, _userPut, sleByte, VER(8)),
-		MKLINE(ScummEngine, _userState, sleUint16, VER(17)),
-		MKLINE(ScummEngine, _cursor.state, sleByte, VER(8)),
-		MK_OBSOLETE(ScummEngine, _gdi->_cursorActive, sleByte, VER(8), VER(20)),
-		MKLINE(ScummEngine, _currentCursor, sleByte, VER(8)),
-		MKARRAY(ScummEngine, _grabbedCursor[0], sleByte, 8192, VER(20)),
-		MKLINE(ScummEngine, _cursor.width, sleInt16, VER(20)),
-		MKLINE(ScummEngine, _cursor.height, sleInt16, VER(20)),
-		MKLINE(ScummEngine, _cursor.hotspotX, sleInt16, VER(20)),
-		MKLINE(ScummEngine, _cursor.hotspotY, sleInt16, VER(20)),
-		MKLINE(ScummEngine, _cursor.animate, sleByte, VER(20)),
-		MKLINE(ScummEngine, _cursor.animateIndex, sleByte, VER(20)),
-		MKLINE(ScummEngine, _mouse.x, sleInt16, VER(20)),
-		MKLINE(ScummEngine, _mouse.y, sleInt16, VER(20)),
-
-		MKARRAY(ScummEngine, _colorUsedByCycle[0], sleByte, 256, VER(60)),
-		MKLINE(ScummEngine, _doEffect, sleByte, VER(8)),
-		MKLINE(ScummEngine, _switchRoomEffect, sleByte, VER(8)),
-		MKLINE(ScummEngine, _newEffect, sleByte, VER(8)),
-		MKLINE(ScummEngine, _switchRoomEffect2, sleByte, VER(8)),
-		MKLINE(ScummEngine, _bgNeedsRedraw, sleByte, VER(8)),
-
-		// The state of palManipulate is stored only since V10
-		MKLINE(ScummEngine, _palManipStart, sleByte, VER(10)),
-		MKLINE(ScummEngine, _palManipEnd, sleByte, VER(10)),
-		MKLINE(ScummEngine, _palManipCounter, sleUint16, VER(10)),
-
-		// gfxUsageBits grew from 200 to 410 entries. Then 3 * 410 entries:
-		MKARRAY_OLD(ScummEngine, gfxUsageBits[0], sleUint32, 200, VER(8), VER(9)),
-		MKARRAY_OLD(ScummEngine, gfxUsageBits[0], sleUint32, 410, VER(10), VER(13)),
-		MKARRAY(ScummEngine, gfxUsageBits[0], sleUint32, 3 * 410, VER(14)),
-
-		MK_OBSOLETE(ScummEngine, _gdi->_transparentColor, sleByte, VER(8), VER(50)),
-		MKARRAY(ScummEngine, _currentPalette[0], sleByte, 768, VER(8)),
-		MKARRAY(ScummEngine, _darkenPalette[0], sleByte, 768, VER(53)),
-
-		// Sam & Max specific palette replaced by _shadowPalette now.
-		MK_OBSOLETE_ARRAY(ScummEngine, _proc_special_palette[0], sleByte, 256, VER(8), VER(33)),
-
-		MKARRAY(ScummEngine, _charsetBuffer[0], sleByte, 256, VER(8)),
-
-		MKLINE(ScummEngine, _egoPositioned, sleByte, VER(8)),
-
-		// _gdi->_imgBufOffs grew from 4 to 5 entries. Then one day we realized
-		// that we don't have to store it since initBGBuffers() recomputes it.
-		MK_OBSOLETE_ARRAY(ScummEngine, _gdi->_imgBufOffs[0], sleUint16, 4, VER(8), VER(9)),
-		MK_OBSOLETE_ARRAY(ScummEngine, _gdi->_imgBufOffs[0], sleUint16, 5, VER(10), VER(26)),
-
-		// See _imgBufOffs: _numZBuffer is recomputed by initBGBuffers().
-		MK_OBSOLETE(ScummEngine, _gdi->_numZBuffer, sleByte, VER(8), VER(26)),
-
-		MKLINE(ScummEngine, _screenEffectFlag, sleByte, VER(8)),
-
-		MK_OBSOLETE(ScummEngine, _randSeed1, sleUint32, VER(8), VER(9)),
-		MK_OBSOLETE(ScummEngine, _randSeed2, sleUint32, VER(8), VER(9)),
-
-		// Converted _shakeEnabled to boolean and added a _shakeFrame field.
-		MKLINE_OLD(ScummEngine, _shakeEnabled, sleInt16, VER(8), VER(9)),
-		MKLINE(ScummEngine, _shakeEnabled, sleByte, VER(10)),
-		MKLINE(ScummEngine, _shakeFrame, sleUint32, VER(10)),
-
-		MKLINE(ScummEngine, _keepText, sleByte, VER(8)),
-
-		MKLINE(ScummEngine, _screenB, sleUint16, VER(8)),
-		MKLINE(ScummEngine, _screenH, sleUint16, VER(8)),
-
-		MKLINE(ScummEngine, _NESCostumeSet, sleUint16, VER(47)),
-
-		MK_OBSOLETE(ScummEngine, _cd_track, sleInt16, VER(9), VER(9)),
-		MK_OBSOLETE(ScummEngine, _cd_loops, sleInt16, VER(9), VER(9)),
-		MK_OBSOLETE(ScummEngine, _cd_frame, sleInt16, VER(9), VER(9)),
-		MK_OBSOLETE(ScummEngine, _cd_end, sleInt16, VER(9), VER(9)),
-
-		MKEND()
-	};
-
-	const SaveLoadEntry scriptSlotEntries[] = {
-		MKLINE(ScriptSlot, offs, sleUint32, VER(8)),
-		MKLINE(ScriptSlot, delay, sleInt32, VER(8)),
-		MKLINE(ScriptSlot, number, sleUint16, VER(8)),
-		MKLINE(ScriptSlot, delayFrameCount, sleUint16, VER(8)),
-		MKLINE(ScriptSlot, status, sleByte, VER(8)),
-		MKLINE(ScriptSlot, where, sleByte, VER(8)),
-		MKLINE(ScriptSlot, freezeResistant, sleByte, VER(8)),
-		MKLINE(ScriptSlot, recursive, sleByte, VER(8)),
-		MKLINE(ScriptSlot, freezeCount, sleByte, VER(8)),
-		MKLINE(ScriptSlot, didexec, sleByte, VER(8)),
-		MKLINE(ScriptSlot, cutsceneOverride, sleByte, VER(8)),
-		MKLINE(ScriptSlot, cycle, sleByte, VER(46)),
-		MK_OBSOLETE(ScriptSlot, unk5, sleByte, VER(8), VER(10)),
-		MKEND()
-	};
-
-	const SaveLoadEntry nestedScriptEntries[] = {
-		MKLINE(NestedScript, number, sleUint16, VER(8)),
-		MKLINE(NestedScript, where, sleByte, VER(8)),
-		MKLINE(NestedScript, slot, sleByte, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry sentenceTabEntries[] = {
-		MKLINE(SentenceTab, verb, sleUint8, VER(8)),
-		MKLINE(SentenceTab, preposition, sleUint8, VER(8)),
-		MKLINE(SentenceTab, objectA, sleUint16, VER(8)),
-		MKLINE(SentenceTab, objectB, sleUint16, VER(8)),
-		MKLINE(SentenceTab, freezeCount, sleUint8, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry stringTabEntries[] = {
-		// Then _default/restore of a StringTab entry becomes a one liner.
-		MKLINE(StringTab, xpos, sleInt16, VER(8)),
-		MKLINE(StringTab, _default.xpos, sleInt16, VER(8)),
-		MKLINE(StringTab, ypos, sleInt16, VER(8)),
-		MKLINE(StringTab, _default.ypos, sleInt16, VER(8)),
-		MKLINE(StringTab, right, sleInt16, VER(8)),
-		MKLINE(StringTab, _default.right, sleInt16, VER(8)),
-		MKLINE(StringTab, color, sleInt8, VER(8)),
-		MKLINE(StringTab, _default.color, sleInt8, VER(8)),
-		MKLINE(StringTab, charset, sleInt8, VER(8)),
-		MKLINE(StringTab, _default.charset, sleInt8, VER(8)),
-		MKLINE(StringTab, center, sleByte, VER(8)),
-		MKLINE(StringTab, _default.center, sleByte, VER(8)),
-		MKLINE(StringTab, overhead, sleByte, VER(8)),
-		MKLINE(StringTab, _default.overhead, sleByte, VER(8)),
-		MKLINE(StringTab, no_talk_anim, sleByte, VER(8)),
-		MKLINE(StringTab, _default.no_talk_anim, sleByte, VER(8)),
-		MKLINE(StringTab, wrapping, sleByte, VER(71)),
-		MKLINE(StringTab, _default.wrapping, sleByte, VER(71)),
-		MKEND()
-	};
-
-	const SaveLoadEntry colorCycleEntries[] = {
-		MKLINE(ColorCycle, delay, sleUint16, VER(8)),
-		MKLINE(ColorCycle, counter, sleUint16, VER(8)),
-		MKLINE(ColorCycle, flags, sleUint16, VER(8)),
-		MKLINE(ColorCycle, start, sleByte, VER(8)),
-		MKLINE(ColorCycle, end, sleByte, VER(8)),
-		MKEND()
-	};
-
-	const SaveLoadEntry scaleSlotsEntries[] = {
-		MKLINE(ScaleSlot, x1, sleUint16, VER(13)),
-		MKLINE(ScaleSlot, y1, sleUint16, VER(13)),
-		MKLINE(ScaleSlot, scale1, sleUint16, VER(13)),
-		MKLINE(ScaleSlot, x2, sleUint16, VER(13)),
-		MKLINE(ScaleSlot, y2, sleUint16, VER(13)),
-		MKLINE(ScaleSlot, scale2, sleUint16, VER(13)),
-		MKEND()
-	};
-
-	// MSVC6 FIX (Jamieson630):
-	// MSVC6 has a problem with any notation that involves
-	// more than one set of double colons ::
-	// The following MKLINE macros expand to such things
-	// as AudioCDManager::Status::playing, and MSVC6 has
-	// a fit with that. This typedef simplifies the notation
-	// to something MSVC6 can grasp.
-	typedef AudioCDManager::Status AudioCDManager_Status;
-	const SaveLoadEntry audioCDEntries[] = {
-		MKLINE(AudioCDManager_Status, playing, sleUint32, VER(24)),
-		MKLINE(AudioCDManager_Status, track, sleInt32, VER(24)),
-		MKLINE(AudioCDManager_Status, start, sleUint32, VER(24)),
-		MKLINE(AudioCDManager_Status, duration, sleUint32, VER(24)),
-		MKLINE(AudioCDManager_Status, numLoops, sleInt32, VER(24)),
-		MKEND()
-	};
+static void syncWithSerializer(Common::Serializer &s, ObjectData &od) {
+	s.syncAsUint32LE(od.OBIMoffset, VER(8));
+	s.syncAsUint32LE(od.OBCDoffset, VER(8));
+	s.syncAsUint16LE(od.walk_x, VER(8));
+	s.syncAsUint16LE(od.walk_y, VER(8));
+	s.syncAsUint16LE(od.obj_nr, VER(8));
+	s.syncAsSint16LE(od.x_pos, VER(8));
+	s.syncAsSint16LE(od.y_pos, VER(8));
+	s.syncAsUint16LE(od.width, VER(8));
+	s.syncAsUint16LE(od.height, VER(8));
+	s.syncAsByte(od.actordir, VER(8));
+	s.syncAsByte(od.parentstate, VER(8));
+	s.syncAsByte(od.parent, VER(8));
+	s.syncAsByte(od.state, VER(8));
+	s.syncAsByte(od.fl_object_index, VER(8));
+	s.syncAsByte(od.flags, VER(46));
+}
+
+static void syncWithSerializer(Common::Serializer &s, VerbSlot &vs) {
+	s.syncAsSint16LE(vs.curRect.left, VER(8));
+	s.syncAsSint16LE(vs.curRect.top, VER(8));
+	s.syncAsSint16LE(vs.curRect.right, VER(8));
+	s.syncAsSint16LE(vs.curRect.bottom, VER(8));
+	s.syncAsSint16LE(vs.oldRect.left, VER(8));
+	s.syncAsSint16LE(vs.oldRect.top, VER(8));
+	s.syncAsSint16LE(vs.oldRect.right, VER(8));
+	s.syncAsSint16LE(vs.oldRect.bottom, VER(8));
+	s.syncAsByte(vs.verbid, VER(8), VER(11));
+	s.syncAsSint16LE(vs.verbid, VER(12));
+	s.syncAsByte(vs.color, VER(8));
+	s.syncAsByte(vs.hicolor, VER(8));
+	s.syncAsByte(vs.dimcolor, VER(8));
+	s.syncAsByte(vs.bkcolor, VER(8));
+	s.syncAsByte(vs.type, VER(8));
+	s.syncAsByte(vs.charset_nr, VER(8));
+	s.syncAsByte(vs.curmode, VER(8));
+	s.syncAsByte(vs.saveid, VER(8));
+	s.syncAsByte(vs.key, VER(8));
+	s.syncAsByte(vs.center, VER(8));
+	s.syncAsByte(vs.prep, VER(8));
+	s.syncAsUint16LE(vs.imgindex, VER(8));
+}
+
+static void syncWithSerializer(Common::Serializer &s, ScriptSlot &ss) {
+	s.syncAsUint32LE(ss.offs, VER(8));
+	s.syncAsSint32LE(ss.delay, VER(8));
+	s.syncAsUint16LE(ss.number, VER(8));
+	s.syncAsUint16LE(ss.delayFrameCount, VER(8));
+	s.syncAsByte(ss.status, VER(8));
+	s.syncAsByte(ss.where, VER(8));
+	s.syncAsByte(ss.freezeResistant, VER(8));
+	s.syncAsByte(ss.recursive, VER(8));
+	s.syncAsByte(ss.freezeCount, VER(8));
+	s.syncAsByte(ss.didexec, VER(8));
+	s.syncAsByte(ss.cutsceneOverride, VER(8));
+	s.syncAsByte(ss.cycle, VER(46));
+	s.skip(1, VER(8), VER(10)); // unk5
+}
+
+static void syncWithSerializer(Common::Serializer &s, NestedScript &ns) {
+	s.syncAsUint16LE(ns.number, VER(8));
+	s.syncAsByte(ns.where, VER(8));
+	s.syncAsByte(ns.slot, VER(8));
+}
+
+static void syncWithSerializer(Common::Serializer &s, SentenceTab &st) {
+	s.syncAsByte(st.verb, VER(8));
+	s.syncAsByte(st.preposition, VER(8));
+	s.syncAsUint16LE(st.objectA, VER(8));
+	s.syncAsUint16LE(st.objectB, VER(8));
+	s.syncAsByte(st.freezeCount, VER(8));
+}
+
+static void syncWithSerializer(Common::Serializer &s, StringTab &st) {
+	s.syncAsSint16LE(st.xpos, VER(8));
+	s.syncAsSint16LE(st._default.xpos, VER(8));
+	s.syncAsSint16LE(st.ypos, VER(8));
+	s.syncAsSint16LE(st._default.ypos, VER(8));
+	s.syncAsSint16LE(st.right, VER(8));
+	s.syncAsSint16LE(st._default.right, VER(8));
+	s.syncAsSByte(st.color, VER(8));
+	s.syncAsSByte(st._default.color, VER(8));
+	s.syncAsSByte(st.charset, VER(8));
+	s.syncAsSByte(st._default.charset, VER(8));
+	s.syncAsByte(st.center, VER(8));
+	s.syncAsByte(st._default.center, VER(8));
+	s.syncAsByte(st.overhead, VER(8));
+	s.syncAsByte(st._default.overhead, VER(8));
+	s.syncAsByte(st.no_talk_anim, VER(8));
+	s.syncAsByte(st._default.no_talk_anim, VER(8));
+	s.syncAsByte(st.wrapping, VER(71));
+	s.syncAsByte(st._default.wrapping, VER(71));
+}
+
+static void syncWithSerializer(Common::Serializer &s, ColorCycle &cc) {
+	s.syncAsUint16LE(cc.delay, VER(8));
+	s.syncAsUint16LE(cc.counter, VER(8));
+	s.syncAsUint16LE(cc.flags, VER(8));
+	s.syncAsByte(cc.start, VER(8));
+	s.syncAsByte(cc.end, VER(8));
+}
+
+void syncWithSerializer(Common::Serializer &s, ScummEngine::ScaleSlot &ss) {
+	s.syncAsUint16LE(ss.x1, VER(13));
+	s.syncAsUint16LE(ss.y1, VER(13));
+	s.syncAsUint16LE(ss.scale1, VER(13));
+	s.syncAsUint16LE(ss.x2, VER(13));
+	s.syncAsUint16LE(ss.y2, VER(13));
+	s.syncAsUint16LE(ss.scale2, VER(13));
+}
+
+static void syncWithSerializer(Common::Serializer &s, AudioCDManager::Status &as) {
+	s.syncAsUint32LE(as.playing, VER(24));
+	s.syncAsSint32LE(as.track, VER(24));
+	s.syncAsUint32LE(as.start, VER(24));
+	s.syncAsUint32LE(as.duration, VER(24));
+	s.syncAsSint32LE(as.numLoops, VER(24));
+}
+
+static void syncWithSerializer(Common::Serializer &s, Common::Rect &rect) {
+	s.syncAsSint16LE(rect.left);
+	s.syncAsSint16LE(rect.top);
+	s.syncAsSint16LE(rect.right);
+	s.syncAsSint16LE(rect.bottom);
+}
+
+template <typename T, size_t N, size_t M>
+static void sync2DArray(Common::Serializer &s, T (&array)[N][M], const size_t dim1, const size_t dim2, void (*serializer)(Common::Serializer &, T &), Common::Serializer::Version minVersion = 0, Common::Serializer::Version maxVersion = Common::Serializer::kLastVersion) {
+
+	if (s.getVersion() < minVersion || s.getVersion() > maxVersion) {
+		return;
+	}
 
+	assert(dim1 <= N);
+	assert(dim2 <= M);
+	for (size_t i = 0; i < dim1; ++i) {
+		for (size_t j = 0; j < dim2; ++j) {
+			serializer(s, array[i][j]);
+		}
+	}
+}
+
+void ScummEngine::saveLoadWithSerializer(Common::Serializer &s) {
 	int i;
 	int var120Backup;
 	int var98Backup;
 	uint8 md5Backup[16];
 
 	// MD5 Operations: Backup on load, compare, and reset.
-	if (s->isLoading())
+	if (s.isLoading())
 		memcpy(md5Backup, _gameMD5, 16);
 
 
 	//
 	// Save/load main state (many members of class ScummEngine get saved here)
 	//
-	s->saveLoadEntries(this, mainEntries);
+	s.syncBytes(_gameMD5, sizeof(_gameMD5), VER(39));
+	s.skip(2, VER(8), VER(50)); // _roomWidth
+	s.skip(2, VER(8), VER(50)); // _roomHeight
+	s.skip(4, VER(8), VER(50)); // _ENCD_offs
+	s.skip(4, VER(8), VER(50)); // _EXCD_offs
+	s.skip(4, VER(8), VER(50)); // _IM00_offs
+	s.skip(4, VER(8), VER(50)); // _CLUT_offs
+	s.skip(4, VER(8), VER(9)); // _EPAL_offs
+	s.skip(4, VER(8), VER(50)); // _PALS_offs
+	s.syncAsByte(_curPalIndex, VER(8));
+	s.syncAsByte(_currentRoom, VER(8));
+	s.syncAsByte(_roomResource, VER(8));
+	s.syncAsByte(_numObjectsInRoom, VER(8));
+	s.syncAsByte(_currentScript, VER(8));
+	s.skip(4 * _numLocalScripts, VER(8), VER(50)); // _localScriptOffsets
+
+	// vm.localvar grew from 25 to 40 script entries and then from
+	// 16 to 32 bit variables (but that wasn't reflect here)... and
+	// THEN from 16 to 25 variables.
+	sync2DArray(s, vm.localvar, 25, 17, Common::Serializer::Uint16LE, VER(8), VER(8));
+	sync2DArray(s, vm.localvar, 40, 17, Common::Serializer::Uint16LE, VER(9), VER(14));
+
+	// We used to save 25 * 40 = 1000 blocks; but actually, each 'row consisted of 26 entry,
+	// i. 26 * 40 = 1040. Thus the last 40 blocks of localvar where not saved at all. To be
+	// able to load this screwed format, we use a trick: We load 26 * 38 = 988 blocks.
+	// Then, we mark the followin 12 blocks (24 bytes) as obsolete.
+	sync2DArray(s, vm.localvar, 38, 26, Common::Serializer::Uint16LE, VER(15), VER(17));
+	s.skip(2 * 12, VER(15), VER(17));
+
+	// This was the first proper multi dimensional version of the localvars, with 32 bit values
+	sync2DArray(s, vm.localvar, 40, 26, Common::Serializer::Uint32LE, VER(18), VER(19));
+
+	// Then we doubled the script slots again, from 40 to 80
+	sync2DArray(s, vm.localvar, NUM_SCRIPT_SLOT, 26, Common::Serializer::Uint32LE, VER(20));
+
+	s.syncBytes(_resourceMapper, 128, VER(8));
+	s.syncBytes(_charsetColorMap, 16, VER(8));
+
+	// _charsetData grew from 10*16, to 15*16, to 23*16 bytes
+	for (int i = 0; i < 10; ++i) {
+		s.syncBytes(_charsetData[i], 16, VER(8));
+	}
+	for (int i = 10; i < 15; ++i) {
+		s.syncBytes(_charsetData[i], 16, VER(10));
+	}
+	for (int i = 15; i < 23; ++i) {
+		s.syncBytes(_charsetData[i], 16, VER(67));
+	}
+
+	s.skip(2, VER(8), VER(62)); // _curExecScript
+
+	s.syncAsSint16LE(camera._dest.x, VER(8));
+	s.syncAsSint16LE(camera._dest.y, VER(8));
+	s.syncAsSint16LE(camera._cur.x, VER(8));
+	s.syncAsSint16LE(camera._cur.y, VER(8));
+	s.syncAsSint16LE(camera._last.x, VER(8));
+	s.syncAsSint16LE(camera._last.y, VER(8));
+	s.syncAsSint16LE(camera._accel.x, VER(8));
+	s.syncAsSint16LE(camera._accel.y, VER(8));
+	s.syncAsSint16LE(_screenStartStrip, VER(8));
+	s.syncAsSint16LE(_screenEndStrip, VER(8));
+	s.syncAsByte(camera._mode, VER(8));
+	s.syncAsByte(camera._follows, VER(8));
+	s.syncAsSint16LE(camera._leftTrigger, VER(8));
+	s.syncAsSint16LE(camera._rightTrigger, VER(8));
+	s.syncAsUint16LE(camera._movingToActor, VER(8));
+
+	s.syncAsByte(_actorToPrintStrFor, VER(8));
+	s.syncAsByte(_charsetColor, VER(8));
+
+	// _charsetBufPos was changed from byte to int
+	s.syncAsByte(_charsetBufPos, VER(8), VER(9));
+	s.syncAsSint16LE(_charsetBufPos, VER(10));
+
+	s.syncAsByte(_haveMsg, VER(8));
+	s.syncAsByte(_haveActorSpeechMsg, VER(61));
+	s.syncAsByte(_useTalkAnims, VER(8));
+
+	s.syncAsSint16LE(_talkDelay, VER(8));
+	s.syncAsSint16LE(_defaultTalkDelay, VER(8));
+	s.skip(2, VER(8), VER(27)); // _numInMsgStack
+	s.syncAsByte(_sentenceNum, VER(8));
+
+	s.syncAsByte(vm.cutSceneStackPointer, VER(8));
+	s.syncArray(vm.cutScenePtr, 5, Common::Serializer::Uint32LE, VER(8));
+	s.syncBytes(vm.cutSceneScript, 5, VER(8));
+	s.syncArray(vm.cutSceneData, 5, Common::Serializer::Sint16LE, VER(8));
+	s.syncAsSint16LE(vm.cutSceneScriptIndex, VER(8));
+
+	s.syncAsByte(vm.numNestedScripts, VER(8));
+	s.syncAsByte(_userPut, VER(8));
+	s.syncAsUint16LE(_userState, VER(17));
+	s.syncAsByte(_cursor.state, VER(8));
+	s.skip(1, VER(8), VER(20)); // _gdi->_cursorActive
+	s.syncAsByte(_currentCursor, VER(8));
+	// TODO: This seems wrong, _grabbedCursor is >8192 bytes and sometimes holds
+	// 16-bit values
+	s.syncBytes(_grabbedCursor, 8192, VER(20));
+	s.syncAsSint16LE(_cursor.width, VER(20));
+	s.syncAsSint16LE(_cursor.height, VER(20));
+	s.syncAsSint16LE(_cursor.hotspotX, VER(20));
+	s.syncAsSint16LE(_cursor.hotspotY, VER(20));
+	s.syncAsByte(_cursor.animate, VER(20));
+	s.syncAsByte(_cursor.animateIndex, VER(20));
+	s.syncAsSint16LE(_mouse.x, VER(20));
+	s.syncAsSint16LE(_mouse.y, VER(20));
+
+	s.syncBytes(_colorUsedByCycle, 256, VER(60));
+	s.syncAsByte(_doEffect, VER(8));
+	s.syncAsByte(_switchRoomEffect, VER(8));
+	s.syncAsByte(_newEffect, VER(8));
+	s.syncAsByte(_switchRoomEffect2, VER(8));
+	s.syncAsByte(_bgNeedsRedraw, VER(8));
+
+	// The state of palManipulate is stored only since V10
+	s.syncAsByte(_palManipStart, VER(10));
+	s.syncAsByte(_palManipEnd, VER(10));
+	s.syncAsUint16LE(_palManipCounter, VER(10));
+
+	// gfxUsageBits grew from 200 to 410 entries. Then 3 * 410 entries:
+	s.syncArray(gfxUsageBits, 200, Common::Serializer::Uint32LE, VER(8), VER(9));
+	s.syncArray(gfxUsageBits, 410, Common::Serializer::Uint32LE, VER(10), VER(13));
+	s.syncArray(gfxUsageBits, 3 * 410, Common::Serializer::Uint32LE, VER(14));
+
+	s.skip(1, VER(8), VER(50)); // _gdi->_transparentColor
+	s.syncBytes(_currentPalette, 768, VER(8));
+	s.syncBytes(_darkenPalette, 768, VER(53));
+
+	// Sam & Max specific palette replaced by _shadowPalette now.
+	s.skip(256, VER(8), VER(33)); // _proc_special_palette
+
+	s.syncBytes(_charsetBuffer, 256, VER(8));
+
+	s.syncAsByte(_egoPositioned, VER(8));
+
+	// _gdi->_imgBufOffs grew from 4 to 5 entries. Then one day we realized
+	// that we don't have to store it since initBGBuffers() recomputes it.
+	s.skip(2 * 4, VER(8), VER(9)); // _gdi->_imgBufOffs
+	s.skip(2 * 5, VER(10), VER(26)); // _gdi->_imgBufOffs
+
+	// See _imgBufOffs: _numZBuffer is recomputed by initBGBuffers().
+	s.skip(1, VER(8), VER(26)); // _gdi->_numZBuffer
+
+	s.syncAsByte(_screenEffectFlag, VER(8));
+
+	s.skip(4, VER(8), VER(9)); // _randSeed1
+	s.skip(4, VER(8), VER(9)); // _randSeed2
+
+	// Converted _shakeEnabled to boolean and added a _shakeFrame field.
+	s.syncAsSint16LE(_shakeEnabled, VER(8), VER(9));
+	s.syncAsByte(_shakeEnabled, VER(10));
+	s.syncAsUint32LE(_shakeFrame, VER(10));
+
+	s.syncAsByte(_keepText, VER(8));
+
+	s.syncAsUint16LE(_screenB, VER(8));
+	s.syncAsUint16LE(_screenH, VER(8));
+
+	s.syncAsUint16LE(_NESCostumeSet, VER(47));
+
+	s.skip(2, VER(9), VER(9)); // _cd_track
+	s.skip(2, VER(9), VER(9)); // _cd_loops
+	s.skip(2, VER(9), VER(9)); // _cd_frame
+	s.skip(2, VER(9), VER(9)); // _cd_end
 
 	// MD5 Operations: Backup on load, compare, and reset.
-	if (s->isLoading()) {
+	if (s.isLoading()) {
 		char md5str1[32+1], md5str2[32+1];
 		for (i = 0; i < 16; i++) {
 			sprintf(md5str1 + i*2, "%02x", (int)_gameMD5[i]);
 			sprintf(md5str2 + i*2, "%02x", (int)md5Backup[i]);
 		}
 
-		debug(2, "Save version: %d", s->getVersion());
-		debug(2, "Saved game MD5: %s", (s->getVersion() >= 39) ? md5str1 : "unknown");
+		debug(2, "Save version: %d", s.getVersion());
+		debug(2, "Saved game MD5: %s", (s.getVersion() >= 39) ? md5str1 : "unknown");
 
 		if (memcmp(md5Backup, _gameMD5, 16) != 0) {
 			warning("Game was saved with different gamedata - you may encounter problems");
@@ -1134,22 +1140,22 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	// that have more than 30 actors (up to 94 are supported now, in theory).
 	// Since the format of the usage bits was changed by this, we have to
 	// convert them when loading an older savegame.
-	if (s->isLoading() && s->getVersion() < VER(14))
+	if (s.isLoading() && s.getVersion() < VER(14))
 		upgradeGfxUsageBits();
 
 	// When loading, reset the ShakePos. Fixes one part of bug #7141
-	if (s->isLoading() && s->getVersion() >= VER(10))
+	if (s.isLoading() && s.getVersion() >= VER(10))
 		_system->setShakePos(0);
 
 	// When loading, move the mouse to the saved mouse position.
-	if (s->isLoading() && s->getVersion() >= VER(20)) {
+	if (s.isLoading() && s.getVersion() >= VER(20)) {
 		updateCursor();
 		_system->warpMouse(_mouse.x, _mouse.y);
 	}
 
 	// Before V61, we re-used the _haveMsg flag to handle "alternative" speech
 	// sound files (see charset code 10).
-	if (s->isLoading() && s->getVersion() < VER(61)) {
+	if (s.isLoading() && s.getVersion() < VER(61)) {
 		if (_haveMsg == 0xFE) {
 			_haveActorSpeechMsg = false;
 			_haveMsg = 0xFF;
@@ -1174,14 +1180,11 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	// Save/load script data
 	//
-	if (s->getVersion() < VER(9))
-		s->saveLoadArrayOf(vm.slot, 25, sizeof(vm.slot[0]), scriptSlotEntries);
-	else if (s->getVersion() < VER(20))
-		s->saveLoadArrayOf(vm.slot, 40, sizeof(vm.slot[0]), scriptSlotEntries);
-	else
-		s->saveLoadArrayOf(vm.slot, NUM_SCRIPT_SLOT, sizeof(vm.slot[0]), scriptSlotEntries);
+	s.syncArray(vm.slot, 25, syncWithSerializer, VER(0), VER(8));
+	s.syncArray(vm.slot, 40, syncWithSerializer, VER(9), VER(19));
+	s.syncArray(vm.slot, NUM_SCRIPT_SLOT, syncWithSerializer, VER(20));
 
-	if (s->getVersion() < VER(46)) {
+	if (s.getVersion() < VER(46)) {
 		// When loading an old savegame, make sure that the 'cycle'
 		// field is set to something sensible, otherwise the scripts
 		// that were running probably won't be.
@@ -1195,13 +1198,13 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	// Save/load local objects
 	//
-	s->saveLoadArrayOf(_objs, _numLocalObjects, sizeof(_objs[0]), objectEntries);
-	if (s->isLoading()) {
-		if (s->getVersion() < VER(13)) {
+	s.syncArray(_objs, _numLocalObjects, syncWithSerializer);
+	if (s.isLoading()) {
+		if (s.getVersion() < VER(13)) {
 			// Since roughly v13 of the save games, the objs storage has changed a bit
 			for (i = _numObjectsInRoom; i < _numLocalObjects; i++)
 				_objs[i].obj_nr = 0;
-		} else if (_game.version == 0 && s->getVersion() < VER(91)) {
+		} else if (_game.version == 0 && s.getVersion() < VER(91)) {
 			for (i = 0; i < _numLocalObjects; i++) {
 				// Merge object id and type (previously stored in flags)
 				if (_objs[i].obj_nr != 0 && OBJECT_V0_TYPE(_objs[i].obj_nr) == 0 && _objs[i].flags != 0)
@@ -1215,13 +1218,12 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	// Save/load misc stuff
 	//
-	s->saveLoadArrayOf(_verbs, _numVerbs, sizeof(_verbs[0]), verbEntries);
-	s->saveLoadArrayOf(vm.nest, 16, sizeof(vm.nest[0]), nestedScriptEntries);
-	s->saveLoadArrayOf(_sentence, 6, sizeof(_sentence[0]), sentenceTabEntries);
-	s->saveLoadArrayOf(_string, 6, sizeof(_string[0]), stringTabEntries);
-	s->saveLoadArrayOf(_colorCycle, 16, sizeof(_colorCycle[0]), colorCycleEntries);
-	if (s->getVersion() >= VER(13))
-		s->saveLoadArrayOf(_scaleSlots, 20, sizeof(_scaleSlots[0]), scaleSlotsEntries);
+	s.syncArray(_verbs, _numVerbs, syncWithSerializer);
+	s.syncArray(vm.nest, 16, syncWithSerializer);
+	s.syncArray(_sentence, 6, syncWithSerializer);
+	s.syncArray(_string, 6, syncWithSerializer);
+	s.syncArray(_colorCycle, 16, syncWithSerializer);
+	s.syncArray(_scaleSlots, 20, syncWithSerializer, VER(13));
 
 
 	//
@@ -1229,30 +1231,31 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	ResType type;
 	ResId idx;
-	if (s->getVersion() >= VER(26)) {
+	if (s.getVersion() >= VER(26)) {
 		// New, more robust resource save/load system. This stores the type
 		// and index of each resource. Thus if we increase e.g. the maximum
 		// number of script resources, savegames won't break.
-		if (s->isSaving()) {
+		if (s.isSaving()) {
+			uint16 endMarker = 0xFFFF;
 			for (type = rtFirst; type <= rtLast; type = ResType(type + 1)) {
 				if (_res->_types[type]._mode != kStaticResTypeMode && type != rtTemp && type != rtBuffer) {
-					s->saveUint16(type);	// Save the res type...
+					s.syncAsUint16LE(type);	// Save the res type...
 					for (idx = 0; idx < _res->_types[type].size(); idx++) {
 						// Only save resources which actually exist...
 						if (_res->_types[type][idx]._address) {
-							s->saveUint16(idx);	// Save the index of the resource
+							s.syncAsUint16LE(idx);	// Save the index of the resource
 							saveResource(s, type, idx);
 						}
 					}
-					s->saveUint16(0xFFFF);	// End marker
+					s.syncAsUint16LE(endMarker);
 				}
 			}
-			s->saveUint16(0xFFFF);	// End marker
+			s.syncAsUint16LE(endMarker);
 		} else {
 			uint16 tmp;
-			while ((tmp = s->loadUint16()) != 0xFFFF) {
+			while (s.syncAsUint16LE(tmp), tmp != 0xFFFF) {
 				type = (ResType)tmp;
-				while ((idx = s->loadUint16()) != 0xFFFF) {
+				while (s.syncAsUint16LE(idx), idx != 0xFFFF) {
 					assert(idx < _res->_types[type].size());
 					loadResource(s, type, idx);
 				}
@@ -1278,17 +1281,17 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	// Save/load global object state
 	//
-	s->saveLoadArrayOf(_objectOwnerTable, _numGlobalObjects, sizeof(_objectOwnerTable[0]), sleByte);
-	s->saveLoadArrayOf(_objectStateTable, _numGlobalObjects, sizeof(_objectStateTable[0]), sleByte);
+	s.syncBytes(_objectOwnerTable, _numGlobalObjects);
+	s.syncBytes(_objectStateTable, _numGlobalObjects);
 	if (_objectRoomTable)
-		s->saveLoadArrayOf(_objectRoomTable, _numGlobalObjects, sizeof(_objectRoomTable[0]), sleByte);
+		s.syncBytes(_objectRoomTable, _numGlobalObjects);
 
 
 	//
 	// Save/load palette data
 	// Don't save 16 bit palette in FM-Towns and PCE games, since it gets regenerated afterwards anyway.
-	if (_16BitPalette && !(_game.platform == Common::kPlatformFMTowns && s->getVersion() < VER(82)) && !((_game.platform == Common::kPlatformFMTowns || _game.platform == Common::kPlatformPCEngine) && s->getVersion() > VER(87))) {
-		s->saveLoadArrayOf(_16BitPalette, 512, sizeof(_16BitPalette[0]), sleUint16);
+	if (_16BitPalette && !(_game.platform == Common::kPlatformFMTowns && s.getVersion() < VER(82)) && !((_game.platform == Common::kPlatformFMTowns || _game.platform == Common::kPlatformPCEngine) && s.getVersion() > VER(87))) {
+		s.syncArray(_16BitPalette, 512, Common::Serializer::Uint16LE);
 	}
 
 
@@ -1310,82 +1313,71 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	}
 
 #else
-	byte hasTownsData = ((_game.platform == Common::kPlatformFMTowns && s->getVersion() >= VER(87)) || (s->getVersion() >= VER(82) && s->getVersion() < VER(87))) ? 1 : 0;
-	if (_game.platform == Common::kPlatformFMTowns && s->getVersion() > VER(87))
-		s->saveLoadArrayOf(&hasTownsData, 1, sizeof(byte), sleByte);
+	byte hasTownsData = ((_game.platform == Common::kPlatformFMTowns && s.getVersion() >= VER(87)) || (s.getVersion() >= VER(82) && s.getVersion() < VER(87))) ? 1 : 0;
+	if (_game.platform == Common::kPlatformFMTowns && s.getVersion() > VER(87))
+		s.syncAsByte(hasTownsData);
 
 	if (hasTownsData) {
-		const SaveLoadEntry townsFields[] = {
-			MKLINE(Common::Rect, left, sleInt16, VER(82)),
-			MKLINE(Common::Rect, top, sleInt16, VER(82)),
-			MKLINE(Common::Rect, right, sleInt16, VER(82)),
-			MKLINE(Common::Rect, bottom, sleInt16, VER(82)),
-			MKEND()
-		};
-
-		const SaveLoadEntry townsExtraEntries[] = {
-			MKLINE(ScummEngine, _townsOverrideShadowColor, sleUint8, VER(82)),
-			MKLINE(ScummEngine, _numCyclRects, sleUint8, VER(82)),
-			MKLINE(ScummEngine, _townsPaletteFlags, sleUint8, VER(82)),
-			MKLINE(ScummEngine, _townsClearLayerFlag, sleUint8, VER(82)),
-			MKLINE(ScummEngine, _townsActiveLayerFlags, sleUint8, VER(82)),
-			MKEND()
-		};
-
-		s->saveLoadArrayOf(_textPalette, 48, sizeof(_textPalette[0]), sleUint8);
-		s->saveLoadArrayOf(_cyclRects, 10, sizeof(_cyclRects[0]), townsFields);
-		s->saveLoadArrayOf(&_curStringRect, 1, sizeof(_curStringRect), townsFields);
-		s->saveLoadArrayOf(_townsCharsetColorMap, 16, sizeof(_townsCharsetColorMap[0]), sleUint8);
-		s->saveLoadEntries(this, townsExtraEntries);
-	} else if (_game.platform == Common::kPlatformFMTowns && s->getVersion() >= VER(82)) {
+		s.syncBytes(_textPalette, 48);
+		// TODO: This seems wrong, there are 16 _cyclRects
+		s.syncArray(_cyclRects, 10, syncWithSerializer, VER(82));
+		if (s.getVersion() >= VER(82))
+			syncWithSerializer(s, _curStringRect);
+		s.syncBytes(_townsCharsetColorMap, 16);
+		s.syncAsByte(_townsOverrideShadowColor, VER(82));
+		s.syncAsByte(_numCyclRects, VER(82));
+		s.syncAsByte(_townsPaletteFlags, VER(82));
+		s.syncAsByte(_townsClearLayerFlag, VER(82));
+		s.syncAsByte(_townsActiveLayerFlags, VER(82));
+	} else if (_game.platform == Common::kPlatformFMTowns && s.getVersion() >= VER(82)) {
 		warning("Save file is missing FM-Towns specific graphic data (game was apparently saved on another platform)");
 	}
 #endif
 
 	if (_shadowPaletteSize) {
-		s->saveLoadArrayOf(_shadowPalette, _shadowPaletteSize, 1, sleByte);
+		s.syncBytes(_shadowPalette, _shadowPaletteSize);
 		// _roomPalette didn't show up until V21 save games
 		// Note that we also save the room palette for Indy4 Amiga, since it
 		// is used as palette map there too, but we do so slightly a bit
 		// further down to group it with the other special palettes needed.
-		if (s->getVersion() >= VER(21) && _game.version < 5)
-			s->saveLoadArrayOf(_roomPalette, sizeof(_roomPalette), 1, sleByte);
+		if (s.getVersion() >= VER(21) && _game.version < 5)
+			s.syncBytes(_roomPalette, sizeof(_roomPalette));
 	}
 
 	// PalManip data was not saved before V10 save games
-	if (s->getVersion() < VER(10))
+	if (s.getVersion() < VER(10))
 		_palManipCounter = 0;
 	if (_palManipCounter) {
 		if (!_palManipPalette)
 			_palManipPalette = (byte *)calloc(0x300, 1);
 		if (!_palManipIntermediatePal)
 			_palManipIntermediatePal = (byte *)calloc(0x600, 1);
-		s->saveLoadArrayOf(_palManipPalette, 0x300, 1, sleByte);
-		s->saveLoadArrayOf(_palManipIntermediatePal, 0x600, 1, sleByte);
+		s.syncBytes(_palManipPalette, 0x300);
+		s.syncBytes(_palManipIntermediatePal, 0x600);
 	}
 
 	// darkenPalette was not saved before V53
-	if (s->isLoading() && s->getVersion() < VER(53)) {
+	if (s.isLoading() && s.getVersion() < VER(53)) {
 		memcpy(_darkenPalette, _currentPalette, 768);
 	}
 
 	// _colorUsedByCycle was not saved before V60
-	if (s->isLoading() && s->getVersion() < VER(60)) {
+	if (s.isLoading() && s.getVersion() < VER(60)) {
 		memset(_colorUsedByCycle, 0, sizeof(_colorUsedByCycle));
 	}
 
 	// Indy4 Amiga specific palette tables were not saved before V85
 	if (_game.platform == Common::kPlatformAmiga && _game.id == GID_INDY4) {
-		if (s->getVersion() >= 85) {
-			s->saveLoadArrayOf(_roomPalette, 256, 1, sleByte);
-			s->saveLoadArrayOf(_verbPalette, 256, 1, sleByte);
-			s->saveLoadArrayOf(_amigaPalette, 3 * 64, 1, sleByte);
+		if (s.getVersion() >= 85) {
+			s.syncBytes(_roomPalette, 256);
+			s.syncBytes(_verbPalette, 256);
+			s.syncBytes(_amigaPalette, 3 * 64);
 
 			// Starting from version 86 we also save the first used color in
 			// the palette beyond the verb palette. For old versions we just
 			// look for it again, which hopefully won't cause any troubles.
-			if (s->getVersion() >= 86) {
-				s->saveLoadArrayOf(&_amigaFirstUsedColor, 1, 2, sleUint16);
+			if (s.getVersion() >= VER(86)) {
+				s.syncAsUint16LE(_amigaFirstUsedColor);
 			} else {
 				amigaPaletteFindFirstUsedColor();
 			}
@@ -1400,7 +1392,7 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	// Save/load more global object state
 	//
-	s->saveLoadArrayOf(_classData, _numGlobalObjects, sizeof(_classData[0]), sleUint32);
+	s.syncArray(_classData, _numGlobalObjects, Common::Serializer::Uint32LE);
 
 
 	//
@@ -1409,40 +1401,40 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	var120Backup = _scummVars[120];
 	var98Backup = _scummVars[98];
 
-	if (s->getVersion() > VER(37))
-		s->saveLoadArrayOf(_roomVars, _numRoomVariables, sizeof(_roomVars[0]), sleInt32);
+	s.syncArray(_roomVars, _numRoomVariables, Common::Serializer::Sint32LE, VER(38));
 
 	// The variables grew from 16 to 32 bit.
-	if (s->getVersion() < VER(15))
-		s->saveLoadArrayOf(_scummVars, _numVariables, sizeof(_scummVars[0]), sleInt16);
+	if (s.getVersion() < VER(15))
+		s.syncArray(_scummVars, _numVariables, Common::Serializer::Sint16LE);
 	else
-		s->saveLoadArrayOf(_scummVars, _numVariables, sizeof(_scummVars[0]), sleInt32);
+		s.syncArray(_scummVars, _numVariables, Common::Serializer::Sint32LE);
 
 	if (_game.id == GID_TENTACLE)	// Maybe misplaced, but that's the main idea
 		_scummVars[120] = var120Backup;
 	if (_game.id == GID_INDY4)
 		_scummVars[98] = var98Backup;
 
-	s->saveLoadArrayOf(_bitVars, _numBitVariables >> 3, 1, sleByte);
+	s.syncBytes(_bitVars, _numBitVariables / 8);
 
 
 	//
 	// Save/load a list of the locked objects
 	//
-	if (s->isSaving()) {
+	if (s.isSaving()) {
+		byte endMarker = 0xFF;
 		for (type = rtFirst; type <= rtLast; type = ResType(type + 1))
 			for (idx = 1; idx < _res->_types[type].size(); idx++) {
 				if (_res->isLocked(type, idx)) {
-					s->saveByte(type);
-					s->saveUint16(idx);
+					s.syncAsByte(type);
+					s.syncAsUint16LE(idx);
 				}
 			}
-		s->saveByte(0xFF);
+		s.syncAsByte(endMarker);
 	} else {
 		uint8 tmp;
-		while ((tmp = s->loadByte()) != 0xFF) {
+		while (s.syncAsByte(tmp), tmp != 0xFF) {
 			type = (ResType)tmp;
-			idx = s->loadUint16();
+			s.syncAsUint16LE(idx);
 			_res->lock(type, idx);
 		}
 	}
@@ -1451,15 +1443,15 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	// Save/load the Audio CD status
 	//
-	if (s->getVersion() >= VER(24)) {
+	if (s.getVersion() >= VER(24)) {
 		AudioCDManager::Status info;
-		if (s->isSaving())
+		if (s.isSaving())
 			info = _system->getAudioCDManager()->getStatus();
-		s->saveLoadArrayOf(&info, 1, sizeof(info), audioCDEntries);
+		syncWithSerializer(s, info);
 		// If we are loading, and the music being loaded was supposed to loop
 		// forever, then resume playing it. This helps a lot when the audio CD
 		// is used to provide ambient music (see bug #788195).
-		if (s->isLoading() && info.playing && info.numLoops < 0)
+		if (s.isLoading() && info.playing && info.numLoops < 0)
 			_sound->playCDTrackInternal(info.track, info.numLoops, info.start, info.duration);
 	}
 
@@ -1468,7 +1460,7 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	// Save/load the iMuse status
 	//
 	if (_imuse && (_saveSound || !_saveTemporaryState)) {
-		_imuse->save_or_load(s, this);
+		_imuse->saveLoadWithSerializer(s, this);
 	}
 
 
@@ -1483,11 +1475,13 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	//
 	// Save/load the charset renderer state
 	//
-	if (s->getVersion() >= VER(73)) {
+	if (s.getVersion() >= VER(73)) {
 		_charset->saveLoadWithSerializer(s);
-	} else if (s->isLoading()) {
-		if (s->getVersion() == VER(72)) {
-			_charset->setCurID(s->loadByte());
+	} else if (s.isLoading()) {
+		if (s.getVersion() == VER(72)) {
+			byte curId;
+			s.syncAsByte(curId);
+			_charset->setCurID(curId);
 		} else {
 			// Before V72, the charset id wasn't saved. This used to cause issues such
 			// as the one described in the bug report #1722153. For these savegames,
@@ -1497,57 +1491,45 @@ void ScummEngine::saveOrLoad(Serializer *s) {
 	}
 }
 
-void ScummEngine_v0::saveOrLoad(Serializer *s) {
-	ScummEngine_v2::saveOrLoad(s);
-
-	const SaveLoadEntry v0Entrys[] = {
-		MKLINE(ScummEngine_v0, _currentMode, sleByte, VER(78)),
-		MKLINE(ScummEngine_v0, _currentLights, sleByte, VER(78)),
-		MKLINE(ScummEngine_v0, _activeVerb, sleByte, VER(92)),
-		MKLINE(ScummEngine_v0, _activeObject, sleUint16, VER(92)),
-		MKLINE(ScummEngine_v0, _activeObject2, sleUint16, VER(92)),
-		MKLINE(ScummEngine_v0, _cmdVerb, sleByte, VER(92)),
-		MKLINE(ScummEngine_v0, _cmdObject, sleUint16, VER(92)),
-		MKLINE(ScummEngine_v0, _cmdObject2, sleUint16, VER(92)),
-		MKLINE(ScummEngine_v0, _walkToObject, sleUint16, VER(92)),
-		MKLINE(ScummEngine_v0, _walkToObjectState, sleByte, VER(92)),
-		MKEND()
-	};
- 	s->saveLoadEntries(this, v0Entrys);
+void ScummEngine_v0::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine_v2::saveLoadWithSerializer(s);
+
+	s.syncAsByte(_currentMode, VER(78));
+	s.syncAsByte(_currentLights, VER(78));
+	s.syncAsByte(_activeVerb, VER(92));
+	s.syncAsUint16LE(_activeObject, VER(92));
+	s.syncAsUint16LE(_activeObject2, VER(92));
+	s.syncAsByte(_cmdVerb, VER(92));
+	s.syncAsUint16LE(_cmdObject, VER(92));
+	s.syncAsUint16LE(_cmdObject2, VER(92));
+	s.syncAsUint16LE(_walkToObject, VER(92));
+	s.syncAsByte(_walkToObjectState, VER(92));
 }
 
 
-void ScummEngine_v2::saveOrLoad(Serializer *s) {
-	ScummEngine::saveOrLoad(s);
+void ScummEngine_v2::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine::saveLoadWithSerializer(s);
 
-	const SaveLoadEntry v2Entrys[] = {
-		MKLINE(ScummEngine_v2, _inventoryOffset, sleUint16, VER(79)),
-		MKEND()
-	};
-	s->saveLoadEntries(this, v2Entrys);
+	s.syncAsUint16LE(_inventoryOffset, VER(79));
 
 	// In old saves we didn't store _inventoryOffset -> reset it to
 	// a sane default when loading one of those.
-	if (s->getVersion() < 79 && s->isLoading()) {
+	if (s.getVersion() < VER(79) && s.isLoading()) {
 		_inventoryOffset = 0;
 	}
 }
 
-void ScummEngine_v5::saveOrLoad(Serializer *s) {
-	ScummEngine::saveOrLoad(s);
-
-	const SaveLoadEntry cursorEntries[] = {
-		MKARRAY2(ScummEngine_v5, _cursorImages[0][0], sleUint16, 16, 4, (byte *)_cursorImages[1] - (byte *)_cursorImages[0], VER(44)),
-		MKARRAY(ScummEngine_v5, _cursorHotspots[0], sleByte, 8, VER(44)),
-		MKEND()
-	};
+void ScummEngine_v5::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine::saveLoadWithSerializer(s);
 
 	// This is probably only needed for Loom.
-	s->saveLoadEntries(this, cursorEntries);
+	// TODO: This looks wrong, _cursorImages is [4][17]
+	sync2DArray(s, _cursorImages, 4, 16, Common::Serializer::Uint16LE, VER(44));
+	s.syncBytes(_cursorHotspots, 8, VER(44));
 
 	// Reset cursors for old FM-Towns savegames saved with 256 color setting.
 	// Otherwise the cursor will be messed up when displayed in the new hi color setting.
-	if (_game.platform == Common::kPlatformFMTowns && _outputPixelFormat.bytesPerPixel == 2 && s->isLoading() && s->getVersion() < VER(82)) {
+	if (_game.platform == Common::kPlatformFMTowns && _outputPixelFormat.bytesPerPixel == 2 && s.isLoading() && s.getVersion() < VER(82)) {
 		if (_game.id == GID_LOOM) {
 			redefineBuiltinCursorFromChar(1, 1);
 			redefineBuiltinCursorHotspot(1, 0, 0);
@@ -1560,7 +1542,7 @@ void ScummEngine_v5::saveOrLoad(Serializer *s) {
 	// This avoids color issues when loading savegames that have been saved with a different ScummVM port
 	// that uses a different 16bit color mode than the ScummVM port which is currently used.
 #ifdef USE_RGB_COLOR
-	if (_game.platform == Common::kPlatformPCEngine && s->isLoading()) {
+	if (_game.platform == Common::kPlatformPCEngine && s.isLoading()) {
 		for (int i = 0; i < 256; ++i)
 			_16BitPalette[i] = get16BitColor(_currentPalette[i * 3 + 0], _currentPalette[i * 3 + 1], _currentPalette[i * 3 + 2]);
 	}
@@ -1568,154 +1550,133 @@ void ScummEngine_v5::saveOrLoad(Serializer *s) {
 }
 
 #ifdef ENABLE_SCUMM_7_8
-void ScummEngine_v7::saveOrLoad(Serializer *s) {
-	ScummEngine::saveOrLoad(s);
-
-	const SaveLoadEntry subtitleQueueEntries[] = {
-		MKARRAY(SubtitleText, text[0], sleByte, 256, VER(61)),
-		MKLINE(SubtitleText, charset, sleByte, VER(61)),
-		MKLINE(SubtitleText, color, sleByte, VER(61)),
-		MKLINE(SubtitleText, xpos, sleInt16, VER(61)),
-		MKLINE(SubtitleText, ypos, sleInt16, VER(61)),
-		MKLINE(SubtitleText, actorSpeechMsg, sleByte, VER(61)),
-		MKEND()
-	};
-
-	const SaveLoadEntry V7Entries[] = {
-		MKLINE(ScummEngine_v7, _subtitleQueuePos, sleInt32, VER(61)),
-		MK_OBSOLETE(ScummEngine_v7, _verbCharset, sleInt32, VER(68), VER(68)),
-		MKLINE(ScummEngine_v7, _verbLineSpacing, sleInt32, VER(68)),
-		MKEND()
-	};
-
-	_imuseDigital->saveOrLoad(s);
-
-	s->saveLoadArrayOf(_subtitleQueue, ARRAYSIZE(_subtitleQueue), sizeof(_subtitleQueue[0]), subtitleQueueEntries);
-	s->saveLoadEntries(this, V7Entries);
-
-	if (s->getVersion() <= VER(68) && s->isLoading()) {
+void syncWithSerializer(Common::Serializer &s, ScummEngine_v7::SubtitleText &st) {
+	s.syncBytes(st.text, 256, VER(61));
+	s.syncAsByte(st.charset, VER(61));
+	s.syncAsByte(st.color, VER(61));
+	s.syncAsSint16LE(st.xpos, VER(61));
+	s.syncAsSint16LE(st.ypos, VER(61));
+	s.syncAsByte(st.actorSpeechMsg, VER(61));
+}
+
+void ScummEngine_v7::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine::saveLoadWithSerializer(s);
+
+	_imuseDigital->saveLoadEarly(s);
+
+	s.syncArray(_subtitleQueue, ARRAYSIZE(_subtitleQueue), syncWithSerializer);
+	s.syncAsSint32LE(_subtitleQueuePos, VER(61));
+	s.skip(4, VER(68), VER(68)); // _verbCharset
+	s.syncAsSint32LE(_verbLineSpacing, VER(68));
+
+	if (s.getVersion() <= VER(68) && s.isLoading()) {
 		// WORKAROUND bug #1846049: Reset the default charset color to a sane value.
 		_string[0]._default.charset = 1;
 	}
 }
 #endif
 
-void ScummEngine_v60he::saveOrLoad(Serializer *s) {
-	ScummEngine::saveOrLoad(s);
+void ScummEngine_v60he::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine::saveLoadWithSerializer(s);
 
-	s->saveLoadArrayOf(_arraySlot, _numArray, sizeof(_arraySlot[0]), sleByte);
+	s.syncBytes(_arraySlot, _numArray);
 }
 
-void ScummEngine_v70he::saveOrLoad(Serializer *s) {
-	ScummEngine_v60he::saveOrLoad(s);
-
-	const SaveLoadEntry HE70Entries[] = {
-		MKLINE(ScummEngine_v70he, _heSndSoundId, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v70he, _heSndOffset, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v70he, _heSndChannel, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v70he, _heSndFlags, sleInt32, VER(51)),
-		MKEND()
-	};
+void ScummEngine_v70he::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine_v60he::saveLoadWithSerializer(s);
 
-	s->saveLoadEntries(this, HE70Entries);
+	s.syncAsSint32LE(_heSndSoundId, VER(51));
+	s.syncAsSint32LE(_heSndOffset, VER(51));
+	s.syncAsSint32LE(_heSndChannel, VER(51));
+	s.syncAsSint32LE(_heSndFlags, VER(51));
 }
 
 #ifdef ENABLE_HE
-void ScummEngine_v71he::saveOrLoad(Serializer *s) {
-	ScummEngine_v70he::saveOrLoad(s);
-
-	const SaveLoadEntry polygonEntries[] = {
-		MKLINE(WizPolygon, vert[0].x, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[0].y, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[1].x, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[1].y, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[2].x, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[2].y, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[3].x, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[3].y, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[4].x, sleInt16, VER(40)),
-		MKLINE(WizPolygon, vert[4].y, sleInt16, VER(40)),
-		MKLINE(WizPolygon, bound.left, sleInt16, VER(40)),
-		MKLINE(WizPolygon, bound.top, sleInt16, VER(40)),
-		MKLINE(WizPolygon, bound.right, sleInt16, VER(40)),
-		MKLINE(WizPolygon, bound.bottom, sleInt16, VER(40)),
-		MKLINE(WizPolygon, id, sleInt16, VER(40)),
-		MKLINE(WizPolygon, numVerts, sleInt16, VER(40)),
-		MKLINE(WizPolygon, flag, sleByte, VER(40)),
-		MKEND()
-	};
-
-	s->saveLoadArrayOf(_wiz->_polygons, ARRAYSIZE(_wiz->_polygons), sizeof(_wiz->_polygons[0]), polygonEntries);
+static void syncWithSerializer(Common::Serializer &s, WizPolygon &wp) {
+	s.syncAsSint16LE(wp.vert[0].x, VER(40));
+	s.syncAsSint16LE(wp.vert[0].y, VER(40));
+	s.syncAsSint16LE(wp.vert[1].x, VER(40));
+	s.syncAsSint16LE(wp.vert[1].y, VER(40));
+	s.syncAsSint16LE(wp.vert[2].x, VER(40));
+	s.syncAsSint16LE(wp.vert[2].y, VER(40));
+	s.syncAsSint16LE(wp.vert[3].x, VER(40));
+	s.syncAsSint16LE(wp.vert[3].y, VER(40));
+	s.syncAsSint16LE(wp.vert[4].x, VER(40));
+	s.syncAsSint16LE(wp.vert[4].y, VER(40));
+	s.syncAsSint16LE(wp.bound.left, VER(40));
+	s.syncAsSint16LE(wp.bound.top, VER(40));
+	s.syncAsSint16LE(wp.bound.right, VER(40));
+	s.syncAsSint16LE(wp.bound.bottom, VER(40));
+	s.syncAsSint16LE(wp.id, VER(40));
+	s.syncAsSint16LE(wp.numVerts, VER(40));
+	s.syncAsByte(wp.flag, VER(40));
 }
 
-void ScummEngine_v90he::saveOrLoad(Serializer *s) {
-	ScummEngine_v71he::saveOrLoad(s);
-
-	const SaveLoadEntry floodFillEntries[] = {
-		MKLINE(FloodFillParameters, box.left, sleInt32, VER(51)),
-		MKLINE(FloodFillParameters, box.top, sleInt32, VER(51)),
-		MKLINE(FloodFillParameters, box.right, sleInt32, VER(51)),
-		MKLINE(FloodFillParameters, box.bottom, sleInt32, VER(51)),
-		MKLINE(FloodFillParameters, x, sleInt32, VER(51)),
-		MKLINE(FloodFillParameters, y, sleInt32, VER(51)),
-		MKLINE(FloodFillParameters, flags, sleInt32, VER(51)),
-		MK_OBSOLETE(FloodFillParameters, unk1C, sleInt32, VER(51), VER(62)),
-		MKEND()
-	};
-
-	const SaveLoadEntry HE90Entries[] = {
-		MKLINE(ScummEngine_v90he, _curMaxSpriteId, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v90he, _curSpriteId, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v90he, _curSpriteGroupId, sleInt32, VER(51)),
-		MK_OBSOLETE(ScummEngine_v90he, _numSpritesToProcess, sleInt32, VER(51), VER(63)),
-		MKLINE(ScummEngine_v90he, _heObject, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v90he, _heObjectNum, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v90he, _hePaletteNum, sleInt32, VER(51)),
-		MKEND()
-	};
-
-	_sprite->saveOrLoadSpriteData(s);
-
-	s->saveLoadArrayOf(&_floodFillParams, 1, sizeof(_floodFillParams), floodFillEntries);
-
-	s->saveLoadEntries(this, HE90Entries);
+void ScummEngine_v71he::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine_v70he::saveLoadWithSerializer(s);
+
+	s.syncArray(_wiz->_polygons, ARRAYSIZE(_wiz->_polygons), syncWithSerializer);
 }
 
-void ScummEngine_v99he::saveOrLoad(Serializer *s) {
-	ScummEngine_v90he::saveOrLoad(s);
+void syncWithSerializer(Common::Serializer &s, FloodFillParameters &ffp) {
+	s.syncAsSint32LE(ffp.box.left, VER(51));
+	s.syncAsSint32LE(ffp.box.top, VER(51));
+	s.syncAsSint32LE(ffp.box.right, VER(51));
+	s.syncAsSint32LE(ffp.box.bottom, VER(51));
+	s.syncAsSint32LE(ffp.x, VER(51));
+	s.syncAsSint32LE(ffp.y, VER(51));
+	s.syncAsSint32LE(ffp.flags, VER(51));
+	s.skip(4, VER(51), VER(62)); // unk1C
+}
+
+void ScummEngine_v90he::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine_v71he::saveLoadWithSerializer(s);
+
+	_sprite->saveLoadWithSerializer(s);
+
+	syncWithSerializer(s, _floodFillParams);
 
-	s->saveLoadArrayOf(_hePalettes, (_numPalettes + 1) * _hePaletteSlot, sizeof(_hePalettes[0]), sleUint8);
+	s.syncAsSint32LE(_curMaxSpriteId, VER(51));
+	s.syncAsSint32LE(_curSpriteId, VER(51));
+	s.syncAsSint32LE(_curSpriteGroupId, VER(51));
+	s.skip(4, VER(51), VER(63)); // _numSpritesToProcess
+	s.syncAsSint32LE(_heObject, VER(51));
+	s.syncAsSint32LE(_heObjectNum, VER(51));
+	s.syncAsSint32LE(_hePaletteNum, VER(51));
 }
 
-void ScummEngine_v100he::saveOrLoad(Serializer *s) {
-	ScummEngine_v99he::saveOrLoad(s);
+void ScummEngine_v99he::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine_v90he::saveLoadWithSerializer(s);
 
-	const SaveLoadEntry HE100Entries[] = {
-		MKLINE(ScummEngine_v100he, _heResId, sleInt32, VER(51)),
-		MKLINE(ScummEngine_v100he, _heResType, sleInt32, VER(51)),
-		MKEND()
-	};
+	s.syncBytes(_hePalettes, (_numPalettes + 1) * _hePaletteSlot);
+}
+
+void ScummEngine_v100he::saveLoadWithSerializer(Common::Serializer &s) {
+	ScummEngine_v99he::saveLoadWithSerializer(s);
 
-	s->saveLoadEntries(this, HE100Entries);
+	s.syncAsSint32LE(_heResId, VER(51));
+	s.syncAsSint32LE(_heResType, VER(51));
 }
 #endif
 
-void ScummEngine::loadResourceOLD(Serializer *ser, ResType type, ResId idx) {
+void ScummEngine::loadResourceOLD(Common::Serializer &ser, ResType type, ResId idx) {
 	uint32 size;
 
-	if (type == rtSound && ser->getVersion() >= VER(23)) {
+	if (type == rtSound && ser.getVersion() >= VER(23)) {
 		// Save/load only a list of resource numbers that need to be reloaded.
-		if (ser->loadUint16())
+		uint16 tmp;
+		ser.syncAsUint16LE(tmp);
+		if (tmp)
 			ensureResourceLoaded(rtSound, idx);
 	} else if (_res->_types[type]._mode == kDynamicResTypeMode) {
-		size = ser->loadUint32();
+		ser.syncAsUint32LE(size);
 		if (size) {
 			_res->createResource(type, idx, size);
-			ser->loadBytes(getResourceAddress(type, idx), size);
+			ser.syncBytes(getResourceAddress(type, idx), size);
 			if (type == rtInventory) {
-				_inventory[idx] = ser->loadUint16();
+				ser.syncAsUint16LE(_inventory[idx]);
 			}
-			if (type == rtObjectName && ser->getVersion() >= VER(25)) {
+			if (type == rtObjectName && ser.getVersion() >= VER(25)) {
 				// Paranoia: We increased the possible number of new names
 				// to fix bugs #933610 and #936323. The savegame format
 				// didn't change, but at least during the transition
@@ -1723,38 +1684,39 @@ void ScummEngine::loadResourceOLD(Serializer *ser, ResType type, ResId idx) {
 				// more names than we have allocated space for. If so,
 				// discard them.
 				if (idx < _numNewNames)
-					_newNames[idx] = ser->loadUint16();
+					ser.syncAsUint16LE(_newNames[idx]);
 			}
 		}
 	}
 }
 
-void ScummEngine::saveResource(Serializer *ser, ResType type, ResId idx) {
+void ScummEngine::saveResource(Common::Serializer &ser, ResType type, ResId idx) {
 	assert(_res->_types[type][idx]._address);
 
 	if (_res->_types[type]._mode == kDynamicResTypeMode) {
 		byte *ptr = _res->_types[type][idx]._address;
 		uint32 size = _res->_types[type][idx]._size;
 
-		ser->saveUint32(size);
-		ser->saveBytes(ptr, size);
+		ser.syncAsUint32LE(size);
+		ser.syncBytes(ptr, size);
 
 		if (type == rtInventory) {
-			ser->saveUint16(_inventory[idx]);
+			ser.syncAsUint16LE(_inventory[idx]);
 		}
 		if (type == rtObjectName) {
-			ser->saveUint16(_newNames[idx]);
+			ser.syncAsUint16LE(_newNames[idx]);
 		}
 	}
 }
 
-void ScummEngine::loadResource(Serializer *ser, ResType type, ResId idx) {
-	if (_game.heversion >= 60 && ser->getVersion() <= VER(65) &&
+void ScummEngine::loadResource(Common::Serializer &ser, ResType type, ResId idx) {
+	if (_game.heversion >= 60 && ser.getVersion() <= VER(65) &&
 		((type == rtSound && idx == 1) || (type == rtSpoolBuffer))) {
-		uint32 size = ser->loadUint32();
+		uint32 size;
+		ser.syncAsUint32LE(size);
 		assert(size);
 		_res->createResource(type, idx, size);
-		ser->loadBytes(getResourceAddress(type, idx), size);
+		ser.syncBytes(getResourceAddress(type, idx), size);
 	} else if (type == rtSound) {
 		// HE Games use sound resource 1 for speech
 		if (_game.heversion >= 60 && idx == 1)
@@ -1762,243 +1724,18 @@ void ScummEngine::loadResource(Serializer *ser, ResType type, ResId idx) {
 
 		ensureResourceLoaded(rtSound, idx);
 	} else if (_res->_types[type]._mode == kDynamicResTypeMode) {
-		uint32 size = ser->loadUint32();
+		uint32 size;
+		ser.syncAsUint32LE(size);
 		assert(size);
 		byte *ptr = _res->createResource(type, idx, size);
-		ser->loadBytes(ptr, size);
+		ser.syncBytes(ptr, size);
 
 		if (type == rtInventory) {
-			_inventory[idx] = ser->loadUint16();
+			ser.syncAsUint16LE(_inventory[idx]);
 		}
 		if (type == rtObjectName) {
-			_newNames[idx] = ser->loadUint16();
-		}
-	}
-}
-
-void Serializer::saveBytes(void *b, int len) {
-	_saveStream->write(b, len);
-}
-
-void Serializer::loadBytes(void *b, int len) {
-	_loadStream->read(b, len);
-}
-
-void Serializer::saveUint32(uint32 d) {
-	_saveStream->writeUint32LE(d);
-}
-
-void Serializer::saveUint16(uint16 d) {
-	_saveStream->writeUint16LE(d);
-}
-
-void Serializer::saveByte(byte b) {
-	_saveStream->writeByte(b);
-}
-
-uint32 Serializer::loadUint32() {
-	return _loadStream->readUint32LE();
-}
-
-uint16 Serializer::loadUint16() {
-	return _loadStream->readUint16LE();
-}
-
-byte Serializer::loadByte() {
-	return _loadStream->readByte();
-}
-
-void Serializer::saveArrayOf(void *b, int len, int datasize, byte filetype) {
-	byte *at = (byte *)b;
-	uint32 data;
-
-	// speed up byte arrays
-	if (datasize == 1 && filetype == sleByte) {
-		if (len > 0) {
-			saveBytes(b, len);
-		}
-		return;
-	}
-
-	while (--len >= 0) {
-		if (datasize == 0) {
-			// Do nothing for obsolete data
-			data = 0;
-		} else if (datasize == 1) {
-			data = *(byte *)at;
-			at += 1;
-		} else if (datasize == 2) {
-			data = *(uint16 *)at;
-			at += 2;
-		} else if (datasize == 4) {
-			data = *(uint32 *)at;
-			at += 4;
-		} else {
-			error("saveArrayOf: invalid size %d", datasize);
-		}
-		switch (filetype) {
-		case sleByte:
-			saveByte((byte)data);
-			break;
-		case sleUint16:
-		case sleInt16:
-			saveUint16((int16)data);
-			break;
-		case sleInt32:
-		case sleUint32:
-			saveUint32(data);
-			break;
-		default:
-			error("saveArrayOf: invalid filetype %d", filetype);
-		}
-	}
-}
-
-void Serializer::loadArrayOf(void *b, int len, int datasize, byte filetype) {
-	byte *at = (byte *)b;
-	uint32 data;
-
-	// speed up byte arrays
-	if (datasize == 1 && filetype == sleByte) {
-		loadBytes(b, len);
-		return;
-	}
-
-	while (--len >= 0) {
-		switch (filetype) {
-		case sleByte:
-			data = loadByte();
-			break;
-		case sleUint16:
-			data = loadUint16();
-			break;
-		case sleInt16:
-			data = (int16)loadUint16();
-			break;
-		case sleUint32:
-			data = loadUint32();
-			break;
-		case sleInt32:
-			data = (int32)loadUint32();
-			break;
-		default:
-			error("loadArrayOf: invalid filetype %d", filetype);
-		}
-		if (datasize == 0) {
-			// Do nothing for obsolete data
-		} else if (datasize == 1) {
-			*(byte *)at = (byte)data;
-			at += 1;
-		} else if (datasize == 2) {
-			*(uint16 *)at = (uint16)data;
-			at += 2;
-		} else if (datasize == 4) {
-			*(uint32 *)at = data;
-			at += 4;
-		} else {
-			error("loadArrayOf: invalid size %d", datasize);
-		}
-	}
-}
-
-void Serializer::saveLoadArrayOf(void *b, int num, int datasize, const SaveLoadEntry *sle) {
-	byte *data = (byte *)b;
-
-	if (isSaving()) {
-		while (--num >= 0) {
-			saveEntries(data, sle);
-			data += datasize;
-		}
-	} else {
-		while (--num >= 0) {
-			loadEntries(data, sle);
-			data += datasize;
-		}
-	}
-}
-
-void Serializer::saveLoadArrayOf(void *b, int len, int datasize, byte filetype) {
-	if (isSaving())
-		saveArrayOf(b, len, datasize, filetype);
-	else
-		loadArrayOf(b, len, datasize, filetype);
-}
-
-void Serializer::saveLoadEntries(void *d, const SaveLoadEntry *sle) {
-	if (isSaving())
-		saveEntries(d, sle);
-	else
-		loadEntries(d, sle);
-}
-
-void Serializer::saveEntries(void *d, const SaveLoadEntry *sle) {
-	byte type;
-	byte *at;
-	int size;
-
-	while (sle->offs != 0xFFFF) {
-		at = (byte *)d + sle->offs;
-		size = sle->size;
-		type = (byte) sle->type;
-
-		if (sle->maxVersion != CURRENT_VER) {
-			// Skip obsolete entries
-			if (type & 128)
-				sle++;
-		} else {
-			// save entry
-			int columns = 1;
-			int rows = 1;
-			int rowlen = 0;
-			if (type & 128) {
-				sle++;
-				columns = sle->offs;
-				rows = sle->type;
-				rowlen = sle->size;
-				type &= ~128;
-			}
-			while (rows--) {
-				saveArrayOf(at, columns, size, type);
-				at += rowlen;
-			}
-		}
-		sle++;
-	}
-}
-
-void Serializer::loadEntries(void *d, const SaveLoadEntry *sle) {
-	byte type;
-	byte *at;
-	int size;
-
-	while (sle->offs != 0xFFFF) {
-		at = (byte *)d + sle->offs;
-		size = sle->size;
-		type = (byte) sle->type;
-
-		if (_savegameVersion < sle->minVersion || _savegameVersion > sle->maxVersion) {
-			// Skip entries which are not present in this save game version
-			if (type & 128)
-				sle++;
-		} else {
-			// load entry
-			int columns = 1;
-			int rows = 1;
-			int rowlen = 0;
-
-			if (type & 128) {
-				sle++;
-				columns = sle->offs;
-				rows = sle->type;
-				rowlen = sle->size;
-				type &= ~128;
-			}
-			while (rows--) {
-				loadArrayOf(at, columns, size, type);
-				at += rowlen;
-			}
+			ser.syncAsUint16LE(_newNames[idx]);
 		}
-		sle++;
 	}
 }
 
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
index fb2d45d..a0f45a3 100644
--- a/engines/scumm/saveload.h
+++ b/engines/scumm/saveload.h
@@ -24,16 +24,10 @@
 #define SCUMM_SAVELOAD_H
 
 #include "common/scummsys.h"
-#include <stddef.h>	// for ptrdiff_t
-
-namespace Common {
-class SeekableReadStream;
-class WriteStream;
-}
+#include "common/serializer.h"
 
 namespace Scumm {
 
-
 /**
  * The current savegame format version.
  * Our save/load system uses an elaborate scheme to allow us to modify the
@@ -54,117 +48,7 @@ namespace Scumm {
  * of just writing the raw version, because this way they stand out more to
  * the reading eye, making it a bit easier to navigate through the code.
  */
-#define VER(x) x
-
-
-/**
- * The OFFS macro essentially provides the functionality of offsetof(), that
- * is, it determines the offset of a struct/class member within instances of
- * that class.
- *
- * This is a place where we cheat a bit and sacrifice some potential portability
- * (although so far we haven't encountered any platform where this matters).
- *
- * To work around a warning in GCC 3.2 (and 3.1 ?) regarding non-POD types,
- * we use a small trick: instead of 0 we use 42. Why? Well, it seems newer GCC
- * versions have a heuristic built in to detect "offset-of" patterns - which is exactly
- * what our OFFS macro does. Now, for non-POD types this is not really legal, because
- * member need not be at a fixed offset relative to the variable, even if they are in
- * current reality (many of our complex structs are non-POD; for an explanation of
- * what POD means refer to <http://en.wikipedia.org/wiki/Plain_Old_Data_Structures> or
- * to <http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=32&rl=1>)
- */
-#define OFFS(type,item) ((uint32)(((ptrdiff_t)(&((type *)42)->type::item))-42))
-
-/**
- * Similar to the OFFS macro, this macro computes the size (in bytes) of a
- * member of a given struct/class type.
- */
-#define SIZE(type,item) sizeof(((type *)42)->type::item)
-
-// Any item that is still in use automatically gets a maxVersion equal to CURRENT_VER
-#define MKLINE(type,item,saveas,minVer) {OFFS(type,item),saveas,SIZE(type,item),minVer,CURRENT_VER}
-#define MKARRAY(type,item,saveas,dim,minVer) {OFFS(type,item),128|saveas,SIZE(type,item),minVer,CURRENT_VER}, {(uint32)(dim),1,0,0,0}
-#define MKARRAY2(type,item,saveas,dim,dim2,rowlen,minVer) {OFFS(type,item),128|saveas,SIZE(type,item),minVer,CURRENT_VER}, {(uint32)(dim),(uint32)(dim2),(uint16)(rowlen),0,0}
-
-// Use this if you have an entry that used to be smaller:
-#define MKLINE_OLD(type,item,saveas,minVer,maxVer) {OFFS(type,item),saveas,SIZE(type,item),minVer,maxVer}
-#define MKARRAY_OLD(type,item,saveas,dim,minVer,maxVer) {OFFS(type,item),128|saveas,SIZE(type,item),minVer,maxVer}, {(uint32)(dim),1,0,0,0}
-#define MKARRAY2_OLD(type,item,saveas,dim,dim2,rowlen,minVer,maxVer) {OFFS(type,item),128|saveas,SIZE(type,item),minVer,maxVer}, {(uint32)(dim),(uint32)(dim2),(uint16)(rowlen),0,0}
-
-// An obsolete item/array, to be ignored upon load. We retain the type/item params to make it easier to debug.
-// Obsolete items have size == 0.
-#define MK_OBSOLETE(type,item,saveas,minVer,maxVer) {0,saveas,0,minVer,maxVer}
-#define MK_OBSOLETE_ARRAY(type,item,saveas,dim,minVer,maxVer) {0,128|saveas,0,minVer,maxVer}, {(uint32)(dim),1,0,0,0}
-#define MK_OBSOLETE_ARRAY2(type,item,saveas,dim,dim2,rowlen,minVer,maxVer) {0,128|saveas,0,minVer,maxVer}, {(uint32)(dim),(uint32)(dim2),(uint16)(rowlen),0,0}
-
-// End marker
-#define MKEND() {0xFFFF,0xFF,0xFF,0,0}
-
-
-enum {
-	sleByte = 1,
-	sleUint8 = 1,
-	sleInt8 = 1,
-	sleInt16 = 2,
-	sleUint16 = 3,
-	sleInt32 = 4,
-	sleUint32 = 5
-};
-
-struct SaveLoadEntry {
-	uint32 offs;	// or: array dimension
-	uint16 type;	// or: array dimension 2
-	uint16 size;	// or: array row length
-	uint8 minVersion;
-	uint8 maxVersion;
-};
-
-class Serializer {
-public:
-	Serializer(Common::SeekableReadStream *in, Common::WriteStream *out, uint32 savegameVersion)
-		: _loadStream(in), _saveStream(out),
-		  _savegameVersion(savegameVersion)
-	{ }
-
-	void saveLoadArrayOf(void *b, int len, int datasize, byte filetype);
-	void saveLoadArrayOf(void *b, int num, int datasize, const SaveLoadEntry *sle);
-	void saveLoadEntries(void *d, const SaveLoadEntry *sle);
-
-	bool isSaving() { return (_saveStream != 0); }
-	bool isLoading() { return (_loadStream != 0); }
-	uint32 getVersion() { return _savegameVersion; }
-
-	void saveUint32(uint32 d);
-	void saveUint16(uint16 d);
-	void saveByte(byte b);
-
-	byte loadByte();
-	uint16 loadUint16();
-	uint32 loadUint32();
-
-	void saveBytes(void *b, int len);
-	void loadBytes(void *b, int len);
-
-protected:
-	Common::SeekableReadStream *_loadStream;
-	Common::WriteStream *_saveStream;
-	uint32 _savegameVersion;
-
-	void saveArrayOf(void *b, int len, int datasize, byte filetype);
-	void loadArrayOf(void *b, int len, int datasize, byte filetype);
-
-	void saveEntries(void *d, const SaveLoadEntry *sle);
-	void loadEntries(void *d, const SaveLoadEntry *sle);
-};
-
-
-// Mixin class / interface. Maybe call it ISerializable or SerializableMixin ?
-class Serializable {
-public:
-	virtual ~Serializable() {}
-	virtual void saveLoadWithSerializer(Serializer *ser) = 0;
-};
+#define VER(x) Common::Serializer::Version(x)
 
 } // End of namespace Scumm
 
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index caa1f84..ad3a3c1 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -33,6 +33,7 @@
 #include "common/random.h"
 #include "common/rect.h"
 #include "common/rendermode.h"
+#include "common/serializer.h"
 #include "common/str.h"
 #include "common/textconsole.h"
 #include "graphics/surface.h"
@@ -88,7 +89,6 @@ class MusicEngine;
 class Player_Towns;
 class ScummEngine;
 class ScummDebugger;
-class Serializer;
 class Sound;
 
 struct Box;
@@ -375,7 +375,7 @@ class ResourceManager;
 /**
  * Base class for all SCUMM engines.
  */
-class ScummEngine : public Engine {
+class ScummEngine : public Engine, public Common::Serializable {
 	friend class ScummDebugger;
 	friend class CharsetRenderer;
 	friend class CharsetRendererTownsClassic;
@@ -608,10 +608,10 @@ protected:
 	bool saveState(int slot, bool compat, Common::String &fileName);
 	bool loadState(int slot, bool compat);
 	bool loadState(int slot, bool compat, Common::String &fileName);
-	virtual void saveOrLoad(Serializer *s);
-	void saveResource(Serializer *ser, ResType type, ResId idx);
-	void loadResource(Serializer *ser, ResType type, ResId idx);
-	void loadResourceOLD(Serializer *ser, ResType type, ResId idx);	// "Obsolete"
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
+	void saveResource(Common::Serializer &ser, ResType type, ResId idx);
+	void loadResource(Common::Serializer &ser, ResType type, ResId idx);
+	void loadResourceOLD(Common::Serializer &ser, ResType type, ResId idx);	// "Obsolete"
 
 	virtual Common::SeekableReadStream *openSaveFileForReading(int slot, bool compat, Common::String &fileName);
 	virtual Common::WriteStream *openSaveFileForWriting(int slot, bool compat, Common::String &fileName);
@@ -1166,6 +1166,7 @@ protected:
 		int x1, y1, scale1;
 		int x2, y2, scale2;
 	};
+	friend void syncWithSerializer(Common::Serializer &, ScaleSlot &);
 	ScaleSlot _scaleSlots[20];
 	void setScaleSlot(int slot, int x1, int y1, int scale1, int x2, int y2, int scale2);
 	void setBoxScaleSlot(int box, int slot);
diff --git a/engines/scumm/scumm_v0.h b/engines/scumm/scumm_v0.h
index 5f40940..dd2142d 100644
--- a/engines/scumm/scumm_v0.h
+++ b/engines/scumm/scumm_v0.h
@@ -86,7 +86,7 @@ protected:
 
 	virtual void processInput();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual bool objIsActor(int obj);
 	virtual int objToActor(int obj);
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index 2a9e7a9..43226b8 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -60,7 +60,7 @@ protected:
 	virtual void resetScummVars();
 	virtual void decodeParseString();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void processKeyboard(Common::KeyState lastKeyHit);
 
diff --git a/engines/scumm/scumm_v5.h b/engines/scumm/scumm_v5.h
index 1bd38d6..76b6c12 100644
--- a/engines/scumm/scumm_v5.h
+++ b/engines/scumm/scumm_v5.h
@@ -66,7 +66,7 @@ protected:
 	virtual void resetScummVars();
 	virtual void decodeParseString();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void readMAXS(int blockSize);
 
diff --git a/engines/scumm/scumm_v7.h b/engines/scumm/scumm_v7.h
index b8830be..822ef7c 100644
--- a/engines/scumm/scumm_v7.h
+++ b/engines/scumm/scumm_v7.h
@@ -84,6 +84,7 @@ protected:
 	struct SubtitleText : TextObject {
 		bool actorSpeechMsg;
 	};
+	friend void syncWithSerializer(Common::Serializer &, SubtitleText &);
 #endif
 
 	int _subtitleQueuePos;
@@ -111,7 +112,7 @@ protected:
 
 	virtual void akos_processQueue();
 
-	virtual void saveOrLoad(Serializer *s);
+	virtual void saveLoadWithSerializer(Common::Serializer &s);
 
 	virtual void readMAXS(int blockSize);
 	virtual void readGlobalObjects();
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 599871b..8099dd2 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -1116,14 +1116,9 @@ AudioCDManager::Status Sound::getCDStatus() {
 	}
 }
 
-void Sound::saveLoadWithSerializer(Serializer *ser) {
-	static const SaveLoadEntry soundEntries[] = {
-		MKLINE(Sound, _currentCDSound, sleInt16, VER(35)),
-		MKLINE(Sound, _currentMusic, sleInt16, VER(35)),
-		MKEND()
-	};
-
-	ser->saveLoadEntries(this, soundEntries);
+void Sound::saveLoadWithSerializer(Common::Serializer &s) {
+	s.syncAsSint16LE(_currentCDSound, VER(35));
+	s.syncAsSint16LE(_currentMusic, VER(35));
 }
 
 
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index bc1e88f..4405703 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -24,6 +24,7 @@
 #define SCUMM_SOUND_H
 
 #include "common/scummsys.h"
+#include "common/serializer.h"
 #include "common/str.h"
 #include "audio/mididrv.h"
 #include "backends/audiocd/audiocd.h"
@@ -46,7 +47,7 @@ enum {
 
 // TODO: Consider splitting Sound into even more subclasses.
 // E.g. for v1-v4, v5, v6+, ...
-class Sound : public Serializable {
+class Sound : public Common::Serializable {
 public:
 	enum SoundMode {
 		kVOCMode,
@@ -132,8 +133,7 @@ public:
 	AudioCDManager::Status getCDStatus();
 	int getCurrentCDSound() const { return _currentCDSound; }
 
-	// Used by the save/load system:
-	void saveLoadWithSerializer(Serializer *ser);
+	void saveLoadWithSerializer(Common::Serializer &ser);
 
 protected:
 	void setupSfxFile();


Commit: 2e061d95c5aeed11b20999baa62418ef3c53141c
    https://github.com/scummvm/scummvm/commit/2e061d95c5aeed11b20999baa62418ef3c53141c
Author: Colin Snover (github.com at zetafleet.com)
Date: 2018-01-31T17:58:01+01:00

Commit Message:
COMMON: Move VER macro for serializer into common code

Changed paths:
  R engines/scumm/saveload.h
    common/serializer.h
    engines/sci/engine/savegame.cpp
    engines/scumm/actor.cpp
    engines/scumm/actor.h
    engines/scumm/charset.h
    engines/scumm/cursor.cpp
    engines/scumm/he/sprite_he.cpp
    engines/scumm/imuse/imuse.cpp
    engines/scumm/imuse/imuse_internal.h
    engines/scumm/imuse/imuse_part.cpp
    engines/scumm/imuse/imuse_player.cpp
    engines/scumm/imuse/instrument.cpp
    engines/scumm/imuse_digi/dimuse.cpp
    engines/scumm/players/player_ad.cpp
    engines/scumm/players/player_mac.h
    engines/scumm/saveload.cpp
    engines/scumm/sound.h


diff --git a/common/serializer.h b/common/serializer.h
index 09f36d0..e8db409 100644
--- a/common/serializer.h
+++ b/common/serializer.h
@@ -28,6 +28,7 @@
 
 namespace Common {
 
+#define VER(x) Common::Serializer::Version(x)
 
 #define SYNC_AS(SUFFIX,TYPE,SIZE) \
 	template<typename T> \
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index a7ebe0b..9f023c7 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -61,12 +61,6 @@
 
 namespace Sci {
 
-
-#define VER(x) Common::Serializer::Version(x)
-
-
-#pragma mark -
-
 // These are serialization functions for various objects.
 
 void syncWithSerializer(Common::Serializer &s, Common::Serializable &obj) {
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp
index c00e38e..004de36 100644
--- a/engines/scumm/actor.cpp
+++ b/engines/scumm/actor.cpp
@@ -31,7 +31,6 @@
 #include "scumm/he/intern_he.h"
 #include "scumm/object.h"
 #include "scumm/resource.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm_v7.h"
 #include "scumm/scumm_v0.h"
 #include "scumm/he/sound_he.h"
diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h
index c059d08..8a1d8e3 100644
--- a/engines/scumm/actor.h
+++ b/engines/scumm/actor.h
@@ -26,7 +26,6 @@
 
 #include "common/scummsys.h"
 #include "common/serializer.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm.h"
 
 
diff --git a/engines/scumm/charset.h b/engines/scumm/charset.h
index 7f3a8ba..7f69798 100644
--- a/engines/scumm/charset.h
+++ b/engines/scumm/charset.h
@@ -28,7 +28,6 @@
 #include "graphics/sjis.h"
 #include "scumm/scumm.h"
 #include "scumm/gfx.h"
-#include "scumm/saveload.h"
 
 namespace Scumm {
 
diff --git a/engines/scumm/cursor.cpp b/engines/scumm/cursor.cpp
index ab38fa5..d7eae60 100644
--- a/engines/scumm/cursor.cpp
+++ b/engines/scumm/cursor.cpp
@@ -31,7 +31,6 @@
 #include "scumm/he/intern_he.h"
 #include "scumm/object.h"
 #include "scumm/he/resource_he.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm.h"
 #include "scumm/scumm_v2.h"
 #include "scumm/scumm_v5.h"
diff --git a/engines/scumm/he/sprite_he.cpp b/engines/scumm/he/sprite_he.cpp
index 16c3b50..e210e0b 100644
--- a/engines/scumm/he/sprite_he.cpp
+++ b/engines/scumm/he/sprite_he.cpp
@@ -24,7 +24,6 @@
 
 #include "scumm/he/intern_he.h"
 #include "scumm/resource.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm.h"
 #include "scumm/he/sprite_he.h"
 #include "scumm/usage_bits.h"
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index d083dc8..109125e 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -32,7 +32,6 @@
 #include "scumm/imuse/imuse_internal.h"
 #include "scumm/imuse/instrument.h"
 #include "scumm/resource.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm.h"
 
 namespace Scumm {
diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index 7b1d2f6..e1e3548 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -27,7 +27,6 @@
 #include "common/serializer.h"
 #include "scumm/imuse/imuse.h"
 #include "scumm/imuse/instrument.h"
-#include "scumm/saveload.h"
 #include "audio/mididrv.h"
 
 class MidiParser;
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index ca0eaa4..33492a1 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -26,7 +26,6 @@
 #include "common/textconsole.h"
 #include "common/util.h"
 #include "scumm/imuse/imuse_internal.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm.h"
 
 namespace Scumm {
diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp
index a4b79f7..b422418 100644
--- a/engines/scumm/imuse/imuse_player.cpp
+++ b/engines/scumm/imuse/imuse_player.cpp
@@ -26,7 +26,6 @@
 #include "engines/engine.h"
 
 #include "scumm/imuse/imuse_internal.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm.h"
 
 #include "audio/midiparser.h"
diff --git a/engines/scumm/imuse/instrument.cpp b/engines/scumm/imuse/instrument.cpp
index 708a980..2ae38b1 100644
--- a/engines/scumm/imuse/instrument.cpp
+++ b/engines/scumm/imuse/instrument.cpp
@@ -21,7 +21,6 @@
  */
 
 #include "scumm/scumm.h"
-#include "scumm/saveload.h"
 #include "scumm/imuse/instrument.h"
 #include "audio/mididrv.h"
 
diff --git a/engines/scumm/imuse_digi/dimuse.cpp b/engines/scumm/imuse_digi/dimuse.cpp
index 9dac8b7..b695521 100644
--- a/engines/scumm/imuse_digi/dimuse.cpp
+++ b/engines/scumm/imuse_digi/dimuse.cpp
@@ -24,7 +24,6 @@
 #include "common/timer.h"
 
 #include "scumm/actor.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm_v7.h"
 #include "scumm/sound.h"
 #include "scumm/imuse_digi/dimuse.h"
diff --git a/engines/scumm/players/player_ad.cpp b/engines/scumm/players/player_ad.cpp
index 2de8ac9..0223da5 100644
--- a/engines/scumm/players/player_ad.cpp
+++ b/engines/scumm/players/player_ad.cpp
@@ -24,7 +24,6 @@
 #include "scumm/imuse/imuse.h"
 #include "scumm/scumm.h"
 #include "scumm/resource.h"
-#include "scumm/saveload.h"
 
 #include "audio/fmopl.h"
 #include "audio/mixer.h"
diff --git a/engines/scumm/players/player_mac.h b/engines/scumm/players/player_mac.h
index 897960d..713d72c 100644
--- a/engines/scumm/players/player_mac.h
+++ b/engines/scumm/players/player_mac.h
@@ -27,7 +27,6 @@
 #include "common/util.h"
 #include "common/mutex.h"
 #include "scumm/music.h"
-#include "scumm/saveload.h"
 #include "audio/audiostream.h"
 #include "audio/mixer.h"
 
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index 3e0a7f1..db36553 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -35,7 +35,6 @@
 #include "scumm/he/intern_he.h"
 #include "scumm/object.h"
 #include "scumm/resource.h"
-#include "scumm/saveload.h"
 #include "scumm/scumm_v0.h"
 #include "scumm/scumm_v7.h"
 #include "scumm/sound.h"
@@ -69,6 +68,7 @@ struct SaveInfoSection {
 
 #define SaveInfoSectionSize (4+4+4 + 4+4 + 4+2)
 
+#define CURRENT_VER 98
 #define INFOSECTION_VERSION 2
 
 #pragma mark -
diff --git a/engines/scumm/saveload.h b/engines/scumm/saveload.h
deleted file mode 100644
index a0f45a3..0000000
--- a/engines/scumm/saveload.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef SCUMM_SAVELOAD_H
-#define SCUMM_SAVELOAD_H
-
-#include "common/scummsys.h"
-#include "common/serializer.h"
-
-namespace Scumm {
-
-/**
- * The current savegame format version.
- * Our save/load system uses an elaborate scheme to allow us to modify the
- * savegame while keeping full backward compatibility, in the sense that newer
- * ScummVM versions always are able to load old savegames.
- * In order to achieve that, we store a version in the savegame files, and whenever
- * the savegame layout is modified, the version is incremented.
- *
- * This roughly works by marking each savegame entry with a range of versions
- * for which it is valid; the save/load code iterates over all entries, but
- * only saves/loads those which are valid for the version of the savegame
- * which is being loaded/saved currently.
- */
-#define CURRENT_VER 98
-
-/**
- * An auxillary macro, used to specify savegame versions. We use this instead
- * of just writing the raw version, because this way they stand out more to
- * the reading eye, making it a bit easier to navigate through the code.
- */
-#define VER(x) Common::Serializer::Version(x)
-
-} // End of namespace Scumm
-
-#endif
diff --git a/engines/scumm/sound.h b/engines/scumm/sound.h
index 4405703..740420e 100644
--- a/engines/scumm/sound.h
+++ b/engines/scumm/sound.h
@@ -28,7 +28,6 @@
 #include "common/str.h"
 #include "audio/mididrv.h"
 #include "backends/audiocd/audiocd.h"
-#include "scumm/saveload.h"
 
 namespace Audio {
 class Mixer;





More information about the Scummvm-git-logs mailing list