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