diff options
| author | Max Horn | 2002-12-08 16:14:29 +0000 | 
|---|---|---|
| committer | Max Horn | 2002-12-08 16:14:29 +0000 | 
| commit | 4ddecdad589e9df3db4a5a12fb9cdb874ae1d00b (patch) | |
| tree | 165ba65531919c0a158136d496b225a3f30a969a /scumm/saveload.cpp | |
| parent | 2986adb53dea09928f5051674e4d53d39d83cf27 (diff) | |
| download | scummvm-rg350-4ddecdad589e9df3db4a5a12fb9cdb874ae1d00b.tar.gz scummvm-rg350-4ddecdad589e9df3db4a5a12fb9cdb874ae1d00b.tar.bz2 scummvm-rg350-4ddecdad589e9df3db4a5a12fb9cdb874ae1d00b.zip | |
Patch #650085: Make saveload system extensible
svn-id: r5885
Diffstat (limited to 'scumm/saveload.cpp')
| -rw-r--r-- | scumm/saveload.cpp | 929 | 
1 files changed, 445 insertions, 484 deletions
| diff --git a/scumm/saveload.cpp b/scumm/saveload.cpp index a562925587..e55188fde7 100644 --- a/scumm/saveload.cpp +++ b/scumm/saveload.cpp @@ -38,23 +38,12 @@ struct SaveGameHeader {  	char name[32];  }; -// Support for "old" savegames (made with 2501 CVS build) -// Can be useful for other ports too :) - -#define VER_V9 9 -#define VER_V8 8 -#define VER_V7 7 - -#define CURRENT_VER VER_V9 - -static uint32 _current_version = CURRENT_VER;  bool Scumm::saveState(int slot, bool compat)  {  	char filename[256];  	SerializerStream out;  	SaveGameHeader hdr; -	Serializer ser;  	makeSavegameName(filename, slot, compat); @@ -65,12 +54,13 @@ bool Scumm::saveState(int slot, bool compat)  	hdr.type = MKID('SCVM');  	hdr.size = 0; -	hdr.ver = TO_LE_32(_current_version); +	hdr.ver = TO_LE_32(CURRENT_VER);  	out.fwrite(&hdr, sizeof(hdr), 1); -	ser._saveLoadStream = out; -	ser._saveOrLoad = true; +	Serializer ser(out, true, CURRENT_VER); + +	_savegameVersion = CURRENT_VER;  	saveOrLoad(&ser);  	out.fclose(); @@ -84,7 +74,6 @@ bool Scumm::loadState(int slot, bool compat)  	SerializerStream out;  	int i, j;  	SaveGameHeader hdr; -	Serializer ser;  	int sb, sh;  	makeSavegameName(filename, slot, compat); @@ -100,16 +89,23 @@ bool Scumm::loadState(int slot, bool compat)  	// In older versions of ScummVM, the header version was not endian safe.  	// We account for that by retrying once with swapped byte order. -	if (hdr.ver < VER_V7 || hdr.ver > _current_version) +	if (hdr.ver > CURRENT_VER)  		hdr.ver = SWAP_BYTES(hdr.ver); -	if (hdr.ver < VER_V7 || hdr.ver > _current_version) +	if (hdr.ver < VER_V7 || hdr.ver > CURRENT_VER)  	{  		warning("Invalid version of '%s'", filename);  		out.fclose();  		return false;  	} - -	_current_version = hdr.ver; +	 +	// Due to a bug in scummvm up to and including 0.3.0, save games could be saved +	// in the V8/V9 format but were tagged with a V7 mark. Ouch. So we just pretend V7 == V8 here +	if (hdr.ver == VER_V7) +		hdr.ver = VER_V8; + +	// _savegameVersion is set so that the load code can know which data format to expect +	_savegameVersion = hdr.ver; +	  	memcpy(_saveLoadName, hdr.name, sizeof(hdr.name));  	if (_imuseDigital) { @@ -133,8 +129,7 @@ bool Scumm::loadState(int slot, bool compat)  	initScummVars(); -	ser._saveLoadStream = out; -	ser._saveOrLoad = false; +	Serializer ser(out, false, _savegameVersion);  	saveOrLoad(&ser);  	out.fclose(); @@ -181,7 +176,6 @@ void Scumm::makeSavegameName(char *out, int slot, bool compatible)  {  	const char *dir = getSavePath(); -	// snprintf should be used here, but it's not portable enough  	sprintf(out, "%s%s.%c%.2d", dir, _game_name, compatible ? 'c' : 's', slot);  } @@ -205,9 +199,9 @@ bool Scumm::getSavegameName(int slot, char *desc)  		return false;  	} -	if (hdr.ver < VER_V7 || hdr.ver > _current_version) +	if (hdr.ver > CURRENT_VER)  		hdr.ver = TO_LE_32(hdr.ver); -	if (hdr.ver < VER_V7 || hdr.ver > _current_version) { +	if (hdr.ver < VER_V7 || hdr.ver > CURRENT_VER) {  		strcpy(desc, "Invalid version");  		return false;  	} @@ -220,410 +214,314 @@ bool Scumm::getSavegameName(int slot, char *desc)  void Scumm::saveOrLoad(Serializer *s)  {  	const SaveLoadEntry objectEntries[] = { -		MKLINE(ObjectData, offs_obim_to_room, sleUint32), -		MKLINE(ObjectData, offs_obcd_to_room, sleUint32), -		MKLINE(ObjectData, walk_x, sleUint16), -		MKLINE(ObjectData, walk_y, sleUint16), -		MKLINE(ObjectData, obj_nr, sleUint16), -		MKLINE(ObjectData, x_pos, sleInt16), -		MKLINE(ObjectData, y_pos, sleInt16), -		MKLINE(ObjectData, width, sleUint16), -		MKLINE(ObjectData, height, sleUint16), -		MKLINE(ObjectData, actordir, sleByte), -		MKLINE(ObjectData, parentstate, sleByte), -		MKLINE(ObjectData, parent, sleByte), -		MKLINE(ObjectData, state, sleByte), -		MKLINE(ObjectData, fl_object_index, sleByte), +		MKLINE(ObjectData, offs_obim_to_room, sleUint32, VER_V8), +		MKLINE(ObjectData, offs_obcd_to_room, sleUint32, VER_V8), +		MKLINE(ObjectData, walk_x, sleUint16, VER_V8), +		MKLINE(ObjectData, walk_y, sleUint16, VER_V8), +		MKLINE(ObjectData, obj_nr, sleUint16, VER_V8), +		MKLINE(ObjectData, x_pos, sleInt16, VER_V8), +		MKLINE(ObjectData, y_pos, sleInt16, VER_V8), +		MKLINE(ObjectData, width, sleUint16, VER_V8), +		MKLINE(ObjectData, height, sleUint16, VER_V8), +		MKLINE(ObjectData, actordir, sleByte, VER_V8), +		MKLINE(ObjectData, parentstate, sleByte, VER_V8), +		MKLINE(ObjectData, parent, sleByte, VER_V8), +		MKLINE(ObjectData, state, sleByte, VER_V8), +		MKLINE(ObjectData, fl_object_index, sleByte, VER_V8),  		MKEND()  	};  	const SaveLoadEntry actorEntries[] = { -		MKLINE(Actor, x, sleInt16), -		MKLINE(Actor, y, sleInt16), -		MKLINE(Actor, top, sleInt16), -		MKLINE(Actor, bottom, sleInt16), -		MKLINE(Actor, elevation, sleInt16), -		MKLINE(Actor, width, sleUint16), -		MKLINE(Actor, facing, sleUint16), -		MKLINE(Actor, costume, sleUint16), -		MKLINE(Actor, room, sleByte), -		MKLINE(Actor, talkColor, sleByte), -		MKLINE(Actor, scalex, sleByte), -		MKLINE(Actor, scaley, sleByte), -		MKLINE(Actor, charset, sleByte), -		MKARRAY(Actor, sound[0], sleByte, 8), -		MKARRAY(Actor, animVariable[0], sleUint16, 8), -		MKLINE(Actor, newDirection, sleUint16), -		MKLINE(Actor, moving, sleByte), -		MKLINE(Actor, ignoreBoxes, sleByte), -		MKLINE(Actor, forceClip, sleByte), -		MKLINE(Actor, initFrame, sleByte), -		MKLINE(Actor, walkFrame, sleByte), -		MKLINE(Actor, standFrame, sleByte), -		MKLINE(Actor, talkFrame1, sleByte), -		MKLINE(Actor, talkFrame2, sleByte), -		MKLINE(Actor, speedx, sleUint16), -		MKLINE(Actor, speedy, sleUint16), -		MKLINE(Actor, cost.animCounter1, sleUint16), -		MKLINE(Actor, cost.animCounter2, sleByte), -		// TODO: increase actor palette to 256 -		MKARRAY(Actor, palette[0], sleByte, 64), -		MKLINE(Actor, mask, sleByte), // FIXME: see actor.h comment -		MKLINE(Actor, shadow_mode, sleByte), -		MKLINE(Actor, visible, sleByte), +		MKLINE(Actor, x, sleInt16, VER_V8), +		MKLINE(Actor, y, sleInt16, VER_V8), +		MKLINE(Actor, top, sleInt16, VER_V8), +		MKLINE(Actor, bottom, sleInt16, VER_V8), +		MKLINE(Actor, elevation, sleInt16, VER_V8), +		MKLINE(Actor, width, sleUint16, VER_V8), +		MKLINE(Actor, facing, sleUint16, VER_V8), +		MKLINE(Actor, costume, sleUint16, VER_V8), +		MKLINE(Actor, room, sleByte, VER_V8), +		MKLINE(Actor, talkColor, sleByte, VER_V8), +		MKLINE(Actor, scalex, sleByte, VER_V8), +		MKLINE(Actor, scaley, sleByte, VER_V8), +		MKLINE(Actor, charset, sleByte, VER_V8), +		MKARRAY(Actor, sound[0], sleByte, 8, VER_V8), +		MKARRAY(Actor, animVariable[0], sleUint16, 8, VER_V8), +		MKLINE(Actor, newDirection, sleUint16, VER_V8), +		MKLINE(Actor, moving, sleByte, VER_V8), +		MKLINE(Actor, ignoreBoxes, sleByte, VER_V8), +		MKLINE(Actor, forceClip, sleByte, VER_V8), +		MKLINE(Actor, initFrame, sleByte, VER_V8), +		MKLINE(Actor, walkFrame, sleByte, VER_V8), +		MKLINE(Actor, standFrame, sleByte, VER_V8), +		MKLINE(Actor, talkFrame1, sleByte, VER_V8), +		MKLINE(Actor, talkFrame2, sleByte, VER_V8), +		MKLINE(Actor, speedx, sleUint16, VER_V8), +		MKLINE(Actor, speedy, sleUint16, VER_V8), +		MKLINE(Actor, cost.animCounter1, sleUint16, VER_V8), +		MKLINE(Actor, cost.animCounter2, sleByte, VER_V8), + +		// Actor palette grew from 64 to 256 bytes +		MKARRAY_OLD(Actor, palette[0], sleByte, 64, VER_V8, VER_V9), +		MKARRAY(Actor, palette[0], sleByte, 256, VER_V10), + +		MK_OBSOLETE(Actor, mask, sleByte, VER_V8, VER_V9), +		MKLINE(Actor, shadow_mode, sleByte, VER_V8), +		MKLINE(Actor, visible, sleByte, VER_V8),  		// FIXME - frame is never set and thus always 0! See actor.h comment -		MKLINE(Actor, frame, sleByte), -		MKLINE(Actor, animSpeed, sleByte), -		MKLINE(Actor, animProgress, sleByte), -		MKLINE(Actor, walkbox, sleByte), -		MKLINE(Actor, needRedraw, sleByte), -		MKLINE(Actor, needBgReset, sleByte), -		MKLINE(Actor, costumeNeedsInit, sleByte), - -		MKLINE(Actor, new_1, sleInt16), -		MKLINE(Actor, new_2, sleInt16), -		MKLINE(Actor, new_3, sleByte), - -		MKLINE(Actor, layer, sleByte), - -		MKLINE(Actor, talk_script, sleUint16), -		MKLINE(Actor, walk_script, sleUint16), - -		MKLINE(Actor, walkdata.destx, sleInt16), -		MKLINE(Actor, walkdata.desty, sleInt16), -		MKLINE(Actor, walkdata.destbox, sleByte), -		MKLINE(Actor, walkdata.destdir, sleUint16), -		MKLINE(Actor, walkdata.curbox, sleByte), -		MKLINE(Actor, walkdata.x, sleInt16), -		MKLINE(Actor, walkdata.y, sleInt16), -		MKLINE(Actor, walkdata.newx, sleInt16), -		MKLINE(Actor, walkdata.newy, sleInt16), -		MKLINE(Actor, walkdata.XYFactor, sleInt32), -		MKLINE(Actor, walkdata.YXFactor, sleInt32), -		MKLINE(Actor, walkdata.xfrac, sleUint16), -		MKLINE(Actor, walkdata.yfrac, sleUint16), - -		MKARRAY(Actor, cost.active[0], sleByte, 16), -		MKLINE(Actor, cost.stopped, sleUint16), -		MKARRAY(Actor, cost.curpos[0], sleUint16, 16), -		MKARRAY(Actor, cost.start[0], sleUint16, 16), -		MKARRAY(Actor, cost.end[0], sleUint16, 16), -		MKARRAY(Actor, cost.frame[0], sleUint16, 16), +		MKLINE(Actor, frame, sleByte, VER_V8), +		MKLINE(Actor, animSpeed, sleByte, VER_V8), +		MKLINE(Actor, animProgress, sleByte, VER_V8), +		MKLINE(Actor, walkbox, sleByte, VER_V8), +		MKLINE(Actor, needRedraw, sleByte, VER_V8), +		MKLINE(Actor, needBgReset, sleByte, VER_V8), +		MKLINE(Actor, costumeNeedsInit, sleByte, VER_V8), + +		MKLINE(Actor, new_1, sleInt16, VER_V8), +		MKLINE(Actor, new_2, sleInt16, VER_V8), +		MKLINE(Actor, new_3, sleByte, VER_V8), + +		MKLINE(Actor, layer, sleByte, VER_V8), + +		MKLINE(Actor, talk_script, sleUint16, VER_V8), +		MKLINE(Actor, walk_script, sleUint16, VER_V8), + +		MKLINE(Actor, walkdata.destx, sleInt16, VER_V8), +		MKLINE(Actor, walkdata.desty, sleInt16, VER_V8), +		MKLINE(Actor, walkdata.destbox, sleByte, VER_V8), +		MKLINE(Actor, walkdata.destdir, sleUint16, VER_V8), +		MKLINE(Actor, walkdata.curbox, sleByte, VER_V8), +		MKLINE(Actor, walkdata.x, sleInt16, VER_V8), +		MKLINE(Actor, walkdata.y, sleInt16, VER_V8), +		MKLINE(Actor, walkdata.newx, sleInt16, VER_V8), +		MKLINE(Actor, walkdata.newy, sleInt16, VER_V8), +		MKLINE(Actor, walkdata.XYFactor, sleInt32, VER_V8), +		MKLINE(Actor, walkdata.YXFactor, sleInt32, VER_V8), +		MKLINE(Actor, walkdata.xfrac, sleUint16, VER_V8), +		MKLINE(Actor, walkdata.yfrac, sleUint16, VER_V8), + +		MKARRAY(Actor, cost.active[0], sleByte, 16, VER_V8), +		MKLINE(Actor, cost.stopped, sleUint16, VER_V8), +		MKARRAY(Actor, cost.curpos[0], sleUint16, 16, VER_V8), +		MKARRAY(Actor, cost.start[0], sleUint16, 16, VER_V8), +		MKARRAY(Actor, cost.end[0], sleUint16, 16, VER_V8), +		MKARRAY(Actor, cost.frame[0], sleUint16, 16, VER_V8),  		MKEND()  	};  	const SaveLoadEntry verbEntries[] = { -		MKLINE(VerbSlot, x, sleInt16), -		MKLINE(VerbSlot, y, sleInt16), -		MKLINE(VerbSlot, right, sleInt16), -		MKLINE(VerbSlot, bottom, sleInt16), -		MKLINE(VerbSlot, oldleft, sleInt16), -		MKLINE(VerbSlot, oldtop, sleInt16), -		MKLINE(VerbSlot, oldright, sleInt16), -		MKLINE(VerbSlot, oldbottom, sleInt16), -		MKLINE(VerbSlot, verbid, sleByte), -		MKLINE(VerbSlot, color, sleByte), -		MKLINE(VerbSlot, hicolor, sleByte), -		MKLINE(VerbSlot, dimcolor, sleByte), -		MKLINE(VerbSlot, bkcolor, sleByte), -		MKLINE(VerbSlot, type, sleByte), -		MKLINE(VerbSlot, charset_nr, sleByte), -		MKLINE(VerbSlot, curmode, sleByte), -		MKLINE(VerbSlot, saveid, sleByte), -		MKLINE(VerbSlot, key, sleByte), -		MKLINE(VerbSlot, center, sleByte), -		MKLINE(VerbSlot, field_1B, sleByte), -		MKLINE(VerbSlot, imgindex, sleUint16), -		MKEND() -	}; - -	const SaveLoadEntry mainEntriesV9[] = { -		MKLINE(Scumm, _scrWidth, sleUint16), -		MKLINE(Scumm, _scrHeight, sleUint16), -		MKLINE(Scumm, _ENCD_offs, sleUint32), -		MKLINE(Scumm, _EXCD_offs, sleUint32), -		MKLINE(Scumm, _IM00_offs, sleUint32), -		MKLINE(Scumm, _CLUT_offs, sleUint32), -		/* XXX Remove _EPAL_offs next time format changes */ -		MKLINE(Scumm, _EPAL_offs, sleUint32), -		MKLINE(Scumm, _PALS_offs, sleUint32), -		MKLINE(Scumm, _curPalIndex, sleByte), -		MKLINE(Scumm, _currentRoom, sleByte), -		MKLINE(Scumm, _roomResource, sleByte), -		MKLINE(Scumm, _numObjectsInRoom, sleByte), -		MKLINE(Scumm, _currentScript, sleByte), -		MKARRAY(Scumm, _localScriptList[0], sleUint32, NUM_LOCALSCRIPT), -		MKARRAY(Scumm, vm.localvar[0][0], sleUint16, NUM_SCRIPT_SLOT * 17), -		MKARRAY(Scumm, _resourceMapper[0], sleByte, 128), -		MKARRAY(Scumm, charset._colorMap[0], sleByte, 16), -		MKARRAY(Scumm, _charsetData[0][0], sleByte, 10 * 16),	// FIXME - _charsetData is 15*16 these days -		MKLINE(Scumm, _curExecScript, sleUint16), - -		MKLINE(Scumm, camera._dest.x, sleInt16), -		MKLINE(Scumm, camera._dest.y, sleInt16), -		MKLINE(Scumm, camera._cur.x, sleInt16), -		MKLINE(Scumm, camera._cur.y, sleInt16), -		MKLINE(Scumm, camera._last.x, sleInt16), -		MKLINE(Scumm, camera._last.y, sleInt16), -		MKLINE(Scumm, camera._accel.x, sleInt16), -		MKLINE(Scumm, camera._accel.y, sleInt16), -		MKLINE(Scumm, _screenStartStrip, sleInt16), -		MKLINE(Scumm, _screenEndStrip, sleInt16), -		MKLINE(Scumm, camera._mode, sleByte), -		MKLINE(Scumm, camera._follows, sleByte), -		MKLINE(Scumm, camera._leftTrigger, sleInt16), -		MKLINE(Scumm, camera._rightTrigger, sleInt16), -		MKLINE(Scumm, camera._movingToActor, sleUint16), - -		MKLINE(Scumm, _actorToPrintStrFor, sleByte), -		MKLINE(Scumm, _charsetColor, sleByte), -		/* XXX Convert into word next time format changes */ -		MKLINE(Scumm, charset._bufPos, sleByte), -		MKLINE(Scumm, _haveMsg, sleByte), -		MKLINE(Scumm, _useTalkAnims, sleByte), - -		MKLINE(Scumm, _talkDelay, sleInt16), -		MKLINE(Scumm, _defaultTalkDelay, sleInt16), -		MKLINE(Scumm, _numInMsgStack, sleInt16), -		MKLINE(Scumm, _sentenceNum, sleByte), - -		MKLINE(Scumm, vm.cutSceneStackPointer, sleByte), -		MKARRAY(Scumm, vm.cutScenePtr[0], sleUint32, 5), -		MKARRAY(Scumm, vm.cutSceneScript[0], sleByte, 5), -		MKARRAY(Scumm, vm.cutSceneData[0], sleInt16, 5), -		MKLINE(Scumm, vm.cutSceneScriptIndex, sleInt16), - -		/* nest */ -		MKLINE(Scumm, _numNestedScripts, sleByte), -		MKLINE(Scumm, _userPut, sleByte), -		MKLINE(Scumm, _cursor.state, sleByte), -		MKLINE(Scumm, gdi._cursorActive, sleByte), -		MKLINE(Scumm, _currentCursor, sleByte), - -		MKLINE(Scumm, _doEffect, sleByte), -		MKLINE(Scumm, _switchRoomEffect, sleByte), -		MKLINE(Scumm, _newEffect, sleByte), -		MKLINE(Scumm, _switchRoomEffect2, sleByte), -		MKLINE(Scumm, _BgNeedsRedraw, sleByte), - -		// Jamieson630: variables for palManipulate -		// TODO: Add these next time save game format changes. -		// MKLINE(Scumm, _palManipStart, sleByte), -		// MKLINE(Scumm, _palManipEnd, sleByte), -		// MKLINE(Scumm, _palManipCounter, sleUint16), - -		// MKARRAY(Scumm, gfxUsageBits[0], sleUint32, 410), -		// replace below: -		MKARRAY(Scumm, gfxUsageBits[0], sleUint32, 200), -		MKLINE(Scumm, gdi._transparency, sleByte), -		MKARRAY(Scumm, _currentPalette[0], sleByte, 768), - -		MKARRAY(Scumm, _proc_special_palette[0], sleByte, 256), -		/* virtscr */ - -		MKARRAY(Scumm, charset._buffer[0], sleByte, 256), - -		MKLINE(Scumm, _egoPositioned, sleByte), - -		// FIXME: Should be 5, not 4 : -		MKARRAY(Scumm, gdi._imgBufOffs[0], sleUint16, 4), -		MKLINE(Scumm, gdi._numZBuffer, sleByte), - -		MKLINE(Scumm, _screenEffectFlag, sleByte), - -		// FIXME: remove when new savegame system is implemented -		MKLINE(Scumm, _randSeed1, sleUint32), -		MKLINE(Scumm, _randSeed2, sleUint32), - -		/* XXX: next time the save game format changes, -		 * convert _shakeEnabled to boolean and add a _shakeFrame field */ -		MKLINE(Scumm, _shakeEnabled, sleInt16), - -		MKLINE(Scumm, _keepText, sleByte), - -		MKLINE(Scumm, _screenB, sleUint16), -		MKLINE(Scumm, _screenH, sleUint16), - -		MKLINE(Scumm, _cd_track, sleInt16),	// FIXME - remove next time save format changes -		MKLINE(Scumm, _cd_loops, sleInt16),	// FIXME - remove next time save format changes -		MKLINE(Scumm, _cd_frame, sleInt16),	// FIXME - remove next time save format changes -		MKLINE(Scumm, _cd_end, sleInt16),	// FIXME - remove next time save format changes - +		MKLINE(VerbSlot, x, sleInt16, VER_V8), +		MKLINE(VerbSlot, y, sleInt16, VER_V8), +		MKLINE(VerbSlot, right, sleInt16, VER_V8), +		MKLINE(VerbSlot, bottom, sleInt16, VER_V8), +		MKLINE(VerbSlot, oldleft, sleInt16, VER_V8), +		MKLINE(VerbSlot, oldtop, sleInt16, VER_V8), +		MKLINE(VerbSlot, oldright, sleInt16, VER_V8), +		MKLINE(VerbSlot, oldbottom, sleInt16, VER_V8), +		MKLINE(VerbSlot, verbid, sleByte, VER_V8), +		MKLINE(VerbSlot, color, sleByte, VER_V8), +		MKLINE(VerbSlot, hicolor, sleByte, VER_V8), +		MKLINE(VerbSlot, dimcolor, sleByte, VER_V8), +		MKLINE(VerbSlot, bkcolor, sleByte, VER_V8), +		MKLINE(VerbSlot, type, sleByte, VER_V8), +		MKLINE(VerbSlot, charset_nr, sleByte, VER_V8), +		MKLINE(VerbSlot, curmode, sleByte, VER_V8), +		MKLINE(VerbSlot, saveid, sleByte, VER_V8), +		MKLINE(VerbSlot, key, sleByte, VER_V8), +		MKLINE(VerbSlot, center, sleByte, VER_V8), +		MKLINE(VerbSlot, field_1B, sleByte, VER_V8), +		MKLINE(VerbSlot, imgindex, sleUint16, VER_V8),  		MKEND()  	}; -	const SaveLoadEntry mainEntriesV8[] = { -		MKLINE(Scumm, _scrWidth, sleUint16), -		MKLINE(Scumm, _scrHeight, sleUint16), -		MKLINE(Scumm, _ENCD_offs, sleUint32), -		MKLINE(Scumm, _EXCD_offs, sleUint32), -		MKLINE(Scumm, _IM00_offs, sleUint32), -		MKLINE(Scumm, _CLUT_offs, sleUint32), -		/* XXX Remove _EPAL_offs next time format changes */ -		MKLINE(Scumm, _EPAL_offs, sleUint32), -		MKLINE(Scumm, _PALS_offs, sleUint32), -		MKLINE(Scumm, _curPalIndex, sleByte), -		MKLINE(Scumm, _currentRoom, sleByte), -		MKLINE(Scumm, _roomResource, sleByte), -		MKLINE(Scumm, _numObjectsInRoom, sleByte), -		MKLINE(Scumm, _currentScript, sleByte), -		MKARRAY(Scumm, _localScriptList[0], sleUint32, NUM_LOCALSCRIPT), -		MKARRAY(Scumm, vm.localvar[0][0], sleUint16, 25 * 17), -		MKARRAY(Scumm, _resourceMapper[0], sleByte, 128), -		MKARRAY(Scumm, charset._colorMap[0], sleByte, 16), -		MKARRAY(Scumm, _charsetData[0][0], sleByte, 10 * 16),	// FIXME - _charsetData is 15*16 these days -		MKLINE(Scumm, _curExecScript, sleUint16), - -		MKLINE(Scumm, camera._dest.x, sleInt16), -		MKLINE(Scumm, camera._dest.y, sleInt16), -		MKLINE(Scumm, camera._cur.x, sleInt16), -		MKLINE(Scumm, camera._cur.y, sleInt16), -		MKLINE(Scumm, camera._last.x, sleInt16), -		MKLINE(Scumm, camera._last.y, sleInt16), -		MKLINE(Scumm, camera._accel.x, sleInt16), -		MKLINE(Scumm, camera._accel.y, sleInt16), -		MKLINE(Scumm, _screenStartStrip, sleInt16), -		MKLINE(Scumm, _screenEndStrip, sleInt16), -		MKLINE(Scumm, camera._mode, sleByte), -		MKLINE(Scumm, camera._follows, sleByte), -		MKLINE(Scumm, camera._leftTrigger, sleInt16), -		MKLINE(Scumm, camera._rightTrigger, sleInt16), -		MKLINE(Scumm, camera._movingToActor, sleUint16), - -		MKLINE(Scumm, _actorToPrintStrFor, sleByte), -		MKLINE(Scumm, _charsetColor, sleByte), -		/* XXX Convert into word next time format changes */ -		MKLINE(Scumm, charset._bufPos, sleByte), -		MKLINE(Scumm, _haveMsg, sleByte), -		MKLINE(Scumm, _useTalkAnims, sleByte), - -		MKLINE(Scumm, _talkDelay, sleInt16), -		MKLINE(Scumm, _defaultTalkDelay, sleInt16), -		MKLINE(Scumm, _numInMsgStack, sleInt16), -		MKLINE(Scumm, _sentenceNum, sleByte), - -		MKLINE(Scumm, vm.cutSceneStackPointer, sleByte), -		MKARRAY(Scumm, vm.cutScenePtr[0], sleUint32, 5), -		MKARRAY(Scumm, vm.cutSceneScript[0], sleByte, 5), -		MKARRAY(Scumm, vm.cutSceneData[0], sleInt16, 5), -		MKLINE(Scumm, vm.cutSceneScriptIndex, sleInt16), - -		/* nest */ -		MKLINE(Scumm, _numNestedScripts, sleByte), -		MKLINE(Scumm, _userPut, sleByte), -		MKLINE(Scumm, _cursor.state, sleByte), -		MKLINE(Scumm, gdi._cursorActive, sleByte), -		MKLINE(Scumm, _currentCursor, sleByte), - -		MKLINE(Scumm, _doEffect, sleByte), -		MKLINE(Scumm, _switchRoomEffect, sleByte), -		MKLINE(Scumm, _newEffect, sleByte), -		MKLINE(Scumm, _switchRoomEffect2, sleByte), -		MKLINE(Scumm, _BgNeedsRedraw, sleByte), - -		// Jamieson630: variables for palManipulate -		// TODO: Add these next time save game format changes. -		// MKLINE(Scumm, _palManipStart, sleByte), -		// MKLINE(Scumm, _palManipEnd, sleByte), -		// MKLINE(Scumm, _palManipCounter, sleUint16), - -		// MKARRAY(Scumm, gfxUsageBits[0], sleUint32, 410), -		// replace below: -		MKARRAY(Scumm, gfxUsageBits[0], sleUint32, 200), -		MKLINE(Scumm, gdi._transparency, sleByte), -		MKARRAY(Scumm, _currentPalette[0], sleByte, 768), - -		MKARRAY(Scumm, _proc_special_palette[0], sleByte, 256), -		/* virtscr */ - -		MKARRAY(Scumm, charset._buffer[0], sleByte, 256), - -		MKLINE(Scumm, _egoPositioned, sleByte), - -		// FIXME: Should be 5, not 4 : -		MKARRAY(Scumm, gdi._imgBufOffs[0], sleUint16, 4), -		MKLINE(Scumm, gdi._numZBuffer, sleByte), - -		MKLINE(Scumm, _screenEffectFlag, sleByte), - -		// FIXME: remove when new savegame system is implemented -		MKLINE(Scumm, _randSeed1, sleUint32), -		MKLINE(Scumm, _randSeed2, sleUint32), - -		/* XXX: next time the save game format changes, -		 * convert _shakeEnabled to boolean and add a _shakeFrame field */ -		MKLINE(Scumm, _shakeEnabled, sleInt16), - -		MKLINE(Scumm, _keepText, sleByte), - -		MKLINE(Scumm, _screenB, sleUint16), -		MKLINE(Scumm, _screenH, sleUint16), - +	const SaveLoadEntry mainEntries[] = { +		MKLINE(Scumm, _scrWidth, sleUint16, VER_V8), +		MKLINE(Scumm, _scrHeight, sleUint16, VER_V8), +		MKLINE(Scumm, _ENCD_offs, sleUint32, VER_V8), +		MKLINE(Scumm, _EXCD_offs, sleUint32, VER_V8), +		MKLINE(Scumm, _IM00_offs, sleUint32, VER_V8), +		MKLINE(Scumm, _CLUT_offs, sleUint32, VER_V8), +		MK_OBSOLETE(Scumm, _EPAL_offs, sleUint32, VER_V8, VER_V9), +		MKLINE(Scumm, _PALS_offs, sleUint32, VER_V8), +		MKLINE(Scumm, _curPalIndex, sleByte, VER_V8), +		MKLINE(Scumm, _currentRoom, sleByte, VER_V8), +		MKLINE(Scumm, _roomResource, sleByte, VER_V8), +		MKLINE(Scumm, _numObjectsInRoom, sleByte, VER_V8), +		MKLINE(Scumm, _currentScript, sleByte, VER_V8), +		MKARRAY(Scumm, _localScriptList[0], sleUint32, NUM_LOCALSCRIPT, VER_V8), + +		// vm.localvar grew from 25 to 40 entries +		MKARRAY_OLD(Scumm, vm.localvar[0][0], sleUint16, 25 * 17, VER_V8, VER_V8), +		MKARRAY(Scumm, vm.localvar[0][0], sleUint16, NUM_SCRIPT_SLOT * 17, VER_V9), + +		MKARRAY(Scumm, _resourceMapper[0], sleByte, 128, VER_V8), +		MKARRAY(Scumm, charset._colorMap[0], sleByte, 16, VER_V8), +		 +		// _charsetData grew from 10*16 to 15*16 bytes +		MKARRAY_OLD(Scumm, _charsetData[0][0], sleByte, 10 * 16, VER_V8, VER_V9), +		MKARRAY(Scumm, _charsetData[0][0], sleByte, 15 * 16, VER_V10), + +		MKLINE(Scumm, _curExecScript, sleUint16, VER_V8), + +		MKLINE(Scumm, camera._dest.x, sleInt16, VER_V8), +		MKLINE(Scumm, camera._dest.y, sleInt16, VER_V8), +		MKLINE(Scumm, camera._cur.x, sleInt16, VER_V8), +		MKLINE(Scumm, camera._cur.y, sleInt16, VER_V8), +		MKLINE(Scumm, camera._last.x, sleInt16, VER_V8), +		MKLINE(Scumm, camera._last.y, sleInt16, VER_V8), +		MKLINE(Scumm, camera._accel.x, sleInt16, VER_V8), +		MKLINE(Scumm, camera._accel.y, sleInt16, VER_V8), +		MKLINE(Scumm, _screenStartStrip, sleInt16, VER_V8), +		MKLINE(Scumm, _screenEndStrip, sleInt16, VER_V8), +		MKLINE(Scumm, camera._mode, sleByte, VER_V8), +		MKLINE(Scumm, camera._follows, sleByte, VER_V8), +		MKLINE(Scumm, camera._leftTrigger, sleInt16, VER_V8), +		MKLINE(Scumm, camera._rightTrigger, sleInt16, VER_V8), +		MKLINE(Scumm, camera._movingToActor, sleUint16, VER_V8), + +		MKLINE(Scumm, _actorToPrintStrFor, sleByte, VER_V8), +		MKLINE(Scumm, _charsetColor, sleByte, VER_V8), + +		// charset._bufPos was changed from byte to int +		MKLINE_OLD(Scumm, charset._bufPos, sleByte, VER_V8, VER_V9), +		MKLINE(Scumm, charset._bufPos, sleInt16, VER_V10), + +		MKLINE(Scumm, _haveMsg, sleByte, VER_V8), +		MKLINE(Scumm, _useTalkAnims, sleByte, VER_V8), + +		MKLINE(Scumm, _talkDelay, sleInt16, VER_V8), +		MKLINE(Scumm, _defaultTalkDelay, sleInt16, VER_V8), +		MKLINE(Scumm, _numInMsgStack, sleInt16, VER_V8), +		MKLINE(Scumm, _sentenceNum, sleByte, VER_V8), + +		MKLINE(Scumm, vm.cutSceneStackPointer, sleByte, VER_V8), +		MKARRAY(Scumm, vm.cutScenePtr[0], sleUint32, 5, VER_V8), +		MKARRAY(Scumm, vm.cutSceneScript[0], sleByte, 5, VER_V8), +		MKARRAY(Scumm, vm.cutSceneData[0], sleInt16, 5, VER_V8), +		MKLINE(Scumm, vm.cutSceneScriptIndex, sleInt16, VER_V8), + +		MKLINE(Scumm, _numNestedScripts, sleByte, VER_V8), +		MKLINE(Scumm, _userPut, sleByte, VER_V8), +		MKLINE(Scumm, _cursor.state, sleByte, VER_V8), +		MKLINE(Scumm, gdi._cursorActive, sleByte, VER_V8), +		MKLINE(Scumm, _currentCursor, sleByte, VER_V8), + +		MKLINE(Scumm, _doEffect, sleByte, VER_V8), +		MKLINE(Scumm, _switchRoomEffect, sleByte, VER_V8), +		MKLINE(Scumm, _newEffect, sleByte, VER_V8), +		MKLINE(Scumm, _switchRoomEffect2, sleByte, VER_V8), +		MKLINE(Scumm, _BgNeedsRedraw, sleByte, VER_V8), + +		// The state of palManipulate is stored only since V10 +		MKLINE(Scumm, _palManipStart, sleByte, VER_V10), +		MKLINE(Scumm, _palManipEnd, sleByte, VER_V10), +		MKLINE(Scumm, _palManipCounter, sleUint16, VER_V10), + +		// gfxUsageBits grew from 200 to 410 entries: +		MKARRAY_OLD(Scumm, gfxUsageBits[0], sleUint32, 200, VER_V8, VER_V9), +		MKARRAY(Scumm, gfxUsageBits[0], sleUint32, 410, VER_V10), + +		MKLINE(Scumm, gdi._transparency, sleByte, VER_V8), +		MKARRAY(Scumm, _currentPalette[0], sleByte, 768, VER_V8), + +		MKARRAY(Scumm, _proc_special_palette[0], sleByte, 256, VER_V8), + +		MKARRAY(Scumm, charset._buffer[0], sleByte, 256, VER_V8), + +		MKLINE(Scumm, _egoPositioned, sleByte, VER_V8), + +		// gdi._imgBufOffs grew from 4 to 5 entries : +		MKARRAY_OLD(Scumm, gdi._imgBufOffs[0], sleUint16, 4, VER_V8, VER_V9), +		MKARRAY(Scumm, gdi._imgBufOffs[0], sleUint16, 5, VER_V10), + +		MKLINE(Scumm, gdi._numZBuffer, sleByte, VER_V8), + +		MKLINE(Scumm, _screenEffectFlag, sleByte, VER_V8), + +		MK_OBSOLETE(Scumm, _randSeed1, sleUint32, VER_V8, VER_V9), +		MK_OBSOLETE(Scumm, _randSeed2, sleUint32, VER_V8, VER_V9), + +		// Converted _shakeEnabled to boolean and added a _shakeFrame field. +		MKLINE_OLD(Scumm, _shakeEnabled, sleInt16, VER_V8, VER_V9), +		MKLINE(Scumm, _shakeEnabled, sleByte, VER_V10), +		MKLINE(Scumm, _shakeFrame, sleUint32, VER_V10), + +		MKLINE(Scumm, _keepText, sleByte, VER_V8), + +		MKLINE(Scumm, _screenB, sleUint16, VER_V8), +		MKLINE(Scumm, _screenH, sleUint16, VER_V8), + +		MK_OBSOLETE(Scumm, _cd_track, sleInt16, VER_V9, VER_V9), +		MK_OBSOLETE(Scumm, _cd_loops, sleInt16, VER_V9, VER_V9), +		MK_OBSOLETE(Scumm, _cd_frame, sleInt16, VER_V9, VER_V9), +		MK_OBSOLETE(Scumm, _cd_end, sleInt16, VER_V9, VER_V9), +		  		MKEND()  	};  	const SaveLoadEntry scriptSlotEntries[] = { -		MKLINE(ScriptSlot, offs, sleUint32), -		MKLINE(ScriptSlot, delay, sleInt32), -		MKLINE(ScriptSlot, number, sleUint16), -		MKLINE(ScriptSlot, delayFrameCount, sleUint16), -		MKLINE(ScriptSlot, status, sleByte), -		MKLINE(ScriptSlot, where, sleByte), -		MKLINE(ScriptSlot, unk1, sleByte), -		MKLINE(ScriptSlot, unk2, sleByte), -		MKLINE(ScriptSlot, freezeCount, sleByte), -		MKLINE(ScriptSlot, didexec, sleByte), -		MKLINE(ScriptSlot, cutsceneOverride, sleByte), -		MKLINE(ScriptSlot, unk5, sleByte), +		MKLINE(ScriptSlot, offs, sleUint32, VER_V8), +		MKLINE(ScriptSlot, delay, sleInt32, VER_V8), +		MKLINE(ScriptSlot, number, sleUint16, VER_V8), +		MKLINE(ScriptSlot, delayFrameCount, sleUint16, VER_V8), +		MKLINE(ScriptSlot, status, sleByte, VER_V8), +		MKLINE(ScriptSlot, where, sleByte, VER_V8), +		MKLINE(ScriptSlot, unk1, sleByte, VER_V8), +		MKLINE(ScriptSlot, unk2, sleByte, VER_V8), +		MKLINE(ScriptSlot, freezeCount, sleByte, VER_V8), +		MKLINE(ScriptSlot, didexec, sleByte, VER_V8), +		MKLINE(ScriptSlot, cutsceneOverride, sleByte, VER_V8), +		MKLINE(ScriptSlot, unk5, sleByte, VER_V8),  		MKEND()  	};  	const SaveLoadEntry nestedScriptEntries[] = { -		MKLINE(NestedScript, number, sleUint16), -		MKLINE(NestedScript, where, sleByte), -		MKLINE(NestedScript, slot, sleByte), +		MKLINE(NestedScript, number, sleUint16, VER_V8), +		MKLINE(NestedScript, where, sleByte, VER_V8), +		MKLINE(NestedScript, slot, sleByte, VER_V8),  		MKEND()  	};  	const SaveLoadEntry sentenceTabEntries[] = { -		MKLINE(SentenceTab, unk5, sleUint8), -		MKLINE(SentenceTab, unk2, sleUint8), -		MKLINE(SentenceTab, unk4, sleUint16), -		MKLINE(SentenceTab, unk3, sleUint16), -		MKLINE(SentenceTab, unk, sleUint8), +		MKLINE(SentenceTab, unk5, sleUint8, VER_V8), +		MKLINE(SentenceTab, unk2, sleUint8, VER_V8), +		MKLINE(SentenceTab, unk4, sleUint16, VER_V8), +		MKLINE(SentenceTab, unk3, sleUint16, VER_V8), +		MKLINE(SentenceTab, unk, sleUint8, VER_V8),  		MKEND()  	};  	const SaveLoadEntry stringTabEntries[] = {  		// TODO - It makes no sense to have all these t_* fields in StringTab  		// Rather let's dump them all when the save game format changes, and  -		// keep two StringTab objects: one normal, and a "t_" one. -		// Then copying them can be done in one line etc. -		MKLINE(StringTab, xpos, sleInt16), -		MKLINE(StringTab, t_xpos, sleInt16), -		MKLINE(StringTab, ypos, sleInt16), -		MKLINE(StringTab, t_ypos, sleInt16), -		MKLINE(StringTab, right, sleInt16), -		MKLINE(StringTab, t_right, sleInt16), -		MKLINE(StringTab, color, sleInt8), -		MKLINE(StringTab, t_color, sleInt8), -		MKLINE(StringTab, charset, sleInt8), -		MKLINE(StringTab, t_charset, sleInt8), -		MKLINE(StringTab, center, sleByte), -		MKLINE(StringTab, t_center, sleByte), -		MKLINE(StringTab, overhead, sleByte), -		MKLINE(StringTab, t_overhead, sleByte), -		MKLINE(StringTab, no_talk_anim, sleByte), -		MKLINE(StringTab, t_no_talk_anim, sleByte), +		// keep two StringTab objects where we have one now: a "normal" one, +		// and a temporar y"t_" one. +		// Then backup/restore of a StringTab entry becomes a one liner. +		MKLINE(StringTab, xpos, sleInt16, VER_V8), +		MKLINE(StringTab, t_xpos, sleInt16, VER_V8), +		MKLINE(StringTab, ypos, sleInt16, VER_V8), +		MKLINE(StringTab, t_ypos, sleInt16, VER_V8), +		MKLINE(StringTab, right, sleInt16, VER_V8), +		MKLINE(StringTab, t_right, sleInt16, VER_V8), +		MKLINE(StringTab, color, sleInt8, VER_V8), +		MKLINE(StringTab, t_color, sleInt8, VER_V8), +		MKLINE(StringTab, charset, sleInt8, VER_V8), +		MKLINE(StringTab, t_charset, sleInt8, VER_V8), +		MKLINE(StringTab, center, sleByte, VER_V8), +		MKLINE(StringTab, t_center, sleByte, VER_V8), +		MKLINE(StringTab, overhead, sleByte, VER_V8), +		MKLINE(StringTab, t_overhead, sleByte, VER_V8), +		MKLINE(StringTab, no_talk_anim, sleByte, VER_V8), +		MKLINE(StringTab, t_no_talk_anim, sleByte, VER_V8),  		MKEND()  	};  	const SaveLoadEntry colorCycleEntries[] = { -		MKLINE(ColorCycle, delay, sleUint16), -		MKLINE(ColorCycle, counter, sleUint16), -		MKLINE(ColorCycle, flags, sleUint16), -		MKLINE(ColorCycle, start, sleByte), -		MKLINE(ColorCycle, end, sleByte), +		MKLINE(ColorCycle, delay, sleUint16, VER_V8), +		MKLINE(ColorCycle, counter, sleUint16, VER_V8), +		MKLINE(ColorCycle, flags, sleUint16, VER_V8), +		MKLINE(ColorCycle, start, sleByte, VER_V8), +		MKLINE(ColorCycle, end, sleByte, VER_V8),  		MKEND()  	}; @@ -642,17 +540,15 @@ void Scumm::saveOrLoad(Serializer *s)  		}  	} -	if (_current_version == VER_V9) -		s->saveLoadEntries(this, mainEntriesV9); -	else -		s->saveLoadEntries(this, mainEntriesV8); +	s->saveLoadEntries(this, mainEntries);  	s->saveLoadArrayOf(_actors, NUM_ACTORS, sizeof(_actors[0]), actorEntries); -	if (_current_version < VER_V9) +	if (_savegameVersion < VER_V9)  		s->saveLoadArrayOf(vm.slot, 25, sizeof(vm.slot[0]), scriptSlotEntries);  	else  		s->saveLoadArrayOf(vm.slot, NUM_SCRIPT_SLOT, sizeof(vm.slot[0]), scriptSlotEntries); +  	s->saveLoadArrayOf(_objs, _numLocalObjects, sizeof(_objs[0]), objectEntries);  	s->saveLoadArrayOf(_verbs, _numVerbs, sizeof(_verbs[0]), verbEntries);  	s->saveLoadArrayOf(vm.nest, 16, sizeof(vm.nest[0]), nestedScriptEntries); @@ -674,7 +570,9 @@ void Scumm::saveOrLoad(Serializer *s)  	if (_shadowPaletteSize)  		s->saveLoadArrayOf(_shadowPalette, _shadowPaletteSize, 1, sleByte); -	_palManipCounter = 0; // TODO: Remove this once it's being loaded from disk +	// PalManip data was not saved before V10 save games +	if (_savegameVersion < VER_V10) +		_palManipCounter = 0;  	if (_palManipCounter) {  		if (!_palManipPalette)  			_palManipPalette = (byte *)calloc(0x300, 1); @@ -823,83 +721,92 @@ byte Serializer::loadByte()  	return e;  } -void Serializer::saveLoadArrayOf(void *b, int len, int datasize, byte filetype) +void Serializer::saveArrayOf(void *b, int len, int datasize, byte filetype)  {  	byte *at = (byte *)b;  	uint32 data; -	/* speed up byte arrays */ +	// speed up byte arrays  	if (datasize == 1 && filetype == sleByte) { -		if (isSaving()) -			saveBytes(b, len); -		else -			loadBytes(b, len); +		saveBytes(b, len);  		return;  	}  	while (--len >= 0) { -		if (isSaving()) { -			/* saving */ -			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("saveLoadArrayOf: invalid size %d", datasize); -			} -			switch (filetype) { -			case sleByte: -				saveByte((byte)data); -				break; -			case sleUint16: -			case sleInt16: -				saveWord((int16)data); -				break; -			case sleInt32: -			case sleUint32: -				saveUint32(data); -				break; -			default: -				error("saveLoadArrayOf: invalid filetype %d", filetype); -			} +		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 { -			/* loading */ -			switch (filetype) { -			case sleByte: -				data = loadByte(); -				break; -			case sleUint16: -				data = loadWord(); -				break; -			case sleInt16: -				data = (int16)loadWord(); -				break; -			case sleUint32: -				data = loadUint32(); -				break; -			case sleInt32: -				data = (int32)loadUint32(); -				break; -			default: -				error("saveLoadArrayOf: invalid filetype %d", filetype); -			} -			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("saveLoadArrayOf: invalid size %d", datasize); -			} +			error("saveLoadArrayOf: invalid size %d", datasize); +		} +		switch (filetype) { +		case sleByte: +			saveByte((byte)data); +			break; +		case sleUint16: +		case sleInt16: +			saveWord((int16)data); +			break; +		case sleInt32: +		case sleUint32: +			saveUint32(data); +			break; +		default: +			error("saveLoadArrayOf: 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 = loadWord(); +			break; +		case sleInt16: +			data = (int16)loadWord(); +			break; +		case sleUint32: +			data = loadUint32(); +			break; +		case sleInt32: +			data = (int32)loadUint32(); +			break; +		default: +			error("saveLoadArrayOf: 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("saveLoadArrayOf: invalid size %d", datasize);  		}  	}  } @@ -908,45 +815,99 @@ void Serializer::saveLoadArrayOf(void *b, int num, int datasize, const SaveLoadE  {  	byte *data = (byte *)b; -	while (--num >= 0) { -		saveLoadEntries(data, sle); -		data += datasize; +	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)  { -	int replen; +	if (isSaving()) +		saveEntries(d, sle); +	else +		loadEntries(d, sle); +} + +void Serializer::saveEntries(void *d, const SaveLoadEntry *sle) +{  	byte type;  	byte *at;  	int size; -	int num; -	void *ptr;  	while (sle->offs != 0xFFFF) {  		at = (byte *)d + sle->offs;  		size = sle->size;  		type = sle->type; -		if (size == 0xFF) { -			if (isSaving()) { -				/* save reference */ -				ptr = *((void **)at); -				saveWord(ptr ? ((*_save_ref) (_ref_me, type, ptr) + 1) : 0); -			} else { -				/* load reference */ -				num = loadWord(); -				*((void **)at) = num ? (*_load_ref) (_ref_me, type, num - 1) : NULL; +		if (sle->maxVersion != CURRENT_VER) { +			// Skip obsolete entries +			if (type & 128) +				sle++; +		} else if (size == 0xFF) { +			// save reference +			void *ptr = *((void **)at); +			saveWord(ptr ? ((*_save_ref) (_ref_me, type, ptr) + 1) : 0); +		} else { +			// save entry +			int replen = 1; +			if (type & 128) { +				sle++; +				replen = sle->offs; +				type &= ~128;  			} +			saveArrayOf(at, replen, size, type); +		} +		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 = 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 if (size == 0xFF) { +			// load reference... +			int num = loadWord(); +			// ...but only use it if it's still there in CURRENT_VER +			if (sle->maxVersion == CURRENT_VER) +				*((void **)at) = num ? (*_load_ref) (_ref_me, type, num - 1) : NULL;  		} else { -			replen = 1; +			// load entry +			int replen = 1; +  			if (type & 128) {  				sle++;  				replen = sle->offs;  				type &= ~128;  			} -			saveLoadArrayOf(at, replen, size, type); +			loadArrayOf(at, replen, size, type);  		}  		sle++;  	} | 
