From 4ddecdad589e9df3db4a5a12fb9cdb874ae1d00b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sun, 8 Dec 2002 16:14:29 +0000 Subject: Patch #650085: Make saveload system extensible svn-id: r5885 --- scumm/actor.h | 1 - scumm/imuse.cpp | 153 ++++----- scumm/saveload.cpp | 929 +++++++++++++++++++++++++---------------------------- scumm/saveload.h | 79 +++-- scumm/scumm.h | 6 +- 5 files changed, 586 insertions(+), 582 deletions(-) (limited to 'scumm') diff --git a/scumm/actor.h b/scumm/actor.h index 3bb5188a8d..2ebfaf02c7 100644 --- a/scumm/actor.h +++ b/scumm/actor.h @@ -101,7 +101,6 @@ public: byte frame; byte walkbox; - byte mask; // FIXME: This field is *NOT* used - remove next time save game format changes byte animProgress, animSpeed; int16 new_1, new_2; uint16 talk_script, walk_script; diff --git a/scumm/imuse.cpp b/scumm/imuse.cpp index 30af7deee7..d46cfe336d 100644 --- a/scumm/imuse.cpp +++ b/scumm/imuse.cpp @@ -455,8 +455,8 @@ private: void fix_parts_after_load(); void fix_players_after_load(Scumm *scumm); - static int saveReference(IMuseInternal *me, byte type, void *ref); - static void *loadReference(IMuseInternal *me, byte type, int ref); + static int saveReference(void *me_ref, byte type, void *ref); + static void *loadReference(void *me_ref, byte type, int ref); void lock(); void unlock(); @@ -3143,8 +3143,9 @@ enum { TYPE_PLAYER = 2, }; -int IMuseInternal::saveReference(IMuseInternal *me, byte type, void *ref) +int IMuseInternal::saveReference(void *me_ref, byte type, void *ref) { + IMuseInternal *me = (IMuseInternal *)me_ref; switch (type) { case TYPE_PART: return (Part *)ref - me->_parts; @@ -3155,8 +3156,9 @@ int IMuseInternal::saveReference(IMuseInternal *me, byte type, void *ref) } } -void *IMuseInternal::loadReference(IMuseInternal *me, byte type, int ref) +void *IMuseInternal::loadReference(void *me_ref, byte type, int ref) { + IMuseInternal *me = (IMuseInternal *)me_ref; switch (type) { case TYPE_PART: return &me->_parts[ref]; @@ -3170,88 +3172,88 @@ void *IMuseInternal::loadReference(IMuseInternal *me, byte type, int ref) int IMuseInternal::save_or_load(Serializer *ser, Scumm *scumm) { const SaveLoadEntry mainEntries[] = { - MKLINE(IMuseInternal, _queue_end, sleUint8), - MKLINE(IMuseInternal, _queue_pos, sleUint8), - MKLINE(IMuseInternal, _queue_sound, sleUint16), - MKLINE(IMuseInternal, _queue_adding, sleByte), - MKLINE(IMuseInternal, _queue_marker, sleByte), - MKLINE(IMuseInternal, _queue_cleared, sleByte), - MKLINE(IMuseInternal, _master_volume, sleByte), - MKLINE(IMuseInternal, _trigger_count, sleUint16), - MKARRAY(IMuseInternal, _channel_volume[0], sleUint16, 8), - MKARRAY(IMuseInternal, _volchan_table[0], sleUint16, 8), + MKLINE(IMuseInternal, _queue_end, sleUint8, VER_V8), + MKLINE(IMuseInternal, _queue_pos, sleUint8, VER_V8), + MKLINE(IMuseInternal, _queue_sound, sleUint16, VER_V8), + MKLINE(IMuseInternal, _queue_adding, sleByte, VER_V8), + MKLINE(IMuseInternal, _queue_marker, sleByte, VER_V8), + MKLINE(IMuseInternal, _queue_cleared, sleByte, VER_V8), + MKLINE(IMuseInternal, _master_volume, sleByte, VER_V8), + MKLINE(IMuseInternal, _trigger_count, sleUint16, VER_V8), + MKARRAY(IMuseInternal, _channel_volume[0], sleUint16, 8, VER_V8), + MKARRAY(IMuseInternal, _volchan_table[0], sleUint16, 8, VER_V8), MKEND() }; const SaveLoadEntry playerEntries[] = { - MKREF(Player, _parts, TYPE_PART), - MKLINE(Player, _active, sleByte), - MKLINE(Player, _id, sleUint16), - MKLINE(Player, _priority, sleByte), - MKLINE(Player, _volume, sleByte), - MKLINE(Player, _pan, sleInt8), - MKLINE(Player, _transpose, sleByte), - MKLINE(Player, _detune, sleInt8), - MKLINE(Player, _vol_chan, sleUint16), - MKLINE(Player, _vol_eff, sleByte), - MKLINE(Player, _speed, sleByte), - MKLINE(Player, _song_index, sleUint16), - MKLINE(Player, _track_index, sleUint16), - MKLINE(Player, _timer_counter, sleUint16), - MKLINE(Player, _loop_to_beat, sleUint16), - MKLINE(Player, _loop_from_beat, sleUint16), - MKLINE(Player, _loop_counter, sleUint16), - MKLINE(Player, _loop_to_tick, sleUint16), - MKLINE(Player, _loop_from_tick, sleUint16), - MKLINE(Player, _tempo, sleUint32), - MKLINE(Player, _cur_pos, sleUint32), - MKLINE(Player, _next_pos, sleUint32), - MKLINE(Player, _song_offset, sleUint32), - MKLINE(Player, _tick_index, sleUint16), - MKLINE(Player, _beat_index, sleUint16), - MKLINE(Player, _ticks_per_beat, sleUint16), - MKLINE(Player, _hook._jump, sleByte), - MKLINE(Player, _hook._transpose, sleByte), - MKARRAY(Player, _hook._part_onoff[0], sleByte, 16), - MKARRAY(Player, _hook._part_volume[0], sleByte, 16), - MKARRAY(Player, _hook._part_program[0], sleByte, 16), - MKARRAY(Player, _hook._part_transpose[0], sleByte, 16), + MKREF(Player, _parts, TYPE_PART, VER_V8), + MKLINE(Player, _active, sleByte, VER_V8), + MKLINE(Player, _id, sleUint16, VER_V8), + MKLINE(Player, _priority, sleByte, VER_V8), + MKLINE(Player, _volume, sleByte, VER_V8), + MKLINE(Player, _pan, sleInt8, VER_V8), + MKLINE(Player, _transpose, sleByte, VER_V8), + MKLINE(Player, _detune, sleInt8, VER_V8), + MKLINE(Player, _vol_chan, sleUint16, VER_V8), + MKLINE(Player, _vol_eff, sleByte, VER_V8), + MKLINE(Player, _speed, sleByte, VER_V8), + MKLINE(Player, _song_index, sleUint16, VER_V8), + MKLINE(Player, _track_index, sleUint16, VER_V8), + MKLINE(Player, _timer_counter, sleUint16, VER_V8), + MKLINE(Player, _loop_to_beat, sleUint16, VER_V8), + MKLINE(Player, _loop_from_beat, sleUint16, VER_V8), + MKLINE(Player, _loop_counter, sleUint16, VER_V8), + MKLINE(Player, _loop_to_tick, sleUint16, VER_V8), + MKLINE(Player, _loop_from_tick, sleUint16, VER_V8), + MKLINE(Player, _tempo, sleUint32, VER_V8), + MKLINE(Player, _cur_pos, sleUint32, VER_V8), + MKLINE(Player, _next_pos, sleUint32, VER_V8), + MKLINE(Player, _song_offset, sleUint32, VER_V8), + MKLINE(Player, _tick_index, sleUint16, VER_V8), + MKLINE(Player, _beat_index, sleUint16, VER_V8), + MKLINE(Player, _ticks_per_beat, sleUint16, VER_V8), + MKLINE(Player, _hook._jump, sleByte, VER_V8), + MKLINE(Player, _hook._transpose, sleByte, VER_V8), + MKARRAY(Player, _hook._part_onoff[0], sleByte, 16, VER_V8), + MKARRAY(Player, _hook._part_volume[0], sleByte, 16, VER_V8), + MKARRAY(Player, _hook._part_program[0], sleByte, 16, VER_V8), + MKARRAY(Player, _hook._part_transpose[0], sleByte, 16, VER_V8), MKEND() }; const SaveLoadEntry volumeFaderEntries[] = { - MKREF(VolumeFader, player, TYPE_PLAYER), - MKLINE(VolumeFader, active, sleUint8), - MKLINE(VolumeFader, curvol, sleUint8), - MKLINE(VolumeFader, speed_lo_max, sleUint16), - MKLINE(VolumeFader, num_steps, sleUint16), - MKLINE(VolumeFader, speed_hi, sleInt8), - MKLINE(VolumeFader, direction, sleInt8), - MKLINE(VolumeFader, speed_lo, sleInt8), - MKLINE(VolumeFader, speed_lo_counter, sleUint16), + MKREF(VolumeFader, player, TYPE_PLAYER, VER_V8), + MKLINE(VolumeFader, active, sleUint8, VER_V8), + MKLINE(VolumeFader, curvol, sleUint8, VER_V8), + MKLINE(VolumeFader, speed_lo_max, sleUint16, VER_V8), + MKLINE(VolumeFader, num_steps, sleUint16, VER_V8), + MKLINE(VolumeFader, speed_hi, sleInt8, VER_V8), + MKLINE(VolumeFader, direction, sleInt8, VER_V8), + MKLINE(VolumeFader, speed_lo, sleInt8, VER_V8), + MKLINE(VolumeFader, speed_lo_counter, sleUint16, VER_V8), MKEND() }; const SaveLoadEntry partEntries[] = { - MKREF(Part, _next, TYPE_PART), - MKREF(Part, _prev, TYPE_PART), - MKREF(Part, _player, TYPE_PLAYER), - MKLINE(Part, _pitchbend, sleInt16), - MKLINE(Part, _pitchbend_factor, sleUint8), - MKLINE(Part, _transpose, sleInt8), - MKLINE(Part, _vol, sleUint8), - MKLINE(Part, _detune, sleInt8), - MKLINE(Part, _pan, sleInt8), - MKLINE(Part, _on, sleUint8), - MKLINE(Part, _modwheel, sleUint8), - MKLINE(Part, _pedal, sleUint8), - MKLINE(Part, _program, sleUint8), - MKLINE(Part, _pri, sleUint8), - MKLINE(Part, _chan, sleUint8), - MKLINE(Part, _effect_level, sleUint8), - MKLINE(Part, _chorus, sleUint8), - MKLINE(Part, _percussion, sleUint8), - MKLINE(Part, _bank, sleUint8), + MKREF(Part, _next, TYPE_PART, VER_V8), + MKREF(Part, _prev, TYPE_PART, VER_V8), + MKREF(Part, _player, TYPE_PLAYER, VER_V8), + MKLINE(Part, _pitchbend, sleInt16, VER_V8), + MKLINE(Part, _pitchbend_factor, sleUint8, VER_V8), + MKLINE(Part, _transpose, sleInt8, VER_V8), + MKLINE(Part, _vol, sleUint8, VER_V8), + MKLINE(Part, _detune, sleInt8, VER_V8), + MKLINE(Part, _pan, sleInt8, VER_V8), + MKLINE(Part, _on, sleUint8, VER_V8), + MKLINE(Part, _modwheel, sleUint8, VER_V8), + MKLINE(Part, _pedal, sleUint8, VER_V8), + MKLINE(Part, _program, sleUint8, VER_V8), + MKLINE(Part, _pri, sleUint8, VER_V8), + MKLINE(Part, _chan, sleUint8, VER_V8), + MKLINE(Part, _effect_level, sleUint8, VER_V8), + MKLINE(Part, _chorus, sleUint8, VER_V8), + MKLINE(Part, _percussion, sleUint8, VER_V8), + MKLINE(Part, _bank, sleUint8, VER_V8), MKEND() }; @@ -3261,7 +3263,8 @@ int IMuseInternal::save_or_load(Serializer *ser, Scumm *scumm) #endif ser->_ref_me = this; - ser->_saveload_ref = ser->isSaving()? ((void *)&saveReference) : ((void *)&loadReference); + ser->_save_ref = saveReference; + ser->_load_ref = loadReference; ser->saveLoadEntries(this, mainEntries); ser->saveLoadArrayOf(_players, ARRAYSIZE(_players), sizeof(_players[0]), playerEntries); 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++; } diff --git a/scumm/saveload.h b/scumm/saveload.h index 914d6b9346..1667aeb045 100644 --- a/scumm/saveload.h +++ b/scumm/saveload.h @@ -22,6 +22,17 @@ #ifndef SAVELOAD_H #define SAVELOAD_H +// Support for "old" savegames (made with 2501 CVS build) +// Can be useful for other ports too :) + +#define VER_V10 10 +#define VER_V9 9 +#define VER_V8 8 +#define VER_V7 7 + +#define CURRENT_VER VER_V10 + + // 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 hae a heuristic built in to detect "offset-of" patterns - which is exactly @@ -32,11 +43,29 @@ #define OFFS(type,item) (((int)(&((type*)42)->type::item))-42) #define SIZE(type,item) sizeof(((type*)42)->type::item) -#define MKLINE(type,item,saveas) {OFFS(type,item),saveas,SIZE(type,item)} -#define MKARRAY(type,item,saveas,num) {OFFS(type,item),128|saveas,SIZE(type,item)}, {num,0,0} -#define MKEND() {0xFFFF,0xFF,0xFF} -#define MKREF(type,item,refid) {OFFS(type,item),refid,0xFF} +// 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,num,minVer) {OFFS(type,item),128|saveas,SIZE(type,item),minVer,CURRENT_VER}, {num,0,0,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,num,minVer,maxVer) {OFFS(type,item),128|saveas,SIZE(type,item),minVer,maxVer}, {num,0,0,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,num,minVer,maxVer) {0,128|saveas,0,minVer,maxVer}, {num,0,0,0,0} + +// End marker +#define MKEND() {0xFFFF,0xFF,0xFF,0,0} + +// A reference +#define MKREF(type,item,refid,minVer) {OFFS(type,item),refid,0xFF,minVer,CURRENT_VER} + +// An obsolete reference. +#define MK_OBSOLETE_REF(type,item,refid,minVer,maxVer) {0,sleUint16,0,minVer,maxVer} + enum { sleByte = 1, @@ -52,6 +81,8 @@ struct SaveLoadEntry { uint32 offs; uint8 type; uint8 size; + uint8 minVersion; + uint8 maxVersion; }; struct SerializerStream { @@ -83,24 +114,25 @@ struct SerializerStream { typedef int SerializerSaveReference(void *me, byte type, void *ref); typedef void *SerializerLoadReference(void *me, byte type, int ref); -struct Serializer { - SerializerStream _saveLoadStream; +class Serializer { +public: + Serializer(SerializerStream stream, bool saveOrLoad, uint32 savegameVersion) + : _save_ref(0), _load_ref(0), _ref_me(0), + _saveLoadStream(stream), _saveOrLoad(saveOrLoad), + _savegameVersion(savegameVersion) + { } - union { - SerializerSaveReference *_save_ref; - SerializerLoadReference *_load_ref; - void *_saveload_ref; - }; + SerializerSaveReference *_save_ref; + SerializerLoadReference *_load_ref; void *_ref_me; - bool _saveOrLoad; - - void saveBytes(void *b, int len); - void loadBytes(void *b, int len); - void saveLoadArrayOf(void *b, int len, int datasize, byte filetype); - void saveLoadEntries(void *d, const SaveLoadEntry *sle); void saveLoadArrayOf(void *b, int num, int datasize, const SaveLoadEntry *sle); + void saveLoadEntries(void *d, const SaveLoadEntry *sle); + + bool isSaving() { return _saveOrLoad; } + + bool checkEOFLoadStream(); void saveUint32(uint32 d); void saveWord(uint16 d); @@ -110,10 +142,19 @@ struct Serializer { uint16 loadWord(); uint32 loadUint32(); - bool isSaving() { return _saveOrLoad; } + void saveBytes(void *b, int len); + void loadBytes(void *b, int len); + +protected: + SerializerStream _saveLoadStream; + bool _saveOrLoad; + uint32 _savegameVersion; - bool checkEOFLoadStream(); + 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); }; #endif diff --git a/scumm/scumm.h b/scumm/scumm.h index d4341959f0..0a1ca45f14 100644 --- a/scumm/scumm.h +++ b/scumm/scumm.h @@ -359,7 +359,6 @@ public: void convertKeysToClicks(); /* Random number generation */ - uint32 _randSeed1, _randSeed2; // FIXME: can be removed when new savegame system is implemented RandomSource _rnd; /* Core variable definitions */ @@ -427,6 +426,8 @@ public: bool _saveLoadCompatible; char _saveLoadName[32]; + uint32 _savegameVersion; + bool saveState(int slot, bool compat); bool loadState(int slot, bool compat); void saveOrLoad(Serializer *s); @@ -692,7 +693,7 @@ public: ColorCycle _colorCycle[16]; // Palette cycles uint32 _ENCD_offs, _EXCD_offs; - uint32 _CLUT_offs, _EPAL_offs; + uint32 _CLUT_offs; uint32 _IM00_offs, _PALS_offs; //ender: fullscreen @@ -856,7 +857,6 @@ public: bool _silentDigitalImuse; int _saveSound; int current_cd_sound; - int _cd_loops, _cd_frame, _cd_track, _cd_end; // FIXME - these are not used anymore /* Walkbox / Navigation class */ int _maxBoxVertexHeap, _boxPathVertexHeapIndex, _boxMatrixItem; -- cgit v1.2.3