void ResetRoomSubBlocks() { // Reset room color for V1 zak if (Game.Version <= 1) { Gdi.RoomPalette[0] = 0; } _boxMatrix.Clear(); _boxMatrix.AddRange(roomData.BoxMatrix); for (int i = 0; i < _scaleSlots.Length; i++) { _scaleSlots[i] = new ScaleSlot(); } for (int i = 1; i <= roomData.Scales.Length; i++) { var scale = roomData.Scales[i - 1]; if (Game.Version == 8 || scale.Scale1 != 0 || scale.Y1 != 0 || scale.Scale2 != 0 || scale.Y2 != 0) { SetScaleSlot(i, 0, scale.Y1, scale.Scale1, 0, scale.Y2, scale.Scale2); } } Array.Clear(_extraBoxFlags, 0, _extraBoxFlags.Length); _boxes = new Box[roomData.Boxes.Count]; for (int i = 0; i < roomData.Boxes.Count; i++) { var box = roomData.Boxes[i]; _boxes[i] = new Box { Flags = box.Flags, Llx = box.Llx, Lly = box.Lly, Lrx = box.Lrx, Lry = box.Lry, Mask = box.Mask, Scale = box.Scale, ScaleSlot = box.ScaleSlot, Ulx = box.Ulx, Uly = box.Uly, Urx = box.Urx, Ury = box.Ury }; } Array.Copy(roomData.ColorCycle, _colorCycle, roomData.ColorCycle.Length); Gdi.RoomChanged(CurrentRoomData); }
protected void SetScaleSlot(int slot, int x1, int y1, int scale1, int x2, int y2, int scale2) { if (slot < 1) { throw new ArgumentOutOfRangeException("slot", "Invalid scale slot"); } if (slot > _scaleSlots.Length) { throw new ArgumentOutOfRangeException("slot", "Invalid scale slot"); } _scaleSlots[slot - 1] = new ScaleSlot { X1 = x1, X2 = x2, Y1 = y1, Y2 = y2, Scale1 = scale1, Scale2 = scale2 }; }
public Room() { Boxes = new List <Box>(); Objects = new List <ObjectData>(); BoxMatrix = new List <byte>(); EntryScript = new ScriptData(); ExitScript = new ScriptData(); LocalScripts = new ScriptData[1024]; TransparentColor = 255; Scales = new ScaleSlot[0]; ColorCycle = new ColorCycle[16]; for (int i = 0; i < ColorCycle.Length; i++) { ColorCycle[i] = new ColorCycle(); } Image = new ImageData(); Palettes = new List <Palette>(); Palettes.Add(new Palette()); }
public Room() { Boxes = new List<Box>(); Objects = new List<ObjectData>(); BoxMatrix = new List<byte>(); EntryScript = new ScriptData(); ExitScript = new ScriptData(); LocalScripts = new ScriptData[1024]; TransparentColor = 255; Scales = new ScaleSlot[0]; ColorCycle = new ColorCycle[16]; for (int i = 0; i < ColorCycle.Length; i++) { ColorCycle[i] = new ColorCycle(); } Image = new ImageData(); Palettes = new List<Palette>(); Palettes.Add(new Palette()); }
protected void SetScaleSlot(int slot, int x1, int y1, int scale1, int x2, int y2, int scale2) { if (slot < 1) throw new ArgumentOutOfRangeException("slot", "Invalid scale slot"); if (slot > _scaleSlots.Length) throw new ArgumentOutOfRangeException("slot", "Invalid scale slot"); _scaleSlots[slot - 1] = new ScaleSlot { X1 = x1, X2 = x2, Y1 = y1, Y2 = y2, Scale1 = scale1, Scale2 = scale2 }; }
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); // } //} }
protected ScummEngine(GameSettings settings, IGraphicsManager gfxManager, IInputManager inputManager, IMixer mixer) { Settings = settings; var game = (GameInfo)settings.Game; _resManager = ResourceManager.Load(game); _game = game; InvalidBox = _game.Version < 5 ? (byte)255 : (byte)0; _gameMD5 = ToMd5Bytes(game.MD5); _gfxManager = gfxManager; _inputManager = inputManager; _inputState = inputManager.GetState(); _strings = new byte[_resManager.NumArray][]; _inventory = new ushort[_resManager.NumInventory]; _invData = new ObjectData[_resManager.NumInventory]; CurrentScript = 0xFF; Mixer = mixer; ScreenWidth = Game.Width; ScreenHeight = Game.Height; AudioCDManager = new DefaultAudioCDManager(this, mixer); Sound = new Sound(this, mixer); SetupMusic(); _variables = new int[_resManager.NumVariables]; _bitVars = new BitArray(_resManager.NumBitVariables); _slots = new ScriptSlot[NumScriptSlot]; for (int i = 0; i < NumScriptSlot; i++) { _slots[i] = new ScriptSlot(); } for (int i = 0; i < 200; i++) { _objs[i] = new ObjectData(); } for (int i = 0; i < 6; i++) { _string[i] = new TextSlot(); if (game.Version != 3) { _string[i].Default.Position = new Point(2, 5); } } _colorCycle = new ColorCycle[16]; for (int i = 0; i < _colorCycle.Length; i++) { _colorCycle[i] = new ColorCycle(); } _nest = new NestedScript[MaxScriptNesting + 1]; for (int i = 0; i < _nest.Length; i++) { _nest[i] = new NestedScript(); } _scaleSlots = new ScaleSlot[20]; for (int i = 0; i < _scaleSlots.Length; i++) { _scaleSlots[i] = new ScaleSlot(); } Gdi = Gdi.Create(this, game); switch (game.Version) { case 0: _costumeLoader = new CostumeLoader0(this); _costumeRenderer = new CostumeRenderer0(this); break; case 7: case 8: _costumeLoader = new AkosCostumeLoader(this); _costumeRenderer = new AkosRenderer(this); break; default: _costumeLoader = new ClassicCostumeLoader(this); _costumeRenderer = new ClassicCostumeRenderer(this); break; } CreateCharset(); ResetCursors(); // Create the text surface var pixelFormat = _game.Features.HasFlag(GameFeatures.Is16BitColor) ? PixelFormat.Rgb16 : PixelFormat.Indexed8; _textSurface = new Surface(ScreenWidth * _textSurfaceMultiplier, ScreenHeight * _textSurfaceMultiplier, PixelFormat.Indexed8, false); ClearTextSurface(); if (Game.Platform == Platform.FMTowns) { _townsScreen = new TownsScreen(_gfxManager, ScreenWidth * _textSurfaceMultiplier, ScreenHeight * _textSurfaceMultiplier, PixelFormat.Rgb16); _townsScreen.SetupLayer(0, ScreenWidth, ScreenHeight, 32767); _townsScreen.SetupLayer(1, ScreenWidth * _textSurfaceMultiplier, ScreenHeight * _textSurfaceMultiplier, 16, _textPalette); } if (Game.Version == 0) { InitScreens(8, 144); } else if ((Game.GameId == GameId.Maniac) && (_game.Version <= 1) && _game.Platform != Platform.NES) { InitScreens(16, 152); } else if (Game.Version >= 7) { InitScreens(0, ScreenHeight); } else { InitScreens(16, 144); } // Allocate gfx compositing buffer (not needed for V7/V8 games). if (Game.Version < 7) { _composite = new Surface(ScreenWidth, ScreenHeight, pixelFormat, false); } InitActors(); OwnerRoom = Game.Version >= 7 ? 0x0FF : 0x0F; if (Game.Version < 7) { Camera.LeftTrigger = 10; Camera.RightTrigger = 30; } InitPalettes(); InitializeVerbs(); // WORKAROUND for bug in boot script of Loom (CD) // The boot script sets the characters of string 21, // before creating the string.resource. if (_game.GameId == GameId.Loom) { _strings[21] = new byte[13]; } }
void ResetRoomSubBlocks() { // Reset room color for V1 zak if (Game.Version <= 1) Gdi.RoomPalette[0] = 0; _boxMatrix.Clear(); _boxMatrix.AddRange(roomData.BoxMatrix); for (int i = 0; i < _scaleSlots.Length; i++) { _scaleSlots[i] = new ScaleSlot(); } for (int i = 1; i <= roomData.Scales.Length; i++) { var scale = roomData.Scales[i - 1]; if (Game.Version == 8 || scale.Scale1 != 0 || scale.Y1 != 0 || scale.Scale2 != 0 || scale.Y2 != 0) { SetScaleSlot(i, 0, scale.Y1, scale.Scale1, 0, scale.Y2, scale.Scale2); } } Array.Clear(_extraBoxFlags, 0, _extraBoxFlags.Length); _boxes = new Box[roomData.Boxes.Count]; for (int i = 0; i < roomData.Boxes.Count; i++) { var box = roomData.Boxes[i]; _boxes[i] = new Box { Flags = box.Flags, Llx = box.Llx, Lly = box.Lly, Lrx = box.Lrx, Lry = box.Lry, Mask = box.Mask, Scale = box.Scale, ScaleSlot = box.ScaleSlot, Ulx = box.Ulx, Uly = box.Uly, Urx = box.Urx, Ury = box.Ury }; } Array.Copy(roomData.ColorCycle, _colorCycle, roomData.ColorCycle.Length); Gdi.RoomChanged(CurrentRoomData); }