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], &param[0], &param[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