ScummVM API documentation
savegame.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef LASTEXPRESS_SAVELOAD_H
23 #define LASTEXPRESS_SAVELOAD_H
24 
25 /*
26  Savegame format
27  ---------------
28 
29  header: 32 bytes
30  uint32 {4} - signature: 0x12001200
31  uint32 {4} - chapter - needs to be [0; 5]
32  uint32 {4} - time - needs to be >= 32 [1061100; timeMax]
33  uint32 {4} - ?? needs to be >= 32
34  uint32 {4} - ?? needs to be = 1
35  uint32 {4} - Brightness (needs to be [0-6])
36  uint32 {4} - Volume (needs to be [0-7])
37  uint32 {4} - ?? needs to be = 9
38 
39  Game data Format
40  -----------------
41 
42  uint32 {4} - entity
43  uint32 {4} - current time
44  uint32 {4} - time delta (how much a tick is in "real" time)
45  uint32 {4} - time ticks
46  uint32 {4} - scene Index max: 2500
47  byte {1} - use backup scene
48  uint32 {4} - backup Scene Index 1 max: 2500
49  uint32 {4} - backup Scene Index 2 max: 2500
50  uint32 {4} - selected inventory item max: 32
51  uint32 {4*100*10} - positions by car(BlockedView)
52  uint32 {4*16} - compartments (BlockedX)
53  uint32 {4*16} - compartments? (SoftBlockedX)
54  uint32 {4*128} - game progress
55  byte {512} - game events
56  byte {7*32} - inventory
57  byte {5*128} - objects
58  byte {1262*40} - entities (characters and train entities)
59 
60  uint32 {4} - sound queue state
61  uint32 {4} - ??
62  uint32 {4} - number of sound entries
63  byte {count*68} - sound entries
64 
65  byte {16*128} - save point data
66  uint32 {4} - number of save points (max: 128)
67  byte {count*16} - save points
68 
69  ... more unknown stuff
70 
71 */
72 
73 #include "lastexpress/shared.h"
74 
75 #include "common/savefile.h"
76 #include "common/serializer.h"
77 #include "common/memstream.h"
78 
79 #include "engines/savestate.h"
80 
81 namespace LastExpress {
82 
83 // our own hack until compression code will be confirmed stable
84 #define DISABLE_COMPRESSION 1
85 
86 // Savegame signatures
87 #define SAVEGAME_SIGNATURE (0x12001200 ^ DISABLE_COMPRESSION) // 301994496
88 #define SAVEGAME_ENTRY_SIGNATURE 0xE660E660 // 3865110112
89 
90 #define WRAP_SYNC_FUNCTION(instance, className, method) \
91  new Common::Functor1Mem<Common::Serializer &, void, className>(instance, &className::method)
92 
93 class LastExpressEngine;
94 
96 public:
97  SavegameStream() : MemoryWriteStreamDynamic(DisposeAfterUse::YES), _eos(false) {
98  _enableCompression = false;
99  _bufferOffset = -1;
100  _valueCount = 0;
101  _previousValue = 0;
102  _repeatCount = 0;
103  _offset = 0;
104  _status = kStatusReady;
105 
106  memset(_buffer, 0, 256);
107  }
108 
109  int64 pos() const override { return MemoryWriteStreamDynamic::pos(); }
110  int64 size() const override { return MemoryWriteStreamDynamic::size(); }
111  bool seek(int64 offset, int whence = SEEK_SET) override { return MemoryWriteStreamDynamic::seek(offset, whence); }
112  bool eos() const override { return _eos; }
113  uint32 read(void *dataPtr, uint32 dataSize) override;
114  uint32 write(const void *dataPtr, uint32 dataSize) override;
115 
116  uint32 process();
117 
118 private:
119  enum CompressedStreamStatus {
120  kStatusReady,
121  kStatusReading,
122  kStatusWriting
123  };
124 
125  uint32 readUncompressed(void *dataPtr, uint32 dataSize);
126 
127  // Compressed data
128  uint32 writeCompressed(const void *dataPtr, uint32 dataSize);
129  uint32 readCompressed(void *dataPtr, uint32 dataSize);
130 
131  void writeBuffer(uint8 value, bool onlyValue = true);
132  uint8 readBuffer();
133 
134 private:
135  bool _eos;
136 
137  // Compression handling
138  bool _enableCompression;
139  int16 _bufferOffset;
140  byte _valueCount;
141  byte _previousValue;
142  int16 _repeatCount;
143  uint32 _offset;
144  CompressedStreamStatus _status;
145 
146  byte _buffer[256];
147 };
148 
149 class SaveLoad {
150 public:
151  static const int kMaximumSaveSlots = 6; // blue, red, green, purple, teal, gold
152 
153  SaveLoad(LastExpressEngine *engine);
154  ~SaveLoad();
155 
156  // Init
157  void create(const Common::String &target, GameId id);
158  void clear(bool clearStream = false);
159  uint32 init(const Common::String &target, GameId id, bool resetHeaders);
160 
161  // Save & Load
162  void loadLastGame();
163  void loadGame(uint32 index);
164  void saveGame(SavegameType type, EntityIndex entity, uint32 value);
165 
166  void loadVolumeBrightness();
167  void saveVolumeBrightness();
168 
169  static SaveStateList list(const MetaEngine *metaEngine, const Common::String &target);
170  static bool remove(const Common::String &target, GameId slot);
171 
172  // Opening save files
173  static Common::String getFilename(const Common::String &target, GameId slot);
174  static Common::InSaveFile *openForLoading(const Common::String &target, GameId slot);
175  static Common::OutSaveFile *openForSaving(const Common::String &target, GameId slot);
176 
177  // Getting information
178  static bool isSavegamePresent(const Common::String &target, GameId id);
179  static bool isSavegameValid(const Common::String &target, GameId id);
180 
181  bool isGameFinished(uint32 menuIndex, uint32 savegameIndex);
182 
183  // Accessors
184  uint32 getTime(uint32 index) { return getEntry(index)->time; }
185  ChapterIndex getChapter(uint32 index) { return getEntry(index)->chapter; }
186  uint32 getValue(uint32 index) { return getEntry(index)->value; }
187  uint32 getLastSavegameTicks() const { return _gameTicksLastSavegame; }
188 
189 private:
190  LastExpressEngine *_engine;
191 
192  struct SavegameMainHeader : Common::Serializable {
193  uint32 signature;
194  uint32 count;
195  uint32 offset;
196  uint32 offsetEntry;
197  uint32 keepIndex;
198  int32 brightness;
199  int32 volume;
200  uint32 field_1C;
201 
202  SavegameMainHeader() {
203  signature = SAVEGAME_SIGNATURE;
204  count = 0;
205  offset = 32;
206  offsetEntry = 32;
207  keepIndex = 0;
208  brightness = 3;
209  volume = 7;
210  field_1C = 9; // Note: In demo's original save "BLUE.EGG" this value is 0x19
211  }
212 
213  void saveLoadWithSerializer(Common::Serializer &s) override {
214  s.syncAsUint32LE(signature);
215  s.syncAsUint32LE(count);
216  s.syncAsUint32LE(offset);
217  s.syncAsUint32LE(offsetEntry);
218  s.syncAsUint32LE(keepIndex);
219  s.syncAsUint32LE(brightness);
220  s.syncAsUint32LE(volume);
221  s.syncAsUint32LE(field_1C);
222  }
223 
224  bool isValid() {
225  if (signature != SAVEGAME_SIGNATURE)
226  return false;
227 
228  /* Check not needed as it can never be < 0
229  if (header.chapter < 0)
230  return false;*/
231 
232  if (offset < 32)
233  return false;
234 
235  if (offsetEntry < 32)
236  return false;
237 
238  if (keepIndex != 1 && keepIndex != 0)
239  return false;
240 
241  if (brightness < 0 || brightness > 6)
242  return false;
243 
244  if (volume < 0 || volume > 7)
245  return false;
246 
247  if (field_1C != 9)
248  return false;
249 
250  return true;
251  }
252  };
253 
254  struct SavegameEntryHeader : Common::Serializable {
255  uint32 signature;
256  SavegameType type;
257  uint32 time;
258  int offset;
259  ChapterIndex chapter;
260  uint32 value;
261  int field_18;
262  int field_1C;
263 
264  SavegameEntryHeader() {
265  signature = SAVEGAME_ENTRY_SIGNATURE;
266  type = kSavegameTypeIndex;
267  time = kTimeNone;
268  offset = 0;
269  chapter = kChapterAll;
270  value = 0;
271  field_18 = 0;
272  field_1C = 0;
273  }
274 
275  void saveLoadWithSerializer(Common::Serializer &s) override {
276  s.syncAsUint32LE(signature);
277  s.syncAsUint32LE(type);
278  s.syncAsUint32LE(time);
279  s.syncAsUint32LE(offset);
280  s.syncAsUint32LE(chapter);
281  s.syncAsUint32LE(value);
282  s.syncAsUint32LE(field_18);
283  s.syncAsUint32LE(field_1C);
284  }
285 
286  bool isValid() {
287  if (signature != SAVEGAME_ENTRY_SIGNATURE)
288  return false;
289 
290  if (type < kSavegameTypeTime || type > kSavegameTypeTickInterval)
291  return false;
292 
293  if (time < kTimeStartGame || time > kTimeCityConstantinople)
294  return false;
295 
296  if (offset <= 0 || offset & 0xF)
297  return false;
298 
299  /* No check for < 0, as it cannot happen normaly */
300  if (chapter == 0)
301  return false;
302 
303  return true;
304  }
305  };
306 
307  SavegameStream *_savegame;
309  uint32 _gameTicksLastSavegame;
310 
311  // Headers
312  static bool loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *header);
313 
314  // Entries
315  void writeEntry(SavegameType type, EntityIndex entity, uint32 val);
316  void readEntry(SavegameType *type, EntityIndex *entity, uint32 *val, bool keepIndex);
317 
318  uint32 writeValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size);
319  uint32 readValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size = 0);
320 
321  SavegameEntryHeader *getEntry(uint32 index);
322 
323  // Savegame stream
324  void initStream();
325  void loadStream(const Common::String &target, GameId id);
326  void flushStream(const Common::String &target, GameId id);
327 
328  // Misc
329  EntityIndex _entity;
330  void syncEntity(Common::Serializer &ser);
331 };
332 
333 } // End of namespace LastExpress
334 
335 #endif // LASTEXPRESS_SAVELOAD_H
Definition: metaengine.h:196
Definition: str.h:59
Definition: savefile.h:54
Definition: lastexpress.h:69
int64 size() const override
Definition: savegame.h:110
Definition: savegame.h:95
Definition: memstream.h:194
Definition: stream.h:745
Definition: animation.h:45
Definition: serializer.h:79
bool eos() const override
Definition: savegame.h:112
Definition: savegame.h:149
bool seek(int64 offset, int whence=SEEK_SET) override
Definition: savegame.h:111
uint32 read(void *dataPtr, uint32 dataSize) override
Definition: serializer.h:308
Definition: func.h:437
uint32 write(const void *dataPtr, uint32 dataSize) override
int64 pos() const override
Definition: savegame.h:109