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  * along 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 
23 #include "graphics/thumbnail.h"
24 
25 #include "hdb/hdb.h"
26 #include "hdb/ai.h"
27 #include "hdb/gfx.h"
28 #include "hdb/lua-script.h"
29 #include "hdb/map.h"
30 #include "hdb/sound.h"
31 #include "hdb/window.h"
32 
33 namespace HDB {
34 
canSaveGameStateCurrently()35 bool HDBGame::canSaveGameStateCurrently() {
36 	return (_gameState == GAME_PLAY && !_ai->cinematicsActive());
37 }
38 
saveGameState(int slot,const Common::String & desc,bool isAutosave)39 Common::Error HDBGame::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
40 
41 	// If no map is loaded, don't try to save
42 	if (!g_hdb->_map->isLoaded())
43 		return Common::kCreatingFileFailed;
44 
45 	// If it is autosave, push down all saves
46 	if (slot == 0) {
47 		Common::String nameFrom;
48 		Common::String nameTo;
49 		for (int i = kNumSaveSlots - 2; i >= 0; i--) {
50 			nameFrom = genSaveFileName(i, false);
51 			nameTo = genSaveFileName(i + 1, false);
52 			_saveFileMan->renameSavefile(nameFrom, nameTo);
53 
54 			nameFrom = genSaveFileName(i, true);
55 			nameTo = genSaveFileName(i + 1, true);
56 			_saveFileMan->renameSavefile(nameFrom, nameTo);
57 		}
58 	}
59 
60 	Common::OutSaveFile *out;
61 
62 	Common::String saveFileName = genSaveFileName(slot, false);
63 	if (!(out = _saveFileMan->openForSaving(saveFileName)))
64 		error("Unable to open save file");
65 
66 	Graphics::saveThumbnail(*out);
67 
68 	_saveHeader.fileSlot = 0;
69 	Common::strlcpy(_saveHeader.saveID, saveFileName.c_str(), sizeof(_saveHeader.saveID));
70 	_saveHeader.seconds = _timeSeconds + (_timePlayed / 1000);
71 	Common::strlcpy(_saveHeader.mapName, _inMapName, sizeof(_saveHeader.mapName));
72 
73 	// Actual Save Data
74 	saveGame(out);
75 	_lua->save(out);
76 
77 	out->finalize();
78 	if (out->err())
79 		warning("Can't write file '%s'. (Disk full?)", saveFileName.c_str());
80 
81 	delete out;
82 
83 	return Common::kNoError;
84 }
85 
canLoadGameStateCurrently()86 bool HDBGame::canLoadGameStateCurrently() {
87 	return _gameState == GAME_PLAY;
88 }
89 
loadGameState(int slot)90 Common::Error HDBGame::loadGameState(int slot) {
91 	Common::InSaveFile *in;
92 
93 	Common::String saveFileName = genSaveFileName(slot, false);
94 	if (!(in = _saveFileMan->openForLoading(saveFileName))) {
95 		warning("missing savegame file %s", saveFileName.c_str());
96 		if (g_hdb->_map->isLoaded())
97 			g_hdb->setGameState(GAME_PLAY);
98 		return Common::kReadingFailed;
99 	}
100 
101 	_window->closeAll();
102 
103 	Graphics::skipThumbnail(*in);
104 
105 	// Actual Save Data
106 	loadGame(in);
107 
108 	_lua->loadLua(_currentLuaName); // load the Lua code FIRST! (if no file, it's ok)
109 
110 	_lua->loadSaveFile(in);
111 
112 	delete in;
113 
114 	// center the player on the screen
115 	int x, y;
116 	_ai->getPlayerXY(&x, &y);
117 	_map->centerMapXY(x + 16, y + 16);
118 
119 	if (!_ai->cinematicsActive())
120 		_gfx->turnOffFade();
121 
122 	debug(7, "Action List Info:");
123 	for (int k = 0; k < 20; k++) {
124 		debug(7, "Action %d: entityName: %s", k, _ai->_actions[k].entityName);
125 		debug(7, "Action %d: x1: %d, y1: %d", k, _ai->_actions[k].x1, _ai->_actions[k].y1);
126 		debug(7, "Action %d: x2: %d, y2: %d", k, _ai->_actions[k].x2, _ai->_actions[k].y2);
127 		debug(7, "Action %d: luaFuncInit: %s, luaFuncUse: %s", k, _ai->_actions[k].luaFuncInit, _ai->_actions[k].luaFuncUse);
128 	}
129 
130 	return Common::kNoError;
131 }
132 
saveGame(Common::OutSaveFile * out)133 void HDBGame::saveGame(Common::OutSaveFile *out) {
134 	debug(1, "HDBGame::saveGame: start at %u", (uint32)out->pos());
135 
136 	// Save Map Name and Time
137 	out->writeUint32LE(_saveHeader.seconds);
138 	out->write(_inMapName, 32);
139 
140 	debug(1, "HDBGame::saveGame: map at %u", (uint32)out->pos());
141 	// Save Map Object Data
142 	_map->save(out);
143 
144 	// Save Window Object Data
145 	debug(1, "HDBGame::saveGame: window at %u", (uint32)out->pos());
146 	_window->save(out);
147 
148 	// Save Gfx Object Data
149 	debug(1, "HDBGame::saveGame: gfx at %u", (uint32)out->pos());
150 	_gfx->save(out);
151 
152 	// Save Sound Object Data
153 	debug(1, "HDBGame::saveGame: sound at %u", (uint32)out->pos());
154 	_sound->save(out);
155 
156 	// Save Game Object Data
157 	debug(1, "HDBGame::saveGame: game object at %u", (uint32)out->pos());
158 	save(out);
159 
160 	// Save AI Object Data
161 	debug(1, "HDBGame::saveGame: ai at %u", (uint32)out->pos());
162 	_ai->save(out);
163 
164 	debug(1, "HDBGame::saveGame: end at %u", (uint32)out->pos());
165 }
166 
loadGame(Common::InSaveFile * in)167 void HDBGame::loadGame(Common::InSaveFile *in) {
168 	debug(1, "HDBGame::loadGame: start at %u", (uint32)in->pos());
169 
170 	// Load Map Name and Time
171 	_timeSeconds = in->readUint32LE();
172 	_timePlayed = 0;
173 	in->read(_inMapName, 32);
174 
175 	g_hdb->_sound->stopMusic();
176 	_saveHeader.seconds = _timeSeconds;
177 	Common::strlcpy(_saveHeader.mapName, _inMapName, sizeof(_saveHeader.mapName));
178 
179 	// Load Map Object Data
180 	debug(1, "HDBGame::loadGame: map at %u", (uint32)in->pos());
181 	_map->loadSaveFile(in);
182 
183 	// Load Window Object Data
184 	debug(1, "HDBGame::loadGame: window at %u", (uint32)in->pos());
185 	_window->loadSaveFile(in);
186 
187 	// Load Gfx Object Data
188 	debug(1, "HDBGame::loadGame: gfx at %u", (uint32)in->pos());
189 	_gfx->loadSaveFile(in);
190 
191 	// Load Sound Object Data
192 	debug(1, "HDBGame::loadGame: sound at %u", (uint32)in->pos());
193 	_sound->loadSaveFile(in);
194 
195 	// Load Game Object Data
196 	debug(1, "HDBGame::loadGame: game object at %u", (uint32)in->pos());
197 	loadSaveFile(in);
198 
199 	// Load AI Object Data
200 	debug(1, "HDBGame::loadGame: ai at %u", (uint32)in->pos());
201 	_ai->loadSaveFile(in);
202 
203 	debug(1, "HDBGame::loadGame: end at %u", (uint32)in->pos());
204 
205 	_gfx->turnOffFade();
206 }
207 
save(Common::OutSaveFile * out)208 void HDBGame::save(Common::OutSaveFile *out) {
209 	out->write(_currentMapname, 64);
210 	out->write(_lastMapname, 64);
211 	out->write(_currentLuaName, 64);
212 	out->writeSint32LE(_actionMode);
213 	out->writeByte(_changeLevel);
214 	out->write(_changeMapname, 64);
215 	out->write(_inMapName, 32);
216 }
217 
loadSaveFile(Common::InSaveFile * in)218 void HDBGame::loadSaveFile(Common::InSaveFile *in) {
219 	in->read(_currentMapname, 64);
220 
221 	debug(0, "Loading map %s", _currentMapname);
222 
223 	in->read(_lastMapname, 64);
224 	in->read(_currentLuaName, 64);
225 	_actionMode = in->readSint32LE();
226 	_changeLevel = in->readByte();
227 	in->read(_changeMapname, 64);
228 	in->read(_inMapName, 32);
229 }
230 
save(Common::OutSaveFile * out)231 void AIEntity::save(Common::OutSaveFile *out) {
232 	char funcString[32];
233 	const char *lookUp;
234 
235 
236 	// Write out 32-char names for the function ptrs we have in the entity struct
237 	lookUp = g_hdb->_ai->funcLookUp(aiAction);
238 	memset(&funcString, 0, 32);
239 	if (!lookUp && aiAction)
240 		error("AIEntity::save: No matching ACTION function for func-string for %s entity", AIType2Str(type));
241 	if (lookUp)
242 		strncpy(funcString, lookUp, 31);
243 	out->write(funcString, 32);
244 
245 	lookUp = g_hdb->_ai->funcLookUp(aiUse);
246 	memset(&funcString, 0, 32);
247 	if (!lookUp && aiUse)
248 		error("AIEntity::save: No matching USE function for func-string for %s entity", AIType2Str(type));
249 	if (lookUp)
250 		strncpy(funcString, lookUp, 31);
251 	out->write(funcString, 32);
252 
253 	lookUp = g_hdb->_ai->funcLookUp(aiInit);
254 	memset(&funcString, 0, 32);
255 	if (!lookUp && aiInit)
256 		error("AIEntity::save: No matching INIT function for func-string for %s entity", AIType2Str(type));
257 	if (lookUp)
258 		strncpy(funcString, lookUp, 31);
259 	out->write(funcString, 32);
260 
261 	lookUp = g_hdb->_ai->funcLookUp(aiInit2);
262 	memset(&funcString, 0, 32);
263 	if (!lookUp && aiInit2)
264 		error("AIEntity::save: No matching INIT2 function for func-string for %s entity", AIType2Str(type));
265 	if (lookUp)
266 		strncpy(funcString, lookUp, 31);
267 	out->write(funcString, 32);
268 
269 	lookUp = g_hdb->_ai->funcLookUp((FuncPtr)aiDraw);
270 	memset(&funcString, 0, 32);
271 	if (!lookUp && aiDraw)
272 		error("AIEntity::save: No matching DRAW function for func-string for %s entity", AIType2Str(type));
273 	if (lookUp)
274 		strncpy(funcString, lookUp, 31);
275 	out->write(funcString, 32);
276 
277 	// Save AIEntity
278 	out->writeSint32LE((int)type);
279 	out->writeSint32LE((int)state);
280 	out->writeSint32LE((int)dir);
281 	out->write(luaFuncInit, 32);
282 	out->write(luaFuncAction, 32);
283 	out->write(luaFuncUse, 32);
284 	out->writeUint16LE(level);
285 	out->writeUint16LE(value1);
286 	out->writeUint16LE(value2);
287 	out->writeSint32LE((int)dir2);
288 	out->writeUint16LE(x);
289 	out->writeUint16LE(y);
290 	out->writeSint16LE(drawXOff);
291 	out->writeSint16LE(drawYOff);
292 	out->writeUint16LE(onScreen);
293 	out->writeUint16LE(moveSpeed);
294 	out->writeSint16LE(xVel);
295 	out->writeSint16LE(yVel);
296 	out->writeUint16LE(tileX);
297 	out->writeUint16LE(tileY);
298 	out->writeUint16LE(goalX);
299 	out->writeUint16LE(goalY);
300 	out->writeUint16LE(touchpX);
301 	out->writeUint16LE(touchpY);
302 	out->writeUint16LE(touchpTile);
303 	out->writeUint16LE(touchpWait);
304 	out->writeUint16LE(stunnedWait);
305 	out->writeSint16LE(sequence);
306 	out->write(entityName, 32);
307 	out->write(printedName, 32);
308 	out->writeUint16LE(animFrame);
309 	out->writeUint16LE(animDelay);
310 	out->writeUint16LE(animCycle);
311 }
312 
load(Common::InSaveFile * in)313 void AIEntity::load(Common::InSaveFile *in) {
314 	char funcString[32];
315 	FuncPtr init, init2, use, action;
316 	EntFuncPtr drawf;
317 
318 	action = init = init2 = use = nullptr;
319 	drawf = nullptr;
320 
321 	// Read 32-char names for the function ptrs we have in entity struct
322 	in->read(funcString, 32);
323 	if (funcString[0])
324 		action = g_hdb->_ai->funcLookUp(funcString);
325 
326 	in->read(funcString, 32);
327 	if (funcString[0])
328 		use = g_hdb->_ai->funcLookUp(funcString);
329 
330 	in->read(funcString, 32);
331 	if (funcString[0])
332 		init = g_hdb->_ai->funcLookUp(funcString);
333 
334 	in->read(funcString, 32);
335 	if (funcString[0])
336 		init2 = g_hdb->_ai->funcLookUp(funcString);
337 
338 	in->read(funcString, 32);
339 	if (funcString[0])
340 		drawf = (EntFuncPtr)g_hdb->_ai->funcLookUp(funcString);
341 
342 	// Load AIEntity
343 	type = (AIType)in->readSint32LE();
344 	state = (AIState)in->readSint32LE();
345 	dir = (AIDir)in->readSint32LE();
346 	in->read(luaFuncInit, 32);
347 	in->read(luaFuncAction, 32);
348 	in->read(luaFuncUse, 32);
349 	level = in->readUint16LE();
350 	value1 = in->readUint16LE();
351 	value2 = in->readUint16LE();
352 	dir2 = (AIDir)in->readSint32LE();
353 	x = in->readUint16LE();
354 	y = in->readUint16LE();
355 	drawXOff = in->readSint16LE();
356 	drawYOff = in->readSint16LE();
357 	onScreen = in->readUint16LE();
358 	moveSpeed = in->readUint16LE();
359 	xVel = in->readSint16LE();
360 	yVel = in->readSint16LE();
361 	tileX = in->readUint16LE();
362 	tileY = in->readUint16LE();
363 	goalX = in->readUint16LE();
364 	goalY = in->readUint16LE();
365 	touchpX = in->readUint16LE();
366 	touchpY = in->readUint16LE();
367 	touchpTile = in->readUint16LE();
368 	touchpWait = in->readUint16LE();
369 	stunnedWait = in->readUint16LE();
370 	sequence = in->readSint16LE();
371 	in->read(entityName, 32);
372 	in->read(printedName, 32);
373 	animFrame = in->readUint16LE();
374 	animDelay = in->readUint16LE();
375 	animCycle = in->readUint16LE();
376 
377 	aiAction = action;
378 	aiInit = init;
379 	aiInit2 = init2;
380 	aiUse = use;
381 	aiDraw = drawf;
382 }
383 
genSaveFileName(uint slot,bool lua)384 Common::String HDBGame::genSaveFileName(uint slot, bool lua) {
385 	if (!lua)
386 		return Common::String::format("%s.%03d", _targetName.c_str(), slot);
387 
388 	return Common::String::format("%s.l.%03d", _targetName.c_str(), slot);
389 }
390 
391 
392 } // End of Namespace
393