1 //----------------------------------------------------------------------------
2 // EDGE New SaveGame Handling (Main)
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2008 The EDGE Team.
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 //----------------------------------------------------------------------------
18 //
19 // See the file "docs/save_sys.txt" for a complete description of the
20 // new savegame system.
21 //
22
23 #include "i_defs.h"
24
25 #include "epi/path.h"
26 #include "epi/str_format.h"
27 #include "epi/filesystem.h"
28
29 #include "dm_state.h"
30 #include "dstrings.h"
31 #include "e_main.h"
32 #include "g_game.h"
33 #include "f_interm.h"
34 #include "m_math.h"
35 #include "m_random.h"
36 #include "p_local.h"
37 #include "p_spec.h"
38 #include "r_state.h"
39 #include "sv_chunk.h"
40 #include "sv_main.h"
41 #include "w_wad.h"
42 #include "z_zone.h"
43
44
45 savestruct_t *sv_known_structs;
46 savearray_t *sv_known_arrays;
47
48 // the current element of an array being read/written
49 void *sv_current_elem;
50
51
52 // sv_mobj.c
53 extern savestruct_t sv_struct_mobj;
54 extern savestruct_t sv_struct_spawnpoint;
55 extern savestruct_t sv_struct_iteminque;
56
57 extern savearray_t sv_array_mobj;
58 extern savearray_t sv_array_iteminque;
59
60 // sv_play.c
61 extern savestruct_t sv_struct_player;
62 extern savestruct_t sv_struct_playerweapon;
63 extern savestruct_t sv_struct_playerammo;
64 extern savestruct_t sv_struct_psprite;
65
66 extern savearray_t sv_array_player;
67
68 // sv_level.c
69 extern savestruct_t sv_struct_surface;
70 extern savestruct_t sv_struct_side;
71 extern savestruct_t sv_struct_line;
72 extern savestruct_t sv_struct_regprops;
73 extern savestruct_t sv_struct_exfloor;
74 extern savestruct_t sv_struct_sector;
75
76 extern savearray_t sv_array_side;
77 extern savearray_t sv_array_line;
78 extern savearray_t sv_array_exfloor;
79 extern savearray_t sv_array_sector;
80
81 // sv_misc.c
82 extern savestruct_t sv_struct_button;
83 extern savestruct_t sv_struct_light;
84 extern savestruct_t sv_struct_trigger;
85 extern savestruct_t sv_struct_drawtip;
86 extern savestruct_t sv_struct_plane_move;
87 extern savestruct_t sv_struct_slider_move;
88
89 extern savearray_t sv_array_button;
90 extern savearray_t sv_array_light;
91 extern savearray_t sv_array_trigger;
92 extern savearray_t sv_array_drawtip;
93 extern savearray_t sv_array_plane_move;
94 extern savearray_t sv_array_slider_move;
95
96
97 //----------------------------------------------------------------------------
98 //
99 // GET ROUTINES
100 //
101
SR_GetByte(void * storage,int index,void * extra)102 bool SR_GetByte(void *storage, int index, void *extra)
103 {
104 ((unsigned char *)storage)[index] = SV_GetByte();
105 return true;
106 }
107
SR_GetShort(void * storage,int index,void * extra)108 bool SR_GetShort(void *storage, int index, void *extra)
109 {
110 ((unsigned short *)storage)[index] = SV_GetShort();
111 return true;
112 }
113
SR_GetInt(void * storage,int index,void * extra)114 bool SR_GetInt(void *storage, int index, void *extra)
115 {
116 ((unsigned int *)storage)[index] = SV_GetInt();
117 return true;
118 }
119
SR_GetAngle(void * storage,int index,void * extra)120 bool SR_GetAngle(void *storage, int index, void *extra)
121 {
122 ((angle_t *)storage)[index] = SV_GetAngle();
123 return true;
124 }
125
SR_GetFloat(void * storage,int index,void * extra)126 bool SR_GetFloat(void *storage, int index, void *extra)
127 {
128 ((float *)storage)[index] = SV_GetFloat();
129 return true;
130 }
131
SR_GetBoolean(void * storage,int index,void * extra)132 bool SR_GetBoolean(void *storage, int index, void *extra)
133 {
134 ((bool *)storage)[index] = SV_GetInt() ? true : false;
135 return true;
136 }
137
SR_GetVec2(void * storage,int index,void * extra)138 bool SR_GetVec2(void *storage, int index, void *extra)
139 {
140 ((vec2_t *)storage)[index].x = SV_GetFloat();
141 ((vec2_t *)storage)[index].y = SV_GetFloat();
142 return true;
143 }
144
SR_GetVec3(void * storage,int index,void * extra)145 bool SR_GetVec3(void *storage, int index, void *extra)
146 {
147 ((vec3_t *)storage)[index].x = SV_GetFloat();
148 ((vec3_t *)storage)[index].y = SV_GetFloat();
149 ((vec3_t *)storage)[index].z = SV_GetFloat();
150 return true;
151 }
152
SR_GetFloatFromInt(void * storage,int index,void * extra)153 bool SR_GetFloatFromInt(void *storage, int index, void *extra)
154 {
155 ((float *)storage)[index] = (float)SV_GetInt();
156 return true;
157 }
158
159 //
160 // For backwards compatibility with old savegames, keep the mlook angle
161 // stored in the savegame file as a slope. Because we forbid looking
162 // directly up and down, there is no problem with infinity.
163 //
SR_GetAngleFromSlope(void * storage,int index,void * extra)164 bool SR_GetAngleFromSlope(void *storage, int index, void *extra)
165 {
166 ((angle_t *)storage)[index] = M_ATan(SV_GetFloat());
167 return true;
168 }
169
170
171 //----------------------------------------------------------------------------
172 //
173 // COMMON PUT ROUTINES
174 //
175
SR_PutByte(void * storage,int index,void * extra)176 void SR_PutByte(void *storage, int index, void *extra)
177 {
178 SV_PutByte(((unsigned char *)storage)[index]);
179 }
180
SR_PutShort(void * storage,int index,void * extra)181 void SR_PutShort(void *storage, int index, void *extra)
182 {
183 SV_PutShort(((unsigned short *)storage)[index]);
184 }
185
SR_PutInt(void * storage,int index,void * extra)186 void SR_PutInt(void *storage, int index, void *extra)
187 {
188 SV_PutInt(((unsigned int *)storage)[index]);
189 }
190
SR_PutAngle(void * storage,int index,void * extra)191 void SR_PutAngle(void *storage, int index, void *extra)
192 {
193 SV_PutAngle(((angle_t *)storage)[index]);
194 }
195
SR_PutFloat(void * storage,int index,void * extra)196 void SR_PutFloat(void *storage, int index, void *extra)
197 {
198 SV_PutFloat(((float *)storage)[index]);
199 }
200
SR_PutBoolean(void * storage,int index,void * extra)201 void SR_PutBoolean(void *storage, int index, void *extra)
202 {
203 SV_PutInt(((bool *)storage)[index] ? 1 : 0);
204 }
205
SR_PutVec2(void * storage,int index,void * extra)206 void SR_PutVec2(void *storage, int index, void *extra)
207 {
208 SV_PutFloat(((vec2_t *)storage)[index].x);
209 SV_PutFloat(((vec2_t *)storage)[index].y);
210 }
211
SR_PutVec3(void * storage,int index,void * extra)212 void SR_PutVec3(void *storage, int index, void *extra)
213 {
214 SV_PutFloat(((vec3_t *)storage)[index].x);
215 SV_PutFloat(((vec3_t *)storage)[index].y);
216 SV_PutFloat(((vec3_t *)storage)[index].z);
217 }
218
SR_PutAngleToSlope(void * storage,int index,void * extra)219 void SR_PutAngleToSlope(void *storage, int index, void *extra)
220 {
221 angle_t val = ((angle_t *)storage)[index];
222
223 SYS_ASSERT(val < ANG90 || val > ANG270);
224
225 SV_PutFloat(M_Tan(val));
226 }
227
228
229 //----------------------------------------------------------------------------
230 //
231 // ADMININISTRATION
232 //
233
AddKnownStruct(savestruct_t * S)234 static void AddKnownStruct(savestruct_t *S)
235 {
236 S->next = sv_known_structs;
237 sv_known_structs = S;
238 }
239
AddKnownArray(savearray_t * A)240 static void AddKnownArray(savearray_t *A)
241 {
242 A->next = sv_known_arrays;
243 sv_known_arrays = A;
244 }
245
246
SV_MainInit(void)247 void SV_MainInit(void)
248 {
249 // One-time initialisation. Sets up lists of known structures
250 // and arrays.
251
252 SV_ChunkInit();
253
254 // sv_mobj.c
255 AddKnownStruct(&sv_struct_mobj);
256 AddKnownStruct(&sv_struct_spawnpoint);
257 AddKnownStruct(&sv_struct_iteminque);
258
259 AddKnownArray(&sv_array_mobj);
260 AddKnownArray(&sv_array_iteminque);
261
262 // sv_play.c
263 AddKnownStruct(&sv_struct_player);
264 AddKnownStruct(&sv_struct_playerweapon);
265 AddKnownStruct(&sv_struct_playerammo);
266 AddKnownStruct(&sv_struct_psprite);
267
268 AddKnownArray(&sv_array_player);
269
270 // sv_level.c
271 AddKnownStruct(&sv_struct_surface);
272 AddKnownStruct(&sv_struct_side);
273 AddKnownStruct(&sv_struct_line);
274 AddKnownStruct(&sv_struct_regprops);
275 AddKnownStruct(&sv_struct_exfloor);
276 AddKnownStruct(&sv_struct_sector);
277
278 AddKnownArray(&sv_array_side);
279 AddKnownArray(&sv_array_line);
280 AddKnownArray(&sv_array_exfloor);
281 AddKnownArray(&sv_array_sector);
282
283 // sv_misc.c
284 AddKnownStruct(&sv_struct_button);
285 AddKnownStruct(&sv_struct_light);
286 AddKnownStruct(&sv_struct_trigger);
287 AddKnownStruct(&sv_struct_drawtip);
288 AddKnownStruct(&sv_struct_plane_move);
289 AddKnownStruct(&sv_struct_slider_move);
290
291 AddKnownArray(&sv_array_button);
292 AddKnownArray(&sv_array_light);
293 AddKnownArray(&sv_array_trigger);
294 AddKnownArray(&sv_array_drawtip);
295 AddKnownArray(&sv_array_plane_move);
296 AddKnownArray(&sv_array_slider_move);
297 }
298
SV_MainLookupStruct(const char * name)299 savestruct_t *SV_MainLookupStruct(const char *name)
300 {
301 savestruct_t *cur;
302
303 for (cur=sv_known_structs; cur; cur=cur->next)
304 if (strcmp(cur->struct_name, name) == 0)
305 return cur;
306
307 // not found
308 return NULL;
309 }
310
SV_MainLookupArray(const char * name)311 savearray_t *SV_MainLookupArray(const char *name)
312 {
313 savearray_t *cur;
314
315 for (cur=sv_known_arrays; cur; cur=cur->next)
316 if (strcmp(cur->array_name, name) == 0)
317 return cur;
318
319 // not found
320 return NULL;
321 }
322
323 //----------------------------------------------------------------------------
324 //
325 // TEST CODE
326 //
327
328 #if 0
329 void SV_MainTestPrimitives(void)
330 {
331 int i;
332 int version;
333
334 if (! SV_OpenWriteFile("savegame/prim.tst", 0x7654))
335 I_Error("SV_MainTestPrimitives: couldn't create output\n");
336
337 SV_PutByte(0x00);
338 SV_PutByte(0x55);
339 SV_PutByte(0xAA);
340 SV_PutByte(0xFF);
341
342 SV_PutShort(0x0000);
343 SV_PutShort(0x4567);
344 SV_PutShort(0xCDEF);
345 SV_PutShort(0xFFFF);
346
347 SV_PutInt(0x00000000);
348 SV_PutInt(0x11223344);
349 SV_PutInt(0xbbccddee);
350 SV_PutInt(0xffffffff);
351
352 SV_PutAngle(ANG1);
353 SV_PutAngle(ANG45);
354 SV_PutAngle(ANG135);
355 SV_PutAngle(ANG180);
356 SV_PutAngle(ANG270);
357 SV_PutAngle(ANG315);
358 SV_PutAngle(0 - ANG1);
359
360 SV_PutFloat(0.0f);
361 SV_PutFloat(0.001f); SV_PutFloat(-0.001f);
362 SV_PutFloat(0.1f); SV_PutFloat(-0.1f);
363 SV_PutFloat(0.25f); SV_PutFloat(-0.25f);
364 SV_PutFloat(1.0f); SV_PutFloat(-1.0f);
365 SV_PutFloat(2.0f); SV_PutFloat(-2.0f);
366 SV_PutFloat(3.1416f); SV_PutFloat(-3.1416f);
367 SV_PutFloat(1000.0f); SV_PutFloat(-1000.0f);
368 SV_PutFloat(1234567890.0f);
369 SV_PutFloat(-1234567890.0f);
370
371 SV_PutString(NULL);
372 SV_PutString("");
373 SV_PutString("A");
374 SV_PutString("123");
375 SV_PutString("HELLO world !");
376
377 SV_PutMarker("ABCD");
378 SV_PutMarker("xyz3");
379
380 SV_CloseWriteFile();
381
382 // ------------------------------------------------------------ //
383
384 if (! SV_OpenReadFile("savegame/prim.tst"))
385 I_Error("SV_MainTestPrimitives: couldn't open input\n");
386
387 if (! SV_VerifyHeader(&version))
388 I_Error("SV_MainTestPrimitives: couldn't open input\n");
389
390 L_WriteDebug("TEST HEADER: version=0x%04x\n", version);
391
392 for (i=0; i < 4; i++)
393 {
394 unsigned int val = SV_GetByte();
395 L_WriteDebug("TEST BYTE: 0x%02x %d\n", val, (char) val);
396 }
397
398 for (i=0; i < 4; i++)
399 {
400 unsigned int val = SV_GetShort();
401 L_WriteDebug("TEST SHORT: 0x%02x %d\n", val, (short) val);
402 }
403
404 for (i=0; i < 4; i++)
405 {
406 unsigned int val = SV_GetInt();
407 L_WriteDebug("TEST INT: 0x%02x %d\n", val, (int) val);
408 }
409
410 for (i=0; i < 7; i++)
411 {
412 angle_t val = SV_GetAngle();
413 L_WriteDebug("TEST ANGLE: 0x%08x = %1.6f\n", (unsigned int) val,
414 ANG_2_FLOAT(val));
415 }
416
417 for (i=0; i < 17; i++)
418 {
419 float val = SV_GetFloat();
420 L_WriteDebug("TEST FLOAT: %1.6f\n", val);
421 }
422
423 for (i=0; i < 5; i++)
424 {
425 const char *val = SV_GetString();
426 L_WriteDebug("TEST STRING: [%s]\n", val ? val : "--NULL--");
427 SV_FreeString(val);
428 }
429
430 for (i=0; i < 2; i++)
431 {
432 char val[6];
433 SV_GetMarker(val);
434 L_WriteDebug("TEST MARKER: [%s]\n", val);
435 }
436
437 SV_CloseReadFile();
438 }
439
440 #endif // TEST CODE
441
442
443 //----------------------------------------------------------------------------
444
SV_SlotName(int slot)445 const char *SV_SlotName(int slot)
446 {
447 SYS_ASSERT(slot < 1000);
448
449 static char buffer[256];
450
451 sprintf(buffer, "slot%03d", slot);
452
453 return buffer;
454 }
455
SV_MapName(const mapdef_c * map)456 const char *SV_MapName(const mapdef_c *map)
457 {
458 // ensure the name is LOWER CASE
459 static char buffer[256];
460
461 strcpy(buffer, map->name.c_str());
462
463 for (char *pos = buffer; *pos; pos++)
464 *pos = tolower(*pos);
465
466 return buffer;
467 }
468
SV_FileName(const char * slot_name,const char * map_name)469 std::string SV_FileName(const char *slot_name, const char *map_name)
470 {
471 std::string temp(epi::STR_Format("%s/%s.%s", slot_name, map_name, SAVEGAMEEXT));
472
473 return epi::PATH_Join(save_dir.c_str(), temp.c_str());
474 }
475
SV_DirName(const char * slot_name)476 std::string SV_DirName(const char *slot_name)
477 {
478 return epi::PATH_Join(save_dir.c_str(), slot_name);
479 }
480
SV_ClearSlot(const char * slot_name)481 void SV_ClearSlot(const char *slot_name)
482 {
483 std::string full_dir = SV_DirName(slot_name);
484
485 // make sure the directory exists
486 epi::FS_MakeDir(full_dir.c_str());
487
488 epi::filesystem_dir_c fsd;
489
490 if (! FS_ReadDir(&fsd, full_dir.c_str(), "*.esg"))
491 {
492 I_Warning("Failed to read directory: %s\n", full_dir.c_str());
493 return;
494 }
495
496 I_Debugf("SV_ClearSlot: removing %d files\n", fsd.GetSize());
497
498 for (int i = 0; i < fsd.GetSize(); i++)
499 {
500 epi::filesys_direntry_c *entry = fsd[i];
501
502 if (entry->is_dir)
503 continue;
504
505 std::string cur_file = epi::PATH_Join(full_dir.c_str(), entry->name.c_str());
506
507 I_Debugf(" Deleting %s\n", cur_file.c_str());
508
509 epi::FS_Delete(cur_file.c_str());
510 }
511 }
512
SV_CopySlot(const char * src_name,const char * dest_name)513 void SV_CopySlot(const char *src_name, const char *dest_name)
514 {
515 std::string src_dir = SV_DirName(src_name);
516 std::string dest_dir = SV_DirName(dest_name);
517
518 epi::filesystem_dir_c fsd;
519
520 if (! FS_ReadDir(&fsd, src_dir.c_str(), "*.esg"))
521 {
522 I_Error("SV_CopySlot: failed to read dir: %s\n", src_dir.c_str());
523 return;
524 }
525
526 I_Debugf("SV_CopySlot: copying %d files\n", fsd.GetSize());
527
528 for (int i = 0; i < fsd.GetSize(); i++)
529 {
530 epi::filesys_direntry_c *entry = fsd[i];
531
532 if (entry->is_dir)
533 continue;
534
535 std::string src_file = epi::PATH_Join( src_dir.c_str(), entry->name.c_str());
536 std::string dest_file = epi::PATH_Join(dest_dir.c_str(), entry->name.c_str());
537
538 I_Debugf(" Copying %s --> %s\n", src_file.c_str(), dest_file.c_str());
539
540 if (! epi::FS_Copy(src_file.c_str(), dest_file.c_str()))
541 I_Error("SV_CopySlot: failed to copy '%s' to '%s'\n",
542 src_file.c_str(), dest_file.c_str());
543 }
544 }
545
546 //--- editor settings ---
547 // vi:ts=4:sw=4:noexpandtab
548