1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include "loadSave.h"
23
initSaveSlots()24 void initSaveSlots()
25 {
26 char filename[PATH_MAX];
27 char string[100];
28 struct stat fileInfo;
29 int modTime = 0;
30
31 Game tempGame;
32
33 engine.continueSaveSlot = 0;
34
35 FILE *fp;
36
37 //READ SAVE GAME DATA
38 for (int i = 0 ; i < 5 ; i++)
39 {
40 snprintf(filename, sizeof filename, "%ssave%d.dat", engine.userHomeDirectory, i);
41
42 fp = fopen(filename, "rb");
43
44 if (!fp)
45 {
46 strlcpy(string, "%.2d - %s", sizeof string);
47 snprintf(engine.saveSlot[i], sizeof engine.saveSlot[i], string, (i + 1), _("Empty"));
48 }
49 else
50 {
51 if (fread(&tempGame, sizeof(Game), 1, fp) != 1)
52 {
53 strlcpy(string, "%.2d - %s", sizeof string);
54 snprintf(engine.saveSlot[i], sizeof engine.saveSlot[i], string, (i + 1), _("Corrupt Save Data"));
55 }
56 else
57 {
58 snprintf(engine.saveSlot[i], sizeof engine.saveSlot[i], "%.2d - %s (%.2d:%.2d:%.2d)", (i + 1), _(tempGame.stageName), tempGame.totalHours, tempGame.totalMinutes, tempGame.totalSeconds);
59 }
60
61 if (stat(filename, &fileInfo) != -1)
62 {
63 if (fileInfo.st_mtime > modTime)
64 {
65 modTime = fileInfo.st_mtime;
66 engine.continueSaveSlot = (i + 1);
67 }
68 }
69
70 fclose(fp);
71 }
72 }
73
74 debug(("Continue Save Slot = %d\n", engine.continueSaveSlot));
75 }
76
77 /*
78 Fill in later...
79 */
loadGame(int slot)80 bool loadGame(int slot)
81 {
82 debug(("Loading Game #%d...\n", slot));
83 game.clear();
84
85 SDL_Delay(500);
86 char filename[PATH_MAX];
87
88 char line[1024];
89 char string[2][1024];
90 int param[2];
91
92 Data *data;
93
94 FILE *fp;
95
96 int sanity = 0;
97
98 snprintf(filename, sizeof filename, "%ssave%d.dat", engine.userHomeDirectory, slot);
99
100 fp = fopen(filename, "rb");
101
102 if (!fp)
103 {
104 return false;
105 }
106
107 if (fread(&game, sizeof(Game), 1, fp) != 1)
108 {
109 fclose(fp);
110 return graphics.showErrorAndExit("The save data loaded was not in the format expected", ""), false;
111 }
112
113 fclose(fp);
114
115 snprintf(filename, sizeof filename, "%spersistant%d.dat", engine.userHomeDirectory, slot);
116
117 fp = fopen(filename, "rb");
118
119 if (!fp)
120 {
121 return false;
122 }
123
124 while (true)
125 {
126 if (!fgets(line, 1024, fp)) {
127 fclose(fp);
128 return graphics.showErrorAndExit("Unexpected end of file reading save data", ""), false;
129 }
130
131 sscanf(line, "%*c %[^\"] %*c %*c %[^\"] %*c %d %d", string[0], string[1], ¶m[0], ¶m[1]);
132
133 data = new Data();
134
135 data->set(string[0], string[1], param[0], param[1]);
136
137 debug(("Read %s %s %d %d\n", data->key, data->value, data->current, data->target));
138
139 if ((data->current == -1) && (data->target == -1))
140 {
141 delete data;
142 break;
143 }
144
145 gameData.addCompletedObjective(data);
146
147 sanity++;
148
149 if (sanity == 10000)
150 {
151 debug(("Sanity Check #1 > 10000!\n"));
152 fclose(fp);
153 exit(1);
154 }
155 }
156
157 sanity = 0;
158
159 char stageName[50];
160 int numberOfLines = 0;
161
162 Persistant *persistant;
163 PersistData *persistData;
164
165 while (true)
166 {
167 if (!fgets(line, 1024, fp)) {
168 fclose(fp);
169 graphics.showErrorAndExit("Unexpected end of file reading save data", "");
170 }
171
172 sscanf(line, "%[^\n\r]", string[0]);
173 strlcpy(stageName, string[0], sizeof stageName);
174
175 if (strcmp(stageName, "@EOF@") == 0)
176 {
177 break;
178 }
179
180 if (!fgets(line, 1024, fp)) {
181 fclose(fp);
182 graphics.showErrorAndExit("Unexpected end of file reading save data", "");
183 }
184 sscanf(line, "%d", &numberOfLines);
185
186 debug(("Read %s with %d lines.\n", stageName, numberOfLines));
187
188 persistant = map.createPersistant(stageName);
189
190 for (int i = 0 ; i < numberOfLines ; i++)
191 {
192 persistData = new PersistData();
193
194 if (!fgets(line, 1024, fp)) {
195 fclose(fp);
196 graphics.showErrorAndExit("Unexpected end of file reading save data", "");
197 }
198
199 strlcpy(persistData->data, line, sizeof persistData->data);
200
201 //debug(("Read %d: %s", i, persistData->data));
202
203 persistant->addLine(persistData->data);
204
205 sanity++;
206
207 if (sanity == 100000)
208 {
209 debug(("Sanity Check #2 > 100000!\n"));
210 fclose(fp);
211 exit(1);
212 }
213 }
214 }
215
216 fclose(fp);
217
218 debug(("Loaded Successfully\n"));
219
220 return true;
221 }
222
confirmSave()223 int confirmSave()
224 {
225 if (game.autoSave)
226 {
227 return game.autoSaveSlot;
228 }
229
230 if (!engine.loadWidgets("data/saveWidgets"))
231 graphics.showErrorAndExit(ERR_FILE, "data/saveWidgets");
232
233 int slot[6], quitYes, quitNo;
234 slot[0] = slot[1] = slot[2] = slot[3] = slot[4] = slot[5] = 0;
235 quitYes = quitNo = 0;
236
237 engine.setWidgetVariable("slot1", &slot[0]);
238 engine.setWidgetVariable("slot2", &slot[1]);
239 engine.setWidgetVariable("slot3", &slot[2]);
240 engine.setWidgetVariable("slot4", &slot[3]);
241 engine.setWidgetVariable("slot5", &slot[4]);
242 engine.setWidgetVariable("slot6", &slot[5]);
243
244 engine.setWidgetVariable("contyes", &quitYes);
245 engine.setWidgetVariable("contno", &quitNo);
246
247 char widgetName[10];
248 widgetName[0] = 0;
249
250 for (int i = 0 ; i < 5 ; i++)
251 {
252 snprintf(widgetName, sizeof widgetName, "slot%d", i + 1);
253 strlcpy(engine.getWidgetByName(widgetName)->label, engine.saveSlot[i], sizeof engine.getWidgetByName(widgetName)->label);
254 }
255
256 engine.highlightWidget("slot1");
257
258 int menuSound = 0;
259
260 int rtn = -1;
261
262 engine.showWidgetGroup("gameSlots", true);
263 engine.showWidgetGroup("continueconf", false);
264
265 graphics.setFontSize(4);
266 SDL_Surface *title = graphics.quickSprite("savetitle", graphics.getString("Save Game", true));
267
268 while (true)
269 {
270 graphics.updateScreen();
271 SDL_FillRect(graphics.screen, NULL, graphics.black);
272 engine.getInput();
273 config.populate();
274
275 menuSound = engine.processWidgets();
276
277 if (menuSound)
278 audio.playMenuSound(menuSound);
279
280 graphics.blit(title, 320, 100, graphics.screen, true);
281
282 drawWidgets();
283
284 if (slot[5])
285 {
286 engine.showWidgetGroup("gameSlots", false);
287 engine.showWidgetGroup("continueconf", true);
288 engine.highlightWidget("contno");
289 drawWidgets();
290 slot[5] = 0;
291 }
292
293 if (quitYes)
294 {
295 break;
296 }
297
298 if (quitNo)
299 {
300 engine.showWidgetGroup("gameSlots", true);
301 engine.showWidgetGroup("continueconf", false);
302 engine.highlightWidget("slot1");
303 drawWidgets();
304 quitNo = 0;
305 }
306
307 for (int i = 0 ; i < 5 ; i++)
308 {
309 if (slot[i])
310 {
311 rtn = i;
312 }
313 }
314
315 if ((slot[0]) || (slot[1]) || (slot[2]) || (slot[3]) || (slot[4]) || (slot[5]))
316 {
317 break;
318 }
319
320 SDL_Delay(16);
321 }
322
323 SDL_FillRect(graphics.screen, NULL, graphics.black);
324 graphics.updateScreen();
325 SDL_Delay(250);
326
327 return rtn;
328 }
329
saveGame()330 void saveGame()
331 {
332 char message[256];
333
334 SDL_FillRect(graphics.screen, NULL, graphics.black);
335 graphics.updateScreen();
336 SDL_Delay(500);
337
338 int slot = confirmSave();
339
340 if (slot == -1)
341 return;
342
343 graphics.setFontSize(1);
344 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
345 snprintf(message, sizeof message, _("Saving Game to Save Slot #%d. Please Wait..."), slot + 1);
346 graphics.drawString(message, 320, 220, true, graphics.screen);
347 graphics.updateScreen();
348
349 char filename[PATH_MAX];
350
351 FILE *fp;
352
353 snprintf(filename, sizeof filename, "%ssave%d.dat", engine.userHomeDirectory, slot);
354
355 fp = fopen(filename, "wb");
356
357 if (!fp)
358 {
359 return graphics.showErrorAndExit("File write error whilst saving game", "");
360 }
361
362 if (fwrite(&game, sizeof(Game), 1, fp) != 1)
363 {
364 fclose(fp);
365 return graphics.showErrorAndExit("File write error whilst saving game", strerror(errno));
366 }
367
368 fclose(fp);
369
370 snprintf(filename, sizeof filename, "%spersistant%d.dat", engine.userHomeDirectory, slot);
371
372 fp = fopen(filename, "wt");
373
374 if (!fp)
375 {
376 return graphics.showErrorAndExit("File write error whilst saving game", "");
377 }
378
379 createPersistantMapData();
380
381 Data *data = (Data*)gameData.dataList.getHead();
382
383 while (data->next != NULL)
384 {
385 data = (Data*)data->next;
386
387 fprintf(fp, "\"%s\" \"%s\" %d %d\n", data->key, data->value, data->current, data->target);
388 }
389
390 fprintf(fp, "\"@EOF@\" \"@EOF@\" -1 -1\n");
391
392 Persistant *persistant = (Persistant*)map.persistantList.getHead();
393 PersistData *persistData;
394
395 while (persistant->next != NULL)
396 {
397 persistant = (Persistant*)persistant->next;
398
399 if (strcmp(persistant->stageName, "@none@") == 0)
400 {
401 continue;
402 }
403
404 fprintf(fp, "%s\n", persistant->stageName);
405 fprintf(fp, "%d\n", persistant->numberOfLines);
406
407 persistData = (PersistData*)persistant->dataList.getHead();
408
409 while (persistData->next != NULL)
410 {
411 persistData = (PersistData*)persistData->next;
412
413 fprintf(fp, "%s", persistData->data);
414 }
415 }
416
417 fprintf(fp, "@EOF@\n");
418
419 fclose(fp);
420
421 map.clear();
422
423 SDL_Delay(500);
424
425 graphics.drawString(_("Save Complete"), 320, 260, true, graphics.screen);
426 graphics.updateScreen();
427
428 SDL_Delay(500);
429 }
430