protected virtual void SaveOrLoad(Serializer serializer)
{
uint ENCD_offs = 0;
uint EXCD_offs = 0;
uint IM00_offs = 0;
uint CLUT_offs = 0;
uint EPAL_offs = 0;
uint PALS_offs = 0;
byte numObjectsInRoom = (byte)_objs.Length;
#region MainEntries
var mainEntries = new[]
{
LoadAndSaveEntry.Create(reader => _gameMD5 = reader.ReadBytes(16), writer => writer.Write(_gameMD5), 39),
LoadAndSaveEntry.Create(reader => reader.ReadUInt16(), writer => writer.Write(roomData.Header.Width), 8, 50),
LoadAndSaveEntry.Create(reader => reader.ReadUInt16(), writer => writer.Write(roomData.Header.Height), 8, 50),
LoadAndSaveEntry.Create(reader => ENCD_offs = reader.ReadUInt32(), writer => writer.Write(ENCD_offs), 8, 50),
LoadAndSaveEntry.Create(reader => EXCD_offs = reader.ReadUInt32(), writer => writer.Write(EXCD_offs), 8, 50),
LoadAndSaveEntry.Create(reader => IM00_offs = reader.ReadUInt32(), writer => writer.Write(IM00_offs), 8, 50),
LoadAndSaveEntry.Create(reader => CLUT_offs = reader.ReadUInt32(), writer => writer.Write(CLUT_offs), 8, 50),
LoadAndSaveEntry.Create(reader => EPAL_offs = reader.ReadUInt32(), writer => writer.Write(EPAL_offs), 8, 9),
LoadAndSaveEntry.Create(reader => PALS_offs = reader.ReadUInt32(), writer => writer.Write(PALS_offs), 8, 50),
LoadAndSaveEntry.Create(reader => _curPalIndex = reader.ReadByte(), writer => writer.WriteByte(_curPalIndex), 8),
LoadAndSaveEntry.Create(reader => _currentRoom = reader.ReadByte(), writer => writer.Write(_currentRoom), 8),
LoadAndSaveEntry.Create(reader => _roomResource = reader.ReadByte(), writer => writer.Write(_roomResource), 8),
LoadAndSaveEntry.Create(reader => numObjectsInRoom = reader.ReadByte(), writer => writer.Write(numObjectsInRoom), 8),
LoadAndSaveEntry.Create(reader => CurrentScript = reader.ReadByte(), writer => writer.Write(CurrentScript), 8),
LoadAndSaveEntry.Create(reader => reader.ReadUInt32s(NumLocalScripts), writer => writer.Write(new uint[NumLocalScripts], NumLocalScripts), 8, 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.
LoadAndSaveEntry.Create(reader =>
{
for (int i = 0; i < 25; i++)
{
_slots[i].InitializeLocals(reader.ReadUInt16s(17));
}
}, writer =>
{
for (int i = 0; i < 25; i++)
{
writer.WriteUInt16s(_slots[i].LocalVariables.Cast<ushort>().ToArray(), 17);
}
}, 8, 8),
LoadAndSaveEntry.Create(reader =>
{
for (int i = 0; i < 40; i++)
{
_slots[i].InitializeLocals(reader.ReadUInt16s(17));
}
}, writer =>
{
for (int i = 0; i < 40; i++)
{
writer.WriteUInt16s(_slots[i].LocalVariables.Cast<ushort>().ToArray(), 17);
}
}, 9, 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.
LoadAndSaveEntry.Create(reader =>
{
for (int i = 0; i < 38; i++)
{
_slots[i].InitializeLocals(reader.ReadUInt16s(26));
}
}, writer =>
{
for (int i = 0; i < 38; i++)
{
writer.WriteUInt16s(_slots[i].LocalVariables.Cast<ushort>().ToArray(), 26);
}
}, 15, 17),
// TODO
//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
LoadAndSaveEntry.Create(reader =>
{
for (int i = 0; i < 40; i++)
{
_slots[i].InitializeLocals(reader.ReadInt32s(26));
}
}, writer =>
{
for (int i = 0; i < 40; i++)
{
writer.WriteInt32s(_slots[i].LocalVariables, 26);
}
}, 18, 19),
// Then we doubled the script slots again, from 40 to 80
LoadAndSaveEntry.Create(reader =>
{
for (int i = 0; i < NumScriptSlot; i++)
{
_slots[i].InitializeLocals(reader.ReadInt32s(26));
}
}, writer =>
{
for (int i = 0; i < NumScriptSlot; i++)
{
writer.WriteInt32s(_slots[i].LocalVariables, 26);
}
}, 20),
LoadAndSaveEntry.Create(reader => _resourceMapper = reader.ReadBytes(128), writer => writer.Write(_resourceMapper), 8),
LoadAndSaveEntry.Create(reader => CharsetColorMap = reader.ReadBytes(16), writer => writer.Write(CharsetColorMap), 8),
// _charsetData grew from 10*16, to 15*16, to 23*16 bytes
LoadAndSaveEntry.Create(reader => reader.ReadMatrixBytes(10, 16), writer => writer.WriteMatrixBytes(new byte[16, 10], 10, 16), 8, 9),
LoadAndSaveEntry.Create(reader => reader.ReadMatrixBytes(15, 16), writer => writer.WriteMatrixBytes(new byte[16, 15], 15, 16), 10, 66),
LoadAndSaveEntry.Create(reader => reader.ReadMatrixBytes(23, 16), writer => writer.WriteMatrixBytes(new byte[16, 23], 23, 16), 67),
LoadAndSaveEntry.Create(reader => reader.ReadUInt16(), writer => writer.WriteUInt16(0), 8, 62),
LoadAndSaveEntry.Create(reader => _camera.DestinationPosition.X = reader.ReadInt16(), writer => writer.WriteInt16(_camera.DestinationPosition.X), 8),
LoadAndSaveEntry.Create(reader => _camera.DestinationPosition.Y = reader.ReadInt16(), writer => writer.WriteInt16(_camera.DestinationPosition.Y), 8),
LoadAndSaveEntry.Create(reader => _camera.CurrentPosition.X = reader.ReadInt16(), writer => writer.WriteInt16(_camera.CurrentPosition.X), 8),
LoadAndSaveEntry.Create(reader => _camera.CurrentPosition.Y = reader.ReadInt16(), writer => writer.WriteInt16(_camera.CurrentPosition.Y), 8),
LoadAndSaveEntry.Create(reader => _camera.LastPosition.X = reader.ReadInt16(), writer => writer.WriteInt16(_camera.LastPosition.X), 8),
LoadAndSaveEntry.Create(reader => _camera.LastPosition.Y = reader.ReadInt16(), writer => writer.WriteInt16(_camera.LastPosition.Y), 8),
LoadAndSaveEntry.Create(reader => _camera.Accel.X = reader.ReadInt16(), writer => writer.WriteInt16(_camera.Accel.X), 8),
LoadAndSaveEntry.Create(reader => _camera.Accel.Y = reader.ReadInt16(), writer => writer.WriteInt16(_camera.Accel.Y), 8),
LoadAndSaveEntry.Create(reader => _screenStartStrip = reader.ReadInt16(), writer => writer.WriteInt16(_screenStartStrip), 8),
LoadAndSaveEntry.Create(reader => _screenEndStrip = reader.ReadInt16(), writer => writer.WriteInt16(_screenEndStrip), 8),
LoadAndSaveEntry.Create(reader => _camera.Mode = (CameraMode)reader.ReadByte(), writer => writer.Write((byte)_camera.Mode), 8),
LoadAndSaveEntry.Create(reader => _camera.ActorToFollow = reader.ReadByte(), writer => writer.Write(_camera.ActorToFollow), 8),
LoadAndSaveEntry.Create(reader => _camera.LeftTrigger = reader.ReadInt16(), writer => writer.WriteInt16(_camera.LeftTrigger), 8),
LoadAndSaveEntry.Create(reader => _camera.RightTrigger = reader.ReadInt16(), writer => writer.WriteInt16(_camera.RightTrigger), 8),
LoadAndSaveEntry.Create(reader => _camera.MovingToActor = reader.ReadUInt16() != 0, writer => writer.WriteUInt16(_camera.MovingToActor), 8),
LoadAndSaveEntry.Create(reader => _actorToPrintStrFor = reader.ReadByte(), writer => writer.WriteByte(_actorToPrintStrFor), 8),
LoadAndSaveEntry.Create(reader => _charsetColor = reader.ReadByte(), writer => writer.WriteByte(_charsetColor), 8),
// _charsetBufPos was changed from byte to int
LoadAndSaveEntry.Create(reader => _charsetBufPos = reader.ReadByte(), writer => writer.WriteByte(_charsetBufPos), 8, 9),
LoadAndSaveEntry.Create(reader => _charsetBufPos = reader.ReadInt16(), writer => writer.WriteInt16(_charsetBufPos), 10),
LoadAndSaveEntry.Create(reader => _haveMsg = reader.ReadByte(), writer => writer.WriteByte(_haveMsg), 8),
LoadAndSaveEntry.Create(reader => _haveActorSpeechMsg = reader.ReadByte() != 0, writer => writer.WriteByte(_haveActorSpeechMsg), 61),
LoadAndSaveEntry.Create(reader => _useTalkAnims = reader.ReadByte() != 0, writer => writer.WriteByte(_useTalkAnims), 8),
LoadAndSaveEntry.Create(reader => _talkDelay = reader.ReadInt16(), writer => writer.WriteInt16(_talkDelay), 8),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 8),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 8, 27),
LoadAndSaveEntry.Create(reader => SentenceNum = reader.ReadByte(), writer => writer.WriteByte(SentenceNum), 8),
LoadAndSaveEntry.Create(reader => cutScene.SaveOrLoad(serializer), writer => cutScene.SaveOrLoad(serializer), 8),
LoadAndSaveEntry.Create(reader => _numNestedScripts = reader.ReadByte(), writer => writer.WriteByte(_numNestedScripts), 8),
LoadAndSaveEntry.Create(reader => _userPut = (sbyte)reader.ReadByte(), writer => writer.WriteByte(_userPut), 8),
LoadAndSaveEntry.Create(reader => reader.ReadUInt16(), writer => writer.WriteUInt16(0), 17),
LoadAndSaveEntry.Create(reader => _cursor.State = (sbyte)reader.ReadByte(), writer => writer.WriteByte(_cursor.State), 8),
LoadAndSaveEntry.Create(reader => reader.ReadByte(), writer => writer.WriteByte(0), 8, 20),
LoadAndSaveEntry.Create(reader => _currentCursor = reader.ReadByte(), writer => writer.WriteByte(_currentCursor), 8),
LoadAndSaveEntry.Create(reader => _cursorData = reader.ReadBytes(8192), writer =>
{
var data = new byte[8192];
if (_cursorData != null)
{
Array.Copy(_cursorData, data, _cursorData.Length);
}
writer.Write(data);
}, 20),
LoadAndSaveEntry.Create(reader => _cursor.Width = reader.ReadInt16(), writer => writer.WriteInt16(_cursor.Width), 20),
LoadAndSaveEntry.Create(reader => _cursor.Height = reader.ReadInt16(), writer => writer.WriteInt16(_cursor.Height), 20),
LoadAndSaveEntry.Create(reader => _cursor.Hotspot = new Point(reader.ReadInt16(), reader.ReadInt16()), writer =>
{
writer.WriteInt16(_cursor.Hotspot.X);
writer.WriteInt16(_cursor.Hotspot.Y);
}, 20),
LoadAndSaveEntry.Create(reader => _cursor.Animate = reader.ReadByte() != 0, writer => writer.WriteByte(_cursor.Animate), 20),
LoadAndSaveEntry.Create(reader => _cursor.AnimateIndex = reader.ReadByte(), writer => writer.WriteByte(_cursor.AnimateIndex), 20),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 20),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 20),
LoadAndSaveEntry.Create(reader => reader.ReadBytes(256), writer => writer.Write(new byte[256]), 60),
LoadAndSaveEntry.Create(reader => _doEffect = reader.ReadByte() != 0, writer => writer.WriteByte(_doEffect), 8),
LoadAndSaveEntry.Create(reader => _switchRoomEffect = reader.ReadByte(), writer => writer.WriteByte(_switchRoomEffect), 8),
LoadAndSaveEntry.Create(reader => _newEffect = reader.ReadByte(), writer => writer.WriteByte(_newEffect), 8),
LoadAndSaveEntry.Create(reader => _switchRoomEffect2 = reader.ReadByte(), writer => writer.WriteByte(_switchRoomEffect2), 8),
LoadAndSaveEntry.Create(reader => _bgNeedsRedraw = reader.ReadByte() != 0, writer => writer.WriteByte(_bgNeedsRedraw), 8),
// The state of palManipulate is stored only since V10
LoadAndSaveEntry.Create(reader => _palManipStart = reader.ReadByte(), writer => writer.WriteByte(_palManipStart), 10),
LoadAndSaveEntry.Create(reader => _palManipEnd = reader.ReadByte(), writer => writer.WriteByte(_palManipEnd), 10),
LoadAndSaveEntry.Create(reader => _palManipCounter = reader.ReadUInt16(), writer => writer.WriteUInt16(_palManipCounter), 10),
// gfxUsageBits grew from 200 to 410 entries. Then 3 * 410 entries:
LoadAndSaveEntry.Create(reader => Gdi.SaveOrLoad(serializer), writer => Gdi.SaveOrLoad(serializer), 0),
LoadAndSaveEntry.Create(reader => Gdi.TransparentColor = reader.ReadByte(), writer => writer.WriteByte(Gdi.TransparentColor), 8, 50),
LoadAndSaveEntry.Create(reader =>
{
for (int i = 0; i < 256; i++)
{
_currentPalette.Colors[i] = Color.FromRgb(reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
}
}, writer =>
{
for (int i = 0; i < 256; i++)
{
var l_color = _currentPalette.Colors[i];
writer.WriteByte(l_color.R);
writer.WriteByte(l_color.G);
writer.WriteByte(l_color.B);
}
}, 8),
LoadAndSaveEntry.Create(reader => reader.ReadBytes(768), writer => writer.Write(new byte[768]), 53),
// Sam & Max specific palette replaced by _shadowPalette now.
LoadAndSaveEntry.Create(reader => reader.ReadBytes(256), writer => writer.Write(new byte[256]), 8, 33),
LoadAndSaveEntry.Create(reader => _charsetBuffer = reader.ReadBytes(256), writer => writer.WriteBytes(_charsetBuffer, 256), 8),
LoadAndSaveEntry.Create(reader => EgoPositioned = reader.ReadByte() != 0, writer => writer.WriteByte(EgoPositioned), 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.
LoadAndSaveEntry.Create(reader => reader.ReadUInt16s(4), writer => writer.WriteUInt16s(new ushort[4], 4), 8, 9),
LoadAndSaveEntry.Create(reader => reader.ReadUInt16s(5), writer => writer.WriteUInt16s(new ushort[5], 5), 10, 26),
// See _imgBufOffs: _numZBuffer is recomputed by initBGBuffers().
LoadAndSaveEntry.Create(reader => Gdi.NumZBuffer = reader.ReadByte(), writer => writer.WriteByte(Gdi.NumZBuffer), 8, 26),
LoadAndSaveEntry.Create(reader => _screenEffectFlag = reader.ReadByte() != 0, writer => writer.WriteByte(_screenEffectFlag), 8),
LoadAndSaveEntry.Create(reader => reader.ReadByte(), writer => writer.WriteByte(0), 8, 9),
LoadAndSaveEntry.Create(reader => reader.ReadByte(), writer => writer.WriteByte(0), 8, 9),
// Converted _shakeEnabled to boolean and added a _shakeFrame field.
LoadAndSaveEntry.Create(reader => _shakeEnabled = reader.ReadInt16() == 1, writer => writer.WriteInt16(_shakeEnabled ? 1 : 0), 8, 9),
LoadAndSaveEntry.Create(reader => _shakeEnabled = reader.ReadBoolean(), writer => writer.WriteByte(_shakeEnabled), 10),
LoadAndSaveEntry.Create(reader => _shakeFrame = (int)reader.ReadUInt32(), writer => writer.WriteUInt32((uint)_shakeFrame), 10),
LoadAndSaveEntry.Create(reader => _keepText = reader.ReadByte() != 0, writer => writer.WriteByte(_keepText), 8),
LoadAndSaveEntry.Create(reader => _screenB = reader.ReadUInt16(), writer => writer.WriteUInt16(_screenB), 8),
LoadAndSaveEntry.Create(reader => _screenH = reader.ReadUInt16(), writer => writer.WriteUInt16(_screenH), 8),
LoadAndSaveEntry.Create(reader => reader.ReadUInt16(), writer => writer.WriteUInt16(0), 47),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 9, 9),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 9, 9),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 9, 9),
LoadAndSaveEntry.Create(reader => reader.ReadInt16(), writer => writer.WriteInt16(0), 9, 9)
};
#endregion MainEntries
var md5Backup = new byte[16];
Array.Copy(_gameMD5, md5Backup, 16);
for (int i = 0; i < mainEntries.Length; i++)
{
mainEntries[i].Execute(serializer);
}
if (serializer.IsLoading)
{
roomData = _resManager.GetRoom(_roomResource);
}
//if (!Array.Equals(md5Backup, _gameMD5))
//{
// //warning("Game was saved with different gamedata - you may encounter problems");
// //debug(1, "You have %s and save is %s.", md5str2, md5str1);
// return false;
//}
// Starting V14, we extended the usage bits, to be able to cope with games
// 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 (serializer.IsLoading && serializer.Version < 14)
// Gdi.UpgradeGfxUsageBits();
// When loading, move the mouse to the saved mouse position.
//if (serializer.Version >= 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 (serializer.IsLoading && serializer.Version < 61)
{
if (_haveMsg == 0xFE)
{
_haveActorSpeechMsg = false;
_haveMsg = 0xFF;
}
else
{
_haveActorSpeechMsg = true;
}
}
//
// Save/load actors
//
for (int i = 0; i < Actors.Length; i++)
{
Actors[i].SaveOrLoad(serializer);
}
//
// Save/load sound data
//
Sound.SaveOrLoad(serializer);
//
// Save/load script data
//
if (serializer.Version < 9)
{
for (int i = 0; i < 25; i++)
{
_slots[i].SaveOrLoad(serializer, roomData.LocalScripts, ResourceManager.NumGlobalScripts);
}
}
else if (serializer.Version < 20)
{
for (int i = 0; i < 40; i++)
{
_slots[i].SaveOrLoad(serializer, roomData.LocalScripts, ResourceManager.NumGlobalScripts);
}
}
else
{
for (int i = 0; i < NumScriptSlot; i++)
{
_slots[i].SaveOrLoad(serializer, roomData.LocalScripts, ResourceManager.NumGlobalScripts);
}
}
if (serializer.IsLoading)
{
_slots.ForEach(slot =>
{
if (slot.Where == WhereIsObject.Global)
{
slot.Offset -= 6;
}
else if (slot.Where == WhereIsObject.Local && slot.Number >= ResourceManager.NumGlobalScripts && roomData.LocalScripts[slot.Number - ResourceManager.NumGlobalScripts] != null)
{
slot.Offset = (uint)(slot.Offset - roomData.LocalScripts[slot.Number - ResourceManager.NumGlobalScripts].Offset);
}
});
ResetRoomObjects();
}
//
// Save/load local objects
//
for (int i = 0; i < _objs.Length; i++)
{
_objs[i].SaveOrLoad(serializer);
}
//
// Save/load misc stuff
//
for (int i = 0; i < Verbs.Length; i++)
{
Verbs[i].SaveOrLoad(serializer);
}
for (int i = 0; i < 16; i++)
{
_nest[i].SaveOrLoad(serializer);
}
for (int i = 0; i < 6; i++)
{
_sentence[i].SaveOrLoad(serializer);
}
for (int i = 0; i < 6; i++)
{
_string[i].SaveOrLoad(serializer);
}
for (int i = 0; i < 16; i++)
{
_colorCycle[i].SaveOrLoad(serializer);
}
if (serializer.Version >= 13)
{
for (int i = 0; i < 20; i++)
{
if (serializer.IsLoading)
{
_scaleSlots[i] = new ScaleSlot();
}
if (_scaleSlots[i] != null)
{
_scaleSlots[i].SaveOrLoad(serializer);
}
}
}
//
// Save/load resources
//
SaveOrLoadResources(serializer);
//
// Save/load global object state
//
var objStatesEntries = new[]
{
LoadAndSaveEntry.Create(reader =>
{
var objectOwnerTable = reader.ReadBytes(_resManager.ObjectOwnerTable.Length);
Array.Copy(objectOwnerTable, _resManager.ObjectOwnerTable, _resManager.ObjectOwnerTable.Length);
},
writer => writer.WriteBytes(_resManager.ObjectOwnerTable, _resManager.ObjectOwnerTable.Length)),
LoadAndSaveEntry.Create(reader =>
{
var objectStateTable = reader.ReadBytes(_resManager.ObjectStateTable.Length);
Array.Copy(objectStateTable, _resManager.ObjectStateTable, _resManager.ObjectStateTable.Length);
},
writer => writer.WriteBytes(_resManager.ObjectStateTable, _resManager.ObjectStateTable.Length))
};
objStatesEntries.ForEach(e => e.Execute(serializer));
//if (_objectRoomTable)
// s->saveLoadArrayOf(_objectRoomTable, _numGlobalObjects, sizeof(_objectRoomTable[0]), sleByte);
//
// 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);
//}
var paletteEntries = new[]
{
LoadAndSaveEntry.Create(
reader => _shadowPalette = reader.ReadBytes(_shadowPalette.Length),
writer => writer.WriteBytes(_shadowPalette, _shadowPalette.Length)),
// _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.
LoadAndSaveEntry.Create(
reader => Gdi.RoomPalette = reader.ReadBytes(256),
writer => writer.WriteBytes(Gdi.RoomPalette, 256)
, 21),
// PalManip data was not saved before V10 save games
LoadAndSaveEntry.Create(reader =>
{
if (_palManipCounter != 0)
{
var colors = reader.ReadBytes(0x300);
for (int i = 0; i < 0x100; i++)
{
_palManipPalette.Colors[i] = Color.FromRgb(colors[i * 3], colors[i * 3 + 1], colors[i * 3 + 2]);
}
var colors2 = reader.ReadUInt16s(0x300);
for (int i = 0; i < 0x100; i++)
{
_palManipIntermediatePal.Colors[i] = Color.FromRgb(colors2[i * 3], colors2[i * 3 + 1], colors2[i * 3 + 2]);
}
}
},
writer =>
{
if (_palManipCounter != 0)
{
for (int i = 0; i < 0x100; i++)
{
writer.WriteByte(_palManipPalette.Colors[i].R);
writer.WriteByte(_palManipPalette.Colors[i].G);
writer.WriteByte(_palManipPalette.Colors[i].B);
}
for (int i = 0; i < 0x100; i++)
{
writer.WriteUInt16(_palManipIntermediatePal.Colors[i].R);
writer.WriteUInt16(_palManipIntermediatePal.Colors[i].G);
writer.WriteUInt16(_palManipIntermediatePal.Colors[i].B);
}
}
}, 10),
// darkenPalette was not saved before V53
LoadAndSaveEntry.Create(reader =>
{
// TODO?
//Array.Copy(currentPalette, darkenPalette, 768);
}, 0, 53),
};
paletteEntries.ForEach(entry => entry.Execute(serializer));
// _colorUsedByCycle was not saved before V60
if (serializer.IsLoading)
{
if (serializer.Version < 60)
{
//Array.Clear(_colorUsedByCycle, 0, _colorUsedByCycle.Length);
}
}
// 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);
// // 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);
// } else {
// amigaPaletteFindFirstUsedColor();
// }
// } else {
// warning("Save with old Indiana Jones 4 Amiga palette handling detected");
// // We need to restore the internal state of the Amiga palette for Indy4
// // Amiga. This might lead to graphics glitches!
// setAmigaPaletteFromPtr(_currentPalette);
// }
//}
//
// Save/load more global object state
//
var globalObjStatesEntries = new[]
{
LoadAndSaveEntry.Create(
reader => Array.Copy(reader.ReadUInt32s(_resManager.ClassData.Length), _resManager.ClassData, _resManager.ClassData.Length),
writer => writer.WriteUInt32s(_resManager.ClassData, _resManager.ClassData.Length))
};
globalObjStatesEntries.ForEach(entry => entry.Execute(serializer));
//
// Save/load script variables
//
var var120Backup = _variables[120];
var var98Backup = _variables[98];
//if (serializer.Version > 37)
//{
// s->saveLoadArrayOf(_roomVars, _numRoomVariables, sizeof(_roomVars[0]), sleInt32);
//}
// The variables grew from 16 to 32 bit.
var variablesEntries = new[]
{
LoadAndSaveEntry.Create(
reader => _variables = reader.ReadInt16s(_variables.Length).ConvertAll(s => (int)s),
writer => writer.WriteInt16s(_variables, _variables.Length)
, 0, 15),
LoadAndSaveEntry.Create(
reader => _variables = reader.ReadInt32s(_variables.Length),
writer => writer.WriteInt32s(_variables, _variables.Length), 15),
LoadAndSaveEntry.Create(
reader => _bitVars = new BitArray(reader.ReadBytes(_bitVars.Length / 8)),
writer => writer.Write(_bitVars.ToByteArray())
),
};
variablesEntries.ForEach(entry => entry.Execute(serializer));
if (_game.GameId == GameId.Tentacle) // Maybe misplaced, but that's the main idea
{
_variables[120] = var120Backup;
}
if (_game.GameId == GameId.Indy4)
{
_variables[98] = var98Backup;
}
//
// Save/load a list of the locked objects
//
var lockedObjEntries = new[]
{
LoadAndSaveEntry.Create(reader =>
{
ResType tmp;
while ((tmp = (ResType)reader.ReadByte()) != (ResType)0xFF)
{
var index = reader.ReadUInt16();
if (tmp == ResType.FlObject)
{
_objs[index].IsLocked = true;
}
}
},
writer =>
{
for (int i = 0; i < _objs.Length; i++)
{
if (_objs[i].IsLocked)
{
writer.WriteByte((byte)ResType.FlObject);
writer.WriteUInt16(i);
}
}
writer.Write((byte)0xFF);
}
)
};
lockedObjEntries.ForEach(entry => entry.Execute(serializer));
//
// Save/load the Audio CD status
//
//if (serializer.Version >= 24)
//{
// AudioCDManager::Status info;
// if (s->isSaving())
// info = _system->getAudioCDManager()->getStatus();
// s->saveLoadArrayOf(&info, 1, sizeof(info), audioCDEntries);
// 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)
// _system->getAudioCDManager()->play(info.track, info.numLoops, info.start, info.duration);
//}
//
// Save/load the iMuse status
//
if (IMuse != null && (_saveSound || !_saveTemporaryState))
{
IMuse.SaveOrLoad(serializer);
}
//
// Save/load music engine status
//
if (MusicEngine != null)
{
MusicEngine.SaveOrLoad(serializer);
}
//
// Save/load the charset renderer state
//
//if (s->getVersion() >= VER(73))
//{
// _charset->saveLoadWithSerializer(s);
//}
//else if (s->isLoading())
//{
// if (s->getVersion() == VER(72))
// {
// _charset->setCurID(s->loadByte());
// }
// 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,
// // we reinitialize the id using a, hopefully, sane value.
// _charset->setCurID(_string[0]._default.charset);
// }
//}
}