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
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (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  * aint32 with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  *
22  * Based on the original sources
23  *   Faery Tale II -- The Halls of the Dead
24  *   (c) 1993-1996 The Wyrmkeep Entertainment Co.
25  */
26 
27 #include "saga2/saga2.h"
28 #include "saga2/saveload.h"
29 #include "saga2/objects.h"
30 #include "saga2/tile.h"
31 #include "saga2/script.h"
32 #include "saga2/motion.h"
33 #include "saga2/task.h"
34 #include "saga2/speech.h"
35 #include "saga2/timers.h"
36 #include "saga2/sensor.h"
37 #include "saga2/band.h"
38 #include "saga2/mission.h"
39 #include "saga2/tilemode.h"
40 #include "saga2/magic.h"
41 #include "saga2/intrface.h"
42 #include "saga2/vpal.h"
43 #include "saga2/palette.h"
44 #include "saga2/contain.h"
45 #include "saga2/imagcach.h"
46 
47 namespace Saga2 {
48 
49 void updateMainDisplay(void);
50 void fadeUp();
51 void fadeDown();
52 void enablePaletteChanges();
53 
54 const ChunkID   gameID = MKTAG('F', 'T', 'A', '2');
55 
read(Common::InSaveFile * in)56 void SaveFileHeader::read(Common::InSaveFile *in) {
57 	char fileName[SaveFileHeader::kSaveNameSize];
58 	gameID = in->readUint32BE();;
59 	in->read(fileName, SaveFileHeader::kSaveNameSize);
60 	saveName = fileName;
61 }
62 
write(Common::OutSaveFile * out)63 void SaveFileHeader::write(Common::OutSaveFile *out) {
64 	out->writeUint32BE(gameID);
65 	out->write(saveName.c_str(), saveName.size());
66 
67 	int remainingBytes = SaveFileHeader::kHeaderSize - saveName.size() - 4;
68 
69 	for (int i = 0; i < remainingBytes; ++i)
70 		out->writeByte(0);
71 
72 	debugC(1, kDebugSaveload, "Writing game header: gameID = %s, saveName = %s", tag2str(gameID), saveName.c_str());
73 }
74 
75 /* ===================================================================== *
76    Functions
77  * ===================================================================== */
78 
79 //	The following resources are included in the save file
80 //		GLOB -  miscellaneous globals
81 //		TIME -  game timer
82 //		CALE -  game calender
83 //		WRLD -  worlds
84 //		ACTR -  actors
85 //		OBJS -  objects
86 //		BAND -  actor bands
87 //		PLYR -  player actors
88 //		CNTR -  center actor ID and view object ID
89 //		TAGS -  active item instance state arrays
90 //		CYCL -  tile cycling states
91 //		SDTA -  SAGA data segment
92 //		SAGA -  SAGA threads
93 //		MOTN -  motion tasks
94 //		TSTK -  actor task stacks
95 //		TASK -  actor tasks
96 //		TACT -  tile activity tasks
97 //		SPCH -  speech tasks
98 //		AREG -  active regions
99 //		TIMR -  actor timers
100 //		SENS -  actor sensors
101 //		ACNT -  temporary actor count array
102 //		MISS -  missions
103 //		FACT -  faction tallies
104 //		TMST -  TileMode state
105 //		SPEL -  Active Spell List
106 //		AMAP -  auto map data
107 //		UIST -  user interface state
108 //		PALE -  palette state
109 //		CONT -  container nodes
110 
111 //----------------------------------------------------------------------
112 //	Load initial game state
113 
initGameState(void)114 void initGameState(void) {
115 	pauseTimer();
116 
117 	initGlobals();
118 	initCalender();
119 	initWorlds();
120 	initActors();
121 	initObjects();
122 	initBands();
123 	initPlayerActors();
124 	initCenterActor();
125 	initActiveItemStates();
126 	initTileCyclingStates();
127 	initSAGADataSeg();
128 	initSAGAThreads();
129 	initMotionTasks();
130 	initTaskStacks();
131 	initTasks();
132 	initTileTasks();
133 	initSpeechTasks();
134 	initActiveRegions();
135 	initSensors();
136 	initTempActorCount();
137 	initMissions();
138 	initFactionTallies();
139 	initTileModeState();
140 	initSpellState();
141 	initAutoMap();
142 	initUIState();
143 	initPaletteState();
144 	initContainerNodes();
145 
146 	resumeTimer();
147 }
148 
149 //----------------------------------------------------------------------
150 //	Save the current game state
151 
saveGame(Common::OutSaveFile * out,Common::String saveName)152 void saveGame(Common::OutSaveFile *out, Common::String saveName) {
153 	debugC(1, kDebugSaveload, "Saving game");
154 
155 	SaveFileHeader header;
156 	header.gameID = gameID;
157 	header.saveName = saveName;
158 
159 	header.write(out);
160 
161 	saveGlobals(out);
162 	saveTimer(out);
163 	saveCalender(out);
164 	saveWorlds(out);
165 	saveActors(out);
166 	saveObjects(out);
167 	saveBands(out);
168 	savePlayerActors(out);
169 	saveCenterActor(out);
170 	saveActiveItemStates(out);
171 	saveTileCyclingStates(out);
172 	saveSAGADataSeg(out);
173 	saveSAGAThreads(out);
174 	saveMotionTasks(out);
175 	saveTaskStacks(out);
176 	saveTasks(out);
177 	saveTileTasks(out);
178 	saveSpeechTasks(out);
179 	saveActiveRegions(out);
180 	saveTimers(out);
181 	saveSensors(out);
182 	saveTempActorCount(out);
183 	saveMissions(out);
184 	saveFactionTallies(out);
185 	saveTileModeState(out);
186 	saveSpellState(out);
187 	saveAutoMap(out);
188 	saveUIState(out);
189 	savePaletteState(out);
190 	saveContainerNodes(out);
191 }
192 
firstChunk(Common::InSaveFile * in,ChunkID & chunk,int32 & size)193 bool firstChunk(Common::InSaveFile *in, ChunkID &chunk, int32 &size) {
194 	if (!in->seek(SaveFileHeader::kHeaderSize, SEEK_SET))
195 		error("Error seeking first save game chunk");
196 
197 	if (in->size() - in->pos() < 8) {
198 		debugC(1, kDebugSaveload, "Reached EOF on first Chunk %s", tag2str(chunk));
199 		return false;
200 	}
201 
202 	chunk = in->readUint32BE();
203 	size = in->readUint32LE();
204 
205 	debugC(1, kDebugSaveload, "First Chunk loaded: chunkID = %s, size = %d", tag2str(chunk), size);
206 
207 	return true;
208 }
209 
nextChunk(Common::InSaveFile * in,ChunkID & chunk,int32 & size)210 bool nextChunk(Common::InSaveFile *in, ChunkID &chunk, int32 &size) {
211 	if (in->size() - in->pos() < 8) {
212 		debugC(1, kDebugSaveload, "Reached EOF at %s", tag2str(chunk));
213 		return false;
214 	}
215 
216 	chunk = in->readUint32BE();
217 	size = in->readUint32LE();
218 
219 	debugC(1, kDebugSaveload, "Next Chunk loaded: chunkID = %s, size = %d", tag2str(chunk), size);
220 
221 	//  Return success
222 	return true;
223 }
224 
225 //----------------------------------------------------------------------
226 //	Load a previously saved game state
227 
loadSavedGameState(int16 saveNo)228 void loadSavedGameState(int16 saveNo) {
229 	enum {
230 		loadGlobalsFlag             = (1 << 0),
231 		loadTimerFlag               = (1 << 1),
232 		loadCalenderFlag            = (1 << 2),
233 		loadWorldsFlag              = (1 << 3),
234 		loadActorsFlag              = (1 << 4),
235 		loadObjectsFlag             = (1 << 5),
236 		loadBandsFlag               = (1 << 6),
237 		loadPlayerActorsFlag        = (1 << 7),
238 		loadCenterActorFlag         = (1 << 8),
239 		loadActiveItemStatesFlag    = (1 << 9),
240 		loadTileCyclingStatesFlag   = (1 << 10),
241 		loadSAGADataSegFlag         = (1 << 11),
242 		loadSAGAThreadsFlag         = (1 << 12),
243 		loadMotionTasksFlag         = (1 << 13),
244 		loadTaskStacksFlag          = (1 << 14),
245 		loadTasksFlag               = (1 << 15),
246 		loadTileTasksFlag           = (1 << 16),
247 		loadSpeechTasksFlag         = (1 << 17),
248 		loadActiveRegionsFlag       = (1 << 18),
249 		loadTimersFlag              = (1 << 19),
250 		loadSensorsFlag             = (1 << 20),
251 		loadTempActorCountFlag      = (1 << 21),
252 		loadMissionsFlag            = (1 << 22),
253 		loadFactionTalliesFlag      = (1 << 23),
254 		loadTileModeStateFlag       = (1 << 24),
255 		loadSpellStateFlag          = (1 << 25),
256 		loadAutoMapFlag             = (1 << 26),
257 		loadUIStateFlag             = (1 << 27),
258 		loadPaletteStateFlag        = (1 << 28),
259 		loadContainerNodesFlag      = (1 << 29)
260 	};
261 
262 	uint32  loadFlags = 0;
263 
264 	pauseTimer();
265 
266 	Common::InSaveFile *in = g_vm->getSaveFileManager()->openForLoading(g_vm->getSavegameFile(saveNo));
267 
268 	ChunkID         id;
269 	int32           chunkSize;
270 	bool            notEOF;
271 
272 	notEOF = firstChunk(in, id, chunkSize);
273 	while (notEOF) {
274 		switch (id) {
275 		case MKTAG('G', 'L', 'O', 'B'):
276 			loadGlobals(in);
277 			loadFlags |= loadGlobalsFlag;
278 			break;
279 
280 		case MKTAG('T', 'I', 'M', 'E'):
281 			loadTimer(in);
282 			loadFlags |= loadTimerFlag;
283 			break;
284 
285 		case MKTAG('C', 'A', 'L', 'E'):
286 			loadCalender(in);
287 			loadFlags |= loadCalenderFlag;
288 			break;
289 
290 		case MKTAG('W', 'R', 'L', 'D'):
291 			loadWorlds(in);
292 			loadFlags |= loadWorldsFlag;
293 			break;
294 
295 		case MKTAG('A', 'C', 'T', 'R'):
296 			loadActors(in);
297 			loadFlags |= loadActorsFlag;
298 			break;
299 
300 		case MKTAG('O', 'B', 'J', 'S'):
301 			loadObjects(in);
302 			loadFlags |= loadObjectsFlag;
303 			break;
304 
305 		case MKTAG('B', 'A', 'N', 'D'):
306 			if (loadFlags & loadActorsFlag) {
307 				loadBands(in, chunkSize);
308 				loadFlags |= loadBandsFlag;
309 			} else
310 				error("Bands loaded prematurely");
311 			break;
312 
313 		case MKTAG('P', 'L', 'Y', 'R'):
314 			if (loadFlags & loadBandsFlag) {
315 				loadPlayerActors(in);
316 				loadFlags |= loadPlayerActorsFlag;
317 			} else
318 				error("PlayerActors loaded prematurely");
319 			break;
320 
321 		case MKTAG('C', 'N', 'T', 'R'):
322 			loadCenterActor(in);
323 			loadFlags |= loadCenterActorFlag;
324 			break;
325 
326 		case MKTAG('T', 'A', 'G', 'S'):
327 			loadActiveItemStates(in);
328 			loadFlags |= loadActiveItemStatesFlag;
329 			break;
330 
331 		case MKTAG('C', 'Y', 'C', 'L'):
332 			loadTileCyclingStates(in);
333 			loadFlags |= loadTileCyclingStatesFlag;
334 			break;
335 
336 		case MKTAG('S', 'D', 'T', 'A'):
337 			loadSAGADataSeg(in);
338 			loadFlags |= loadSAGADataSegFlag;
339 			break;
340 
341 		case MKTAG('S', 'A', 'G', 'A'):
342 			loadSAGAThreads(in, chunkSize);
343 			loadFlags |= loadSAGAThreadsFlag;
344 			break;
345 
346 		case MKTAG('M', 'O', 'T', 'N'):
347 			if (!(~loadFlags & (loadActorsFlag | loadObjectsFlag))) {
348 				loadMotionTasks(in, chunkSize);
349 				loadFlags |= loadMotionTasksFlag;
350 			} else
351 				error("MotionTasks loaded prematurely");
352 			break;
353 
354 		case MKTAG('T', 'S', 'T', 'K'):
355 			if (loadFlags & loadActorsFlag) {
356 				loadTaskStacks(in, chunkSize);
357 				loadFlags |= loadTaskStacksFlag;
358 			} else
359 				error("TaskStacks loaded prematurely");
360 			break;
361 
362 		case MKTAG('T', 'A', 'S', 'K'):
363 			if (loadFlags & loadTaskStacksFlag) {
364 				loadTasks(in, chunkSize);
365 				loadFlags |= loadTasksFlag;
366 			} else
367 				error("Tasks loaded prematurely");
368 			break;
369 
370 		case MKTAG('T', 'A', 'C', 'T'):
371 			if (loadFlags & loadWorldsFlag) {
372 				loadTileTasks(in, chunkSize);
373 				loadFlags |= loadTileTasksFlag;
374 			} else
375 				error("TileActivityTasks loaded prematurely");
376 			break;
377 
378 		case MKTAG('S', 'P', 'C', 'H'):
379 			if (!(~loadFlags & (loadActorsFlag | loadObjectsFlag))) {
380 				loadSpeechTasks(in, chunkSize);
381 				loadFlags |= loadSpeechTasksFlag;
382 			} else
383 				error("SpeechTasks loaded prematurely");
384 			break;
385 
386 		case MKTAG('A', 'R', 'E', 'G'):
387 			loadActiveRegions(in);
388 			loadFlags |= loadActiveRegionsFlag;
389 			break;
390 
391 		case MKTAG('T', 'I', 'M', 'R'):
392 			if (loadFlags & loadActorsFlag) {
393 				loadTimers(in);
394 				loadFlags |= loadTimersFlag;
395 			} else
396 				error("Timers loaded prematurely");
397 			break;
398 
399 		case MKTAG('S', 'E', 'N', 'S'):
400 			if (loadFlags & loadActorsFlag) {
401 				loadSensors(in);
402 				loadFlags |= loadSensorsFlag;
403 			} else
404 				error("Sensors loaded prematurely");
405 			break;
406 
407 		case MKTAG('A', 'C', 'N', 'T'):
408 			loadTempActorCount(in, chunkSize);
409 			loadFlags |= loadTempActorCountFlag;
410 			break;
411 
412 		case MKTAG('M', 'I', 'S', 'S'):
413 			loadMissions(in);
414 			loadFlags |= loadMissionsFlag;
415 			break;
416 
417 		case MKTAG('F', 'A', 'C', 'T'):
418 			loadFactionTallies(in);
419 			loadFlags |= loadFactionTalliesFlag;
420 			break;
421 
422 		case MKTAG('T', 'M', 'S', 'T'):
423 			if (loadFlags & loadActorsFlag) {
424 				loadTileModeState(in);
425 				loadFlags |= loadTileModeStateFlag;
426 			} else
427 				error("TileMode state loaded prematurely");
428 			break;
429 
430 		case MKTAG('S', 'P', 'E', 'L'):
431 			loadSpellState(in);
432 			loadFlags |= loadSpellStateFlag;
433 			break;
434 
435 		case MKTAG('A', 'M', 'A', 'P'):
436 			if (loadFlags & loadWorldsFlag) {
437 				loadAutoMap(in, chunkSize);
438 				loadFlags |= loadAutoMapFlag;
439 			} else
440 				error("Auto map loaded prematurely");
441 			break;
442 
443 		case MKTAG('U', 'I', 'S', 'T'):
444 			if (loadFlags & loadPlayerActorsFlag) {
445 				loadUIState(in);
446 				loadFlags |= loadUIStateFlag;
447 			} else
448 				error("UI state loaded prematurely");
449 			break;
450 
451 		case MKTAG('P', 'A', 'L', 'E'):
452 			loadPaletteState(in);
453 			loadFlags |= loadPaletteStateFlag;
454 			break;
455 
456 		case MKTAG('C', 'O', 'N', 'T'):
457 			if (loadFlags & loadObjectsFlag) {
458 				loadContainerNodes(in);
459 				loadFlags |= loadContainerNodesFlag;
460 			} else
461 				error("ContainerNodes loaded prematurely");
462 			break;
463 		}
464 
465 		if (loadFlags & loadContainerNodesFlag)
466 			break;
467 		notEOF = nextChunk(in, id, chunkSize);
468 	}
469 
470 	if (!(loadFlags & loadGlobalsFlag))
471 		error("Globals not loaded");
472 
473 	if (!(loadFlags & loadTimerFlag))
474 		error("Timer not loaded");
475 
476 	if (!(loadFlags & loadCalenderFlag))
477 		error("Game calender not loaded");
478 
479 	if (!(loadFlags & loadWorldsFlag))
480 		error("Worlds not loaded");
481 
482 	if (!(loadFlags & loadObjectsFlag))
483 		error("Objects not loaded");
484 
485 	if (!(loadFlags & loadActorsFlag))
486 		error("Actors not loaded");
487 
488 	if (!(loadFlags & loadPlayerActorsFlag))
489 		error("Player actors not loaded");
490 
491 	if (!(loadFlags & loadCenterActorFlag))
492 		error("Center actor not loaded");
493 
494 	if (!(loadFlags & loadActiveItemStatesFlag))
495 		error("Active item states not loaded");
496 
497 	if (!(loadFlags & loadTileCyclingStatesFlag))
498 		error("Tile cycling states not loaded");
499 
500 	if (!(loadFlags & loadSAGADataSegFlag))
501 		error("SAGA data segment not loaded");
502 
503 	if (!(loadFlags & loadSAGAThreadsFlag))
504 		error("SAGA threads not loaded");
505 
506 	if (!(loadFlags & loadActiveRegionsFlag))
507 		error("Active Regions not loaded");
508 
509 	ExtendedSavegameHeader header;
510 	if (MetaEngine::readSavegameHeader(in, &header)) {
511 		g_vm->setTotalPlayTime(header.playtime * 1000);
512 	}
513 
514 	delete in;
515 
516 	resumeTimer();
517 }
518 
loadGame(int16 saveNo)519 void loadGame(int16 saveNo) {
520 	disableUserControls();
521 	cleanupGameState();
522 	fadeDown();
523 	loadSavedGameState(saveNo);
524 	if (GameMode::newmodeFlag)
525 		GameMode::update();
526 	updateActiveRegions();
527 	enableUserControls();
528 	updateMainDisplay();
529 	drawMainDisplay();
530 	enablePaletteChanges();
531 	updateAllUserControls();
532 	fadeUp();
533 	reDrawScreen();
534 }
535 
536 //----------------------------------------------------------------------
537 //	Cleanup the game state
538 
cleanupGameState(void)539 void cleanupGameState(void) {
540 	cleanupContainerNodes();
541 	cleanupPaletteState();
542 	cleanupUIState();
543 	cleanupAutoMap();
544 	cleanupSpellState();
545 	cleanupTileModeState();
546 	cleanupFactionTallies();
547 	cleanupMissions();
548 	cleanupTempActorCount();
549 	cleanupSensors();
550 	cleanupTimers();
551 	cleanupActiveRegions();
552 	cleanupSpeechTasks();
553 	cleanupTileTasks();
554 	cleanupTasks();
555 	cleanupTaskStacks();
556 	cleanupMotionTasks();
557 	cleanupSAGAThreads();
558 	cleanupSAGADataSeg();
559 	cleanupTileCyclingStates();
560 	cleanupActiveItemStates();
561 	cleanupCenterActor();
562 	cleanupPlayerActors();
563 	cleanupBands();
564 	cleanupObjects();
565 	cleanupActors();
566 	cleanupWorlds();
567 	cleanupGlobals();
568 }
569 
570 //#define DEBUG_FILETIME
571 
572 #ifdef DEBUG_FILETIME
573 #include <time.h>
574 #endif
575 
checkRestartGame(const char * exeName)576 void checkRestartGame(const char *exeName) {
577 	Common::String saveRestart = g_vm->getSavegameFile(999);
578 	g_vm->saveGameState(999, saveRestart, true);
579 }
580 
581 
loadRestartGame(void)582 void loadRestartGame(void) {
583 	loadSavedGameState(999);
584 }
585 
586 } // end of namespace Saga2
587