rnd-20030704-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * files.c                                                  *
12 ***********************************************************/
13
14 #include <ctype.h>
15 #include <sys/stat.h>
16
17 #include "libgame/libgame.h"
18
19 #include "files.h"
20 #include "init.h"
21 #include "tools.h"
22 #include "tape.h"
23
24
25 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
26 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
27 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
28 #define FILE_VERS_CHUNK_SIZE    8       /* size of file version chunk */
29 #define LEVEL_HEADER_SIZE       80      /* size of level file header  */
30 #define LEVEL_HEADER_UNUSED     13      /* unused level header bytes  */
31 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
32 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
33 #define LEVEL_CPART_CUS3_SIZE   134     /* size of CUS3 chunk part    */
34 #define LEVEL_CPART_CUS3_UNUSED 16      /* unused CUS3 bytes / part   */
35 #define TAPE_HEADER_SIZE        20      /* size of tape file header   */
36 #define TAPE_HEADER_UNUSED      3       /* unused tape header bytes   */
37
38 #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + x * LEVEL_CPART_CUS3_SIZE)
39
40 /* file identifier strings */
41 #define LEVEL_COOKIE_TMPL       "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
42 #define TAPE_COOKIE_TMPL        "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
43 #define SCORE_COOKIE            "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
44
45
46 /* ========================================================================= */
47 /* level file functions                                                      */
48 /* ========================================================================= */
49
50 static void setLevelInfoToDefaults()
51 {
52   int i, j, x, y;
53
54   level.file_version = FILE_VERSION_ACTUAL;
55   level.game_version = GAME_VERSION_ACTUAL;
56
57   level.encoding_16bit_field = FALSE;   /* default: only 8-bit elements */
58   level.encoding_16bit_yamyam = FALSE;  /* default: only 8-bit elements */
59   level.encoding_16bit_amoeba = FALSE;  /* default: only 8-bit elements */
60
61   lev_fieldx = level.fieldx = STD_LEV_FIELDX;
62   lev_fieldy = level.fieldy = STD_LEV_FIELDY;
63
64   for(x=0; x<MAX_LEV_FIELDX; x++)
65     for(y=0; y<MAX_LEV_FIELDY; y++)
66       Feld[x][y] = Ur[x][y] = EL_SAND;
67
68   level.time = 100;
69   level.gems_needed = 0;
70   level.amoeba_speed = 10;
71   level.time_magic_wall = 10;
72   level.time_wheel = 10;
73   level.time_light = 10;
74   level.time_timegate = 10;
75   level.amoeba_content = EL_DIAMOND;
76   level.double_speed = FALSE;
77   level.gravity = FALSE;
78   level.em_slippery_gems = FALSE;
79
80   level.use_custom_template = FALSE;
81
82   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
83     level.name[i] = '\0';
84   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
85     level.author[i] = '\0';
86
87   strcpy(level.name, NAMELESS_LEVEL_NAME);
88   strcpy(level.author, ANONYMOUS_NAME);
89
90   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
91     level.score[i] = 10;
92
93   level.num_yamyam_contents = STD_ELEMENT_CONTENTS;
94   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
95     for(x=0; x<3; x++)
96       for(y=0; y<3; y++)
97         level.yamyam_content[i][x][y] =
98           (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
99
100   Feld[0][0] = Ur[0][0] = EL_PLAYER_1;
101   Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
102     Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
103
104   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
105   {
106     int element = EL_CUSTOM_START + i;
107
108     for(j=0; j<MAX_ELEMENT_NAME_LEN + 1; j++)
109       element_info[element].description[j] = '\0';
110     if (element_info[element].custom_description != NULL)
111       strncpy(element_info[element].description,
112               element_info[element].custom_description, MAX_ELEMENT_NAME_LEN);
113     else
114       strcpy(element_info[element].description,
115              element_info[element].editor_description);
116
117     element_info[element].use_gfx_element = FALSE;
118     element_info[element].gfx_element = EL_EMPTY_SPACE;
119
120     element_info[element].score = 0;
121     element_info[element].gem_count = 0;
122
123     element_info[element].push_delay_fixed = 2;         /* special default */
124     element_info[element].push_delay_random = 8;        /* special default */
125     element_info[element].move_delay_fixed = 0;
126     element_info[element].move_delay_random = 0;
127
128     element_info[element].move_pattern = MV_ALL_DIRECTIONS;
129     element_info[element].move_direction_initial = MV_NO_MOVING;
130     element_info[element].move_stepsize = TILEX / 8;
131
132     for(x=0; x<3; x++)
133       for(y=0; y<3; y++)
134         element_info[element].content[x][y] = EL_EMPTY_SPACE;
135
136     element_info[element].change.events = CE_BITMASK_DEFAULT;
137     element_info[element].change.target_element = EL_EMPTY_SPACE;
138
139     element_info[element].change.delay_fixed = 0;
140     element_info[element].change.delay_random = 0;
141     element_info[element].change.delay_frames = -1;     /* use default */
142
143     element_info[element].change.trigger_element = EL_EMPTY_SPACE;
144
145     element_info[element].change.explode = FALSE;
146     element_info[element].change.use_content = FALSE;
147     element_info[element].change.only_complete = FALSE;
148     element_info[element].change.use_random_change = FALSE;
149     element_info[element].change.random = 0;
150     element_info[element].change.power = CP_NON_DESTRUCTIVE;
151
152     for(x=0; x<3; x++)
153       for(y=0; y<3; y++)
154         element_info[element].change.content[x][y] = EL_EMPTY_SPACE;
155
156     element_info[element].access_type = 0;
157     element_info[element].access_layer = 0;
158     element_info[element].walk_to_action = 0;
159     element_info[element].smash_targets = 0;
160     element_info[element].deadliness = 0;
161     element_info[element].consistency = 0;
162     element_info[element].change_player_action = 0;
163     element_info[element].change_collide_action = 0;
164     element_info[element].change_other_action = 0;
165
166     element_info[element].can_explode_by_fire = FALSE;
167     element_info[element].can_explode_smashed = FALSE;
168     element_info[element].can_explode_impact = FALSE;
169
170     /* start with no properties at all */
171     for (j=0; j < NUM_EP_BITFIELDS; j++)
172       Properties[element][j] = EP_BITMASK_DEFAULT;
173   }
174
175   BorderElement = EL_STEELWALL;
176
177   level.no_level_file = FALSE;
178
179   if (leveldir_current == NULL)         /* only when dumping level */
180     return;
181
182   /* try to determine better author name than 'anonymous' */
183   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
184   {
185     strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
186     level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
187   }
188   else
189   {
190     switch (LEVELCLASS(leveldir_current))
191     {
192       case LEVELCLASS_TUTORIAL:
193         strcpy(level.author, PROGRAM_AUTHOR_STRING);
194         break;
195
196       case LEVELCLASS_CONTRIBUTION:
197         strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
198         level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
199         break;
200
201       case LEVELCLASS_USER:
202         strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
203         level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
204         break;
205
206       default:
207         /* keep default value */
208         break;
209     }
210   }
211 }
212
213 static int checkLevelElement(int element)
214 {
215   if (element >= NUM_FILE_ELEMENTS)
216   {
217     Error(ERR_WARN, "invalid level element %d", element);
218     element = EL_CHAR_QUESTION;
219   }
220   else if (element == EL_PLAYER_OBSOLETE)
221     element = EL_PLAYER_1;
222   else if (element == EL_KEY_OBSOLETE)
223     element = EL_KEY_1;
224
225   return element;
226 }
227
228 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
229 {
230   level->file_version = getFileVersion(file);
231   level->game_version = getFileVersion(file);
232
233   return chunk_size;
234 }
235
236 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
237 {
238   int i, x, y;
239
240   lev_fieldx = level->fieldx = fgetc(file);
241   lev_fieldy = level->fieldy = fgetc(file);
242
243   level->time           = getFile16BitBE(file);
244   level->gems_needed    = getFile16BitBE(file);
245
246   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
247     level->name[i] = fgetc(file);
248   level->name[MAX_LEVEL_NAME_LEN] = 0;
249
250   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
251     level->score[i] = fgetc(file);
252
253   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
254   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
255     for(y=0; y<3; y++)
256       for(x=0; x<3; x++)
257         level->yamyam_content[i][x][y] = checkLevelElement(fgetc(file));
258
259   level->amoeba_speed           = fgetc(file);
260   level->time_magic_wall        = fgetc(file);
261   level->time_wheel             = fgetc(file);
262   level->amoeba_content         = checkLevelElement(fgetc(file));
263   level->double_speed           = (fgetc(file) == 1 ? TRUE : FALSE);
264   level->gravity                = (fgetc(file) == 1 ? TRUE : FALSE);
265   level->encoding_16bit_field   = (fgetc(file) == 1 ? TRUE : FALSE);
266   level->em_slippery_gems       = (fgetc(file) == 1 ? TRUE : FALSE);
267
268   level->use_custom_template    = (fgetc(file) == 1 ? TRUE : FALSE);
269
270   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
271
272   return chunk_size;
273 }
274
275 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
276 {
277   int i;
278
279   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
280     level->author[i] = fgetc(file);
281   level->author[MAX_LEVEL_NAME_LEN] = 0;
282
283   return chunk_size;
284 }
285
286 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
287 {
288   int x, y;
289   int chunk_size_expected = level->fieldx * level->fieldy;
290
291   /* Note: "chunk_size" was wrong before version 2.0 when elements are
292      stored with 16-bit encoding (and should be twice as big then).
293      Even worse, playfield data was stored 16-bit when only yamyam content
294      contained 16-bit elements and vice versa. */
295
296   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
297     chunk_size_expected *= 2;
298
299   if (chunk_size_expected != chunk_size)
300   {
301     ReadUnusedBytesFromFile(file, chunk_size);
302     return chunk_size_expected;
303   }
304
305   for(y=0; y<level->fieldy; y++)
306     for(x=0; x<level->fieldx; x++)
307       Feld[x][y] = Ur[x][y] =
308         checkLevelElement(level->encoding_16bit_field ?
309                           getFile16BitBE(file) : fgetc(file));
310   return chunk_size;
311 }
312
313 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
314 {
315   int i, x, y;
316   int header_size = 4;
317   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
318   int chunk_size_expected = header_size + content_size;
319
320   /* Note: "chunk_size" was wrong before version 2.0 when elements are
321      stored with 16-bit encoding (and should be twice as big then).
322      Even worse, playfield data was stored 16-bit when only yamyam content
323      contained 16-bit elements and vice versa. */
324
325   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
326     chunk_size_expected += content_size;
327
328   if (chunk_size_expected != chunk_size)
329   {
330     ReadUnusedBytesFromFile(file, chunk_size);
331     return chunk_size_expected;
332   }
333
334   fgetc(file);
335   level->num_yamyam_contents = fgetc(file);
336   fgetc(file);
337   fgetc(file);
338
339   /* correct invalid number of content fields -- should never happen */
340   if (level->num_yamyam_contents < 1 ||
341       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
342     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
343
344   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
345     for(y=0; y<3; y++)
346       for(x=0; x<3; x++)
347         level->yamyam_content[i][x][y] =
348           checkLevelElement(level->encoding_16bit_field ?
349                             getFile16BitBE(file) : fgetc(file));
350   return chunk_size;
351 }
352
353 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
354 {
355   int i, x, y;
356   int element;
357   int num_contents, content_xsize, content_ysize;
358   int content_array[MAX_ELEMENT_CONTENTS][3][3];
359
360   element = checkLevelElement(getFile16BitBE(file));
361   num_contents = fgetc(file);
362   content_xsize = fgetc(file);
363   content_ysize = fgetc(file);
364   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
365
366   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
367     for(y=0; y<3; y++)
368       for(x=0; x<3; x++)
369         content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
370
371   /* correct invalid number of content fields -- should never happen */
372   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
373     num_contents = STD_ELEMENT_CONTENTS;
374
375   if (element == EL_YAMYAM)
376   {
377     level->num_yamyam_contents = num_contents;
378
379     for(i=0; i<num_contents; i++)
380       for(y=0; y<3; y++)
381         for(x=0; x<3; x++)
382           level->yamyam_content[i][x][y] = content_array[i][x][y];
383   }
384   else if (element == EL_BD_AMOEBA)
385   {
386     level->amoeba_content = content_array[0][0][0];
387   }
388   else
389   {
390     Error(ERR_WARN, "cannot load content for element '%d'", element);
391   }
392
393   return chunk_size;
394 }
395
396 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
397 {
398   int num_changed_custom_elements = getFile16BitBE(file);
399   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
400   int i;
401
402   if (chunk_size_expected != chunk_size)
403   {
404     ReadUnusedBytesFromFile(file, chunk_size - 2);
405     return chunk_size_expected;
406   }
407
408   for (i=0; i < num_changed_custom_elements; i++)
409   {
410     int element = getFile16BitBE(file);
411     int properties = getFile32BitBE(file);
412
413     if (IS_CUSTOM_ELEMENT(element))
414       Properties[element][EP_BITFIELD_BASE] = properties;
415     else
416       Error(ERR_WARN, "invalid custom element number %d", element);
417   }
418
419   return chunk_size;
420 }
421
422 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
423 {
424   int num_changed_custom_elements = getFile16BitBE(file);
425   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
426   int i;
427
428   if (chunk_size_expected != chunk_size)
429   {
430     ReadUnusedBytesFromFile(file, chunk_size - 2);
431     return chunk_size_expected;
432   }
433
434   for (i=0; i < num_changed_custom_elements; i++)
435   {
436     int element = getFile16BitBE(file);
437     int custom_target_element = getFile16BitBE(file);
438
439     if (IS_CUSTOM_ELEMENT(element))
440       element_info[element].change.target_element = custom_target_element;
441     else
442       Error(ERR_WARN, "invalid custom element number %d", element);
443   }
444
445   return chunk_size;
446 }
447
448 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
449 {
450   int num_changed_custom_elements = getFile16BitBE(file);
451   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
452   int i, j, x, y;
453
454   if (chunk_size_expected != chunk_size)
455   {
456     ReadUnusedBytesFromFile(file, chunk_size - 2);
457     return chunk_size_expected;
458   }
459
460   for (i=0; i < num_changed_custom_elements; i++)
461   {
462     int element = getFile16BitBE(file);
463
464     if (!IS_CUSTOM_ELEMENT(element))
465     {
466       Error(ERR_WARN, "invalid custom element number %d", element);
467
468       element = EL_DEFAULT;     /* dummy element used for artwork config */
469     }
470
471     for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
472       element_info[element].description[j] = getFile8Bit(file);
473     element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
474
475     Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
476
477     /* some free bytes for future properties and padding */
478     ReadUnusedBytesFromFile(file, 7);
479
480     element_info[element].use_gfx_element = getFile8Bit(file);
481     element_info[element].gfx_element =
482       checkLevelElement(getFile16BitBE(file));
483
484     element_info[element].score = getFile8Bit(file);
485     element_info[element].gem_count = getFile8Bit(file);
486
487     element_info[element].push_delay_fixed = getFile16BitBE(file);
488     element_info[element].push_delay_random = getFile16BitBE(file);
489     element_info[element].move_delay_fixed = getFile16BitBE(file);
490     element_info[element].move_delay_random = getFile16BitBE(file);
491
492     element_info[element].move_pattern = getFile16BitBE(file);
493     element_info[element].move_direction_initial = getFile8Bit(file);
494     element_info[element].move_stepsize = getFile8Bit(file);
495
496     for(y=0; y<3; y++)
497       for(x=0; x<3; x++)
498         element_info[element].content[x][y] =
499           checkLevelElement(getFile16BitBE(file));
500
501     element_info[element].change.events = getFile32BitBE(file);
502
503     element_info[element].change.target_element =
504       checkLevelElement(getFile16BitBE(file));
505
506     element_info[element].change.delay_fixed = getFile16BitBE(file);
507     element_info[element].change.delay_random = getFile16BitBE(file);
508     element_info[element].change.delay_frames = getFile16BitBE(file);
509
510     element_info[element].change.trigger_element =
511       checkLevelElement(getFile16BitBE(file));
512
513     element_info[element].change.explode = getFile8Bit(file);
514     element_info[element].change.use_content = getFile8Bit(file);
515     element_info[element].change.only_complete = getFile8Bit(file);
516     element_info[element].change.use_random_change = getFile8Bit(file);
517
518     element_info[element].change.random = getFile8Bit(file);
519     element_info[element].change.power = getFile8Bit(file);
520
521     for(y=0; y<3; y++)
522       for(x=0; x<3; x++)
523         element_info[element].change.content[x][y] =
524           checkLevelElement(getFile16BitBE(file));
525
526     /* some free bytes for future properties and padding */
527     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
528   }
529
530   return chunk_size;
531 }
532
533 void LoadLevelFromFilename(char *filename)
534 {
535   char cookie[MAX_LINE_LEN];
536   char chunk_name[CHUNK_ID_LEN + 1];
537   int chunk_size;
538   FILE *file;
539
540   /* always start with reliable default values */
541   setLevelInfoToDefaults();
542
543   if (!(file = fopen(filename, MODE_READ)))
544   {
545     level.no_level_file = TRUE;
546
547     Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
548     return;
549   }
550
551   getFileChunkBE(file, chunk_name, NULL);
552   if (strcmp(chunk_name, "RND1") == 0)
553   {
554     getFile32BitBE(file);               /* not used */
555
556     getFileChunkBE(file, chunk_name, NULL);
557     if (strcmp(chunk_name, "CAVE") != 0)
558     {
559       Error(ERR_WARN, "unknown format of level file '%s'", filename);
560       fclose(file);
561       return;
562     }
563   }
564   else  /* check for pre-2.0 file format with cookie string */
565   {
566     strcpy(cookie, chunk_name);
567     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
568     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
569       cookie[strlen(cookie) - 1] = '\0';
570
571     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
572     {
573       Error(ERR_WARN, "unknown format of level file '%s'", filename);
574       fclose(file);
575       return;
576     }
577
578     if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
579     {
580       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
581       fclose(file);
582       return;
583     }
584
585     /* pre-2.0 level files have no game version, so use file version here */
586     level.game_version = level.file_version;
587   }
588
589   if (level.file_version < FILE_VERSION_1_2)
590   {
591     /* level files from versions before 1.2.0 without chunk structure */
592     LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,           &level);
593     LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
594   }
595   else
596   {
597     static struct
598     {
599       char *name;
600       int size;
601       int (*loader)(FILE *, int, struct LevelInfo *);
602     }
603     chunk_info[] =
604     {
605       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadLevel_VERS },
606       { "HEAD", LEVEL_HEADER_SIZE,      LoadLevel_HEAD },
607       { "AUTH", MAX_LEVEL_AUTHOR_LEN,   LoadLevel_AUTH },
608       { "BODY", -1,                     LoadLevel_BODY },
609       { "CONT", -1,                     LoadLevel_CONT },
610       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
611       { "CUS1", -1,                     LoadLevel_CUS1 },
612       { "CUS2", -1,                     LoadLevel_CUS2 },
613       { "CUS3", -1,                     LoadLevel_CUS3 },
614       {  NULL,  0,                      NULL }
615     };
616
617     while (getFileChunkBE(file, chunk_name, &chunk_size))
618     {
619       int i = 0;
620
621       while (chunk_info[i].name != NULL &&
622              strcmp(chunk_name, chunk_info[i].name) != 0)
623         i++;
624
625       if (chunk_info[i].name == NULL)
626       {
627         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
628               chunk_name, filename);
629         ReadUnusedBytesFromFile(file, chunk_size);
630       }
631       else if (chunk_info[i].size != -1 &&
632                chunk_info[i].size != chunk_size)
633       {
634         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
635               chunk_size, chunk_name, filename);
636         ReadUnusedBytesFromFile(file, chunk_size);
637       }
638       else
639       {
640         /* call function to load this level chunk */
641         int chunk_size_expected =
642           (chunk_info[i].loader)(file, chunk_size, &level);
643
644         /* the size of some chunks cannot be checked before reading other
645            chunks first (like "HEAD" and "BODY") that contain some header
646            information, so check them here */
647         if (chunk_size_expected != chunk_size)
648         {
649           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
650                 chunk_size, chunk_name, filename);
651         }
652       }
653     }
654   }
655
656   fclose(file);
657
658   if (leveldir_current == NULL)         /* only when dumping level */
659     return;
660
661   if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
662       IS_LEVELCLASS_USER(leveldir_current))
663   {
664     /* For user contributed and private levels, use the version of
665        the game engine the levels were created for.
666        Since 2.0.1, the game engine version is now directly stored
667        in the level file (chunk "VERS"), so there is no need anymore
668        to set the game version from the file version (except for old,
669        pre-2.0 levels, where the game version is still taken from the
670        file format version used to store the level -- see above). */
671
672     /* do some special adjustments to support older level versions */
673     if (level.file_version == FILE_VERSION_1_0)
674     {
675       Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
676       Error(ERR_WARN, "using high speed movement for player");
677
678       /* player was faster than monsters in (pre-)1.0 levels */
679       level.double_speed = TRUE;
680     }
681
682     /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
683     if (level.game_version == VERSION_IDENT(2,0,1))
684       level.em_slippery_gems = TRUE;
685   }
686   else
687   {
688     /* Always use the latest version of the game engine for all but
689        user contributed and private levels; this allows for actual
690        corrections in the game engine to take effect for existing,
691        converted levels (from "classic" or other existing games) to
692        make the game emulation more accurate, while (hopefully) not
693        breaking existing levels created from other players. */
694
695     level.game_version = GAME_VERSION_ACTUAL;
696
697     /* Set special EM style gems behaviour: EM style gems slip down from
698        normal, steel and growing wall. As this is a more fundamental change,
699        it seems better to set the default behaviour to "off" (as it is more
700        natural) and make it configurable in the level editor (as a property
701        of gem style elements). Already existing converted levels (neither
702        private nor contributed levels) are changed to the new behaviour. */
703
704     if (level.file_version < FILE_VERSION_2_0)
705       level.em_slippery_gems = TRUE;
706   }
707
708   /* map some elements which have changed in newer versions */
709   if (level.game_version <= VERSION_IDENT(2,2,0))
710   {
711     int x, y;
712
713     /* map game font elements */
714     for(y=0; y<level.fieldy; y++)
715     {
716       for(x=0; x<level.fieldx; x++)
717       {
718         int element = Ur[x][y];
719
720         if (element == EL_CHAR('['))
721           element = EL_CHAR_AUMLAUT;
722         else if (element == EL_CHAR('\\'))
723           element = EL_CHAR_OUMLAUT;
724         else if (element == EL_CHAR(']'))
725           element = EL_CHAR_UUMLAUT;
726         else if (element == EL_CHAR('^'))
727           element = EL_CHAR_COPYRIGHT;
728
729         Feld[x][y] = Ur[x][y] = element;
730       }
731     }
732   }
733
734   /* determine border element for this level */
735   SetBorderElement();
736 }
737
738 void LoadLevel(int level_nr)
739 {
740   char *filename = getLevelFilename(level_nr);
741
742   LoadLevelFromFilename(filename);
743   InitElementPropertiesEngine(level.game_version);
744 }
745
746 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
747 {
748   putFileVersion(file, level->file_version);
749   putFileVersion(file, level->game_version);
750 }
751
752 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
753 {
754   int i, x, y;
755
756   fputc(level->fieldx, file);
757   fputc(level->fieldy, file);
758
759   putFile16BitBE(file, level->time);
760   putFile16BitBE(file, level->gems_needed);
761
762   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
763     fputc(level->name[i], file);
764
765   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
766     fputc(level->score[i], file);
767
768   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
769     for(y=0; y<3; y++)
770       for(x=0; x<3; x++)
771         fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
772                level->yamyam_content[i][x][y]),
773               file);
774   fputc(level->amoeba_speed, file);
775   fputc(level->time_magic_wall, file);
776   fputc(level->time_wheel, file);
777   fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
778         file);
779   fputc((level->double_speed ? 1 : 0), file);
780   fputc((level->gravity ? 1 : 0), file);
781   fputc((level->encoding_16bit_field ? 1 : 0), file);
782   fputc((level->em_slippery_gems ? 1 : 0), file);
783
784   fputc((level->use_custom_template ? 1 : 0), file);
785
786   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
787 }
788
789 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
790 {
791   int i;
792
793   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
794     fputc(level->author[i], file);
795 }
796
797 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
798 {
799   int x, y;
800
801   for(y=0; y<level->fieldy; y++) 
802     for(x=0; x<level->fieldx; x++) 
803       if (level->encoding_16bit_field)
804         putFile16BitBE(file, Ur[x][y]);
805       else
806         fputc(Ur[x][y], file);
807 }
808
809 #if 0
810 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
811 {
812   int i, x, y;
813
814   fputc(EL_YAMYAM, file);
815   fputc(level->num_yamyam_contents, file);
816   fputc(0, file);
817   fputc(0, file);
818
819   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
820     for(y=0; y<3; y++)
821       for(x=0; x<3; x++)
822         if (level->encoding_16bit_field)
823           putFile16BitBE(file, level->yamyam_content[i][x][y]);
824         else
825           fputc(level->yamyam_content[i][x][y], file);
826 }
827 #endif
828
829 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
830 {
831   int i, x, y;
832   int num_contents, content_xsize, content_ysize;
833   int content_array[MAX_ELEMENT_CONTENTS][3][3];
834
835   if (element == EL_YAMYAM)
836   {
837     num_contents = level->num_yamyam_contents;
838     content_xsize = 3;
839     content_ysize = 3;
840
841     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
842       for(y=0; y<3; y++)
843         for(x=0; x<3; x++)
844           content_array[i][x][y] = level->yamyam_content[i][x][y];
845   }
846   else if (element == EL_BD_AMOEBA)
847   {
848     num_contents = 1;
849     content_xsize = 1;
850     content_ysize = 1;
851
852     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
853       for(y=0; y<3; y++)
854         for(x=0; x<3; x++)
855           content_array[i][x][y] = EL_EMPTY;
856     content_array[0][0][0] = level->amoeba_content;
857   }
858   else
859   {
860     /* chunk header already written -- write empty chunk data */
861     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
862
863     Error(ERR_WARN, "cannot save content for element '%d'", element);
864     return;
865   }
866
867   putFile16BitBE(file, element);
868   fputc(num_contents, file);
869   fputc(content_xsize, file);
870   fputc(content_ysize, file);
871
872   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
873
874   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
875     for(y=0; y<3; y++)
876       for(x=0; x<3; x++)
877         putFile16BitBE(file, content_array[i][x][y]);
878 }
879
880 #if 0
881 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
882                            int num_changed_custom_elements)
883 {
884   int i, check = 0;
885
886   putFile16BitBE(file, num_changed_custom_elements);
887
888   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
889   {
890     int element = EL_CUSTOM_START + i;
891
892     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
893     {
894       if (check < num_changed_custom_elements)
895       {
896         putFile16BitBE(file, element);
897         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
898       }
899
900       check++;
901     }
902   }
903
904   if (check != num_changed_custom_elements)     /* should not happen */
905     Error(ERR_WARN, "inconsistent number of custom element properties");
906 }
907 #endif
908
909 #if 0
910 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
911                            int num_changed_custom_elements)
912 {
913   int i, check = 0;
914
915   putFile16BitBE(file, num_changed_custom_elements);
916
917   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
918   {
919     int element = EL_CUSTOM_START + i;
920
921     if (element_info[element].change.target_element != EL_EMPTY_SPACE)
922     {
923       if (check < num_changed_custom_elements)
924       {
925         putFile16BitBE(file, element);
926         putFile16BitBE(file, element_info[element].change.target_element);
927       }
928
929       check++;
930     }
931   }
932
933   if (check != num_changed_custom_elements)     /* should not happen */
934     Error(ERR_WARN, "inconsistent number of custom target elements");
935 }
936 #endif
937
938 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
939                            int num_changed_custom_elements)
940 {
941   int i, j, x, y, check = 0;
942
943   putFile16BitBE(file, num_changed_custom_elements);
944
945   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
946   {
947     int element = EL_CUSTOM_START + i;
948
949     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
950     {
951       if (check < num_changed_custom_elements)
952       {
953         putFile16BitBE(file, element);
954
955         for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
956           putFile8Bit(file, element_info[element].description[j]);
957
958         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
959
960         /* some free bytes for future properties and padding */
961         WriteUnusedBytesToFile(file, 7);
962
963         putFile8Bit(file, element_info[element].use_gfx_element);
964         putFile16BitBE(file, element_info[element].gfx_element);
965
966         putFile8Bit(file, element_info[element].score);
967         putFile8Bit(file, element_info[element].gem_count);
968
969         putFile16BitBE(file, element_info[element].push_delay_fixed);
970         putFile16BitBE(file, element_info[element].push_delay_random);
971         putFile16BitBE(file, element_info[element].move_delay_fixed);
972         putFile16BitBE(file, element_info[element].move_delay_random);
973
974         putFile16BitBE(file, element_info[element].move_pattern);
975         putFile8Bit(file, element_info[element].move_direction_initial);
976         putFile8Bit(file, element_info[element].move_stepsize);
977
978         for(y=0; y<3; y++)
979           for(x=0; x<3; x++)
980             putFile16BitBE(file, element_info[element].content[x][y]);
981
982         putFile32BitBE(file, element_info[element].change.events);
983
984         putFile16BitBE(file, element_info[element].change.target_element);
985
986         putFile16BitBE(file, element_info[element].change.delay_fixed);
987         putFile16BitBE(file, element_info[element].change.delay_random);
988         putFile16BitBE(file, element_info[element].change.delay_frames);
989
990         putFile16BitBE(file, element_info[element].change.trigger_element);
991
992         putFile8Bit(file, element_info[element].change.explode);
993         putFile8Bit(file, element_info[element].change.use_content);
994         putFile8Bit(file, element_info[element].change.only_complete);
995         putFile8Bit(file, element_info[element].change.use_random_change);
996
997         putFile8Bit(file, element_info[element].change.random);
998         putFile8Bit(file, element_info[element].change.power);
999
1000         for(y=0; y<3; y++)
1001           for(x=0; x<3; x++)
1002             putFile16BitBE(file, element_info[element].change.content[x][y]);
1003
1004         /* some free bytes for future properties and padding */
1005         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
1006       }
1007
1008       check++;
1009     }
1010   }
1011
1012   if (check != num_changed_custom_elements)     /* should not happen */
1013     Error(ERR_WARN, "inconsistent number of custom element properties");
1014 }
1015
1016 void SaveLevel(int level_nr)
1017 {
1018   char *filename = getLevelFilename(level_nr);
1019   int body_chunk_size;
1020   int num_changed_custom_elements = 0;
1021   int level_chunk_CUS3_size;
1022   int i, x, y;
1023   FILE *file;
1024
1025   if (!(file = fopen(filename, MODE_WRITE)))
1026   {
1027     Error(ERR_WARN, "cannot save level file '%s'", filename);
1028     return;
1029   }
1030
1031   level.file_version = FILE_VERSION_ACTUAL;
1032   level.game_version = GAME_VERSION_ACTUAL;
1033
1034   /* check level field for 16-bit elements */
1035   level.encoding_16bit_field = FALSE;
1036   for(y=0; y<level.fieldy; y++) 
1037     for(x=0; x<level.fieldx; x++) 
1038       if (Ur[x][y] > 255)
1039         level.encoding_16bit_field = TRUE;
1040
1041   /* check yamyam content for 16-bit elements */
1042   level.encoding_16bit_yamyam = FALSE;
1043   for(i=0; i<level.num_yamyam_contents; i++)
1044     for(y=0; y<3; y++)
1045       for(x=0; x<3; x++)
1046         if (level.yamyam_content[i][x][y] > 255)
1047           level.encoding_16bit_yamyam = TRUE;
1048
1049   /* check amoeba content for 16-bit elements */
1050   level.encoding_16bit_amoeba = FALSE;
1051   if (level.amoeba_content > 255)
1052     level.encoding_16bit_amoeba = TRUE;
1053
1054   /* calculate size of "BODY" chunk */
1055   body_chunk_size =
1056     level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
1057
1058   /* check for non-standard custom elements and calculate "CUS3" chunk size */
1059   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1060     if (Properties[EL_CUSTOM_START +i][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
1061       num_changed_custom_elements++;
1062   level_chunk_CUS3_size = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
1063
1064   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1065   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
1066
1067   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1068   SaveLevel_VERS(file, &level);
1069
1070   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
1071   SaveLevel_HEAD(file, &level);
1072
1073   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
1074   SaveLevel_AUTH(file, &level);
1075
1076   putFileChunkBE(file, "BODY", body_chunk_size);
1077   SaveLevel_BODY(file, &level);
1078
1079   if (level.encoding_16bit_yamyam ||
1080       level.num_yamyam_contents != STD_ELEMENT_CONTENTS)
1081   {
1082     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1083     SaveLevel_CNT2(file, &level, EL_YAMYAM);
1084   }
1085
1086   if (level.encoding_16bit_amoeba)
1087   {
1088     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1089     SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
1090   }
1091
1092   if (num_changed_custom_elements > 0)
1093   {
1094     putFileChunkBE(file, "CUS3", level_chunk_CUS3_size);
1095     SaveLevel_CUS3(file, &level, num_changed_custom_elements);
1096   }
1097
1098   fclose(file);
1099
1100   SetFilePermissions(filename, PERMS_PRIVATE);
1101 }
1102
1103 void DumpLevel(struct LevelInfo *level)
1104 {
1105   printf_line("-", 79);
1106   printf("Level xxx (file version %08d, game version %08d)\n",
1107          level->file_version, level->game_version);
1108   printf_line("-", 79);
1109
1110   printf("Level Author: '%s'\n", level->author);
1111   printf("Level Title:  '%s'\n", level->name);
1112   printf("\n");
1113   printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
1114   printf("\n");
1115   printf("Level Time:  %d seconds\n", level->time);
1116   printf("Gems needed: %d\n", level->gems_needed);
1117   printf("\n");
1118   printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
1119   printf("Time for Wheel:      %d seconds\n", level->time_wheel);
1120   printf("Time for Light:      %d seconds\n", level->time_light);
1121   printf("Time for Timegate:   %d seconds\n", level->time_timegate);
1122   printf("\n");
1123   printf("Amoeba Speed: %d\n", level->amoeba_speed);
1124   printf("\n");
1125   printf("Gravity:                %s\n", (level->gravity ? "yes" : "no"));
1126   printf("Double Speed Movement:  %s\n", (level->double_speed ? "yes" : "no"));
1127   printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
1128
1129   printf_line("-", 79);
1130 }
1131
1132
1133 /* ========================================================================= */
1134 /* tape file functions                                                       */
1135 /* ========================================================================= */
1136
1137 static void setTapeInfoToDefaults()
1138 {
1139   int i;
1140
1141   /* always start with reliable default values (empty tape) */
1142   TapeErase();
1143
1144   /* default values (also for pre-1.2 tapes) with only the first player */
1145   tape.player_participates[0] = TRUE;
1146   for(i=1; i<MAX_PLAYERS; i++)
1147     tape.player_participates[i] = FALSE;
1148
1149   /* at least one (default: the first) player participates in every tape */
1150   tape.num_participating_players = 1;
1151
1152   tape.level_nr = level_nr;
1153   tape.counter = 0;
1154   tape.changed = FALSE;
1155
1156   tape.recording = FALSE;
1157   tape.playing = FALSE;
1158   tape.pausing = FALSE;
1159 }
1160
1161 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
1162 {
1163   tape->file_version = getFileVersion(file);
1164   tape->game_version = getFileVersion(file);
1165
1166   return chunk_size;
1167 }
1168
1169 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
1170 {
1171   int i;
1172
1173   tape->random_seed = getFile32BitBE(file);
1174   tape->date        = getFile32BitBE(file);
1175   tape->length      = getFile32BitBE(file);
1176
1177   /* read header fields that are new since version 1.2 */
1178   if (tape->file_version >= FILE_VERSION_1_2)
1179   {
1180     byte store_participating_players = fgetc(file);
1181     int engine_version;
1182
1183     /* since version 1.2, tapes store which players participate in the tape */
1184     tape->num_participating_players = 0;
1185     for(i=0; i<MAX_PLAYERS; i++)
1186     {
1187       tape->player_participates[i] = FALSE;
1188
1189       if (store_participating_players & (1 << i))
1190       {
1191         tape->player_participates[i] = TRUE;
1192         tape->num_participating_players++;
1193       }
1194     }
1195
1196     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
1197
1198     engine_version = getFileVersion(file);
1199     if (engine_version > 0)
1200       tape->engine_version = engine_version;
1201   }
1202
1203   return chunk_size;
1204 }
1205
1206 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
1207 {
1208   int level_identifier_size;
1209   int i;
1210
1211   level_identifier_size = getFile16BitBE(file);
1212
1213   tape->level_identifier =
1214     checked_realloc(tape->level_identifier, level_identifier_size);
1215
1216   for(i=0; i < level_identifier_size; i++)
1217     tape->level_identifier[i] = fgetc(file);
1218
1219   tape->level_nr = getFile16BitBE(file);
1220
1221   chunk_size = 2 + level_identifier_size + 2;
1222
1223   return chunk_size;
1224 }
1225
1226 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
1227 {
1228   int i, j;
1229   int chunk_size_expected =
1230     (tape->num_participating_players + 1) * tape->length;
1231
1232   if (chunk_size_expected != chunk_size)
1233   {
1234     ReadUnusedBytesFromFile(file, chunk_size);
1235     return chunk_size_expected;
1236   }
1237
1238   for(i=0; i<tape->length; i++)
1239   {
1240     if (i >= MAX_TAPELEN)
1241       break;
1242
1243     for(j=0; j<MAX_PLAYERS; j++)
1244     {
1245       tape->pos[i].action[j] = MV_NO_MOVING;
1246
1247       if (tape->player_participates[j])
1248         tape->pos[i].action[j] = fgetc(file);
1249     }
1250
1251     tape->pos[i].delay = fgetc(file);
1252
1253     if (tape->file_version == FILE_VERSION_1_0)
1254     {
1255       /* eliminate possible diagonal moves in old tapes */
1256       /* this is only for backward compatibility */
1257
1258       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
1259       byte action = tape->pos[i].action[0];
1260       int k, num_moves = 0;
1261
1262       for (k=0; k<4; k++)
1263       {
1264         if (action & joy_dir[k])
1265         {
1266           tape->pos[i + num_moves].action[0] = joy_dir[k];
1267           if (num_moves > 0)
1268             tape->pos[i + num_moves].delay = 0;
1269           num_moves++;
1270         }
1271       }
1272
1273       if (num_moves > 1)
1274       {
1275         num_moves--;
1276         i += num_moves;
1277         tape->length += num_moves;
1278       }
1279     }
1280     else if (tape->file_version < FILE_VERSION_2_0)
1281     {
1282       /* convert pre-2.0 tapes to new tape format */
1283
1284       if (tape->pos[i].delay > 1)
1285       {
1286         /* action part */
1287         tape->pos[i + 1] = tape->pos[i];
1288         tape->pos[i + 1].delay = 1;
1289
1290         /* delay part */
1291         for(j=0; j<MAX_PLAYERS; j++)
1292           tape->pos[i].action[j] = MV_NO_MOVING;
1293         tape->pos[i].delay--;
1294
1295         i++;
1296         tape->length++;
1297       }
1298     }
1299
1300     if (feof(file))
1301       break;
1302   }
1303
1304   if (i != tape->length)
1305     chunk_size = (tape->num_participating_players + 1) * i;
1306
1307   return chunk_size;
1308 }
1309
1310 void LoadTapeFromFilename(char *filename)
1311 {
1312   char cookie[MAX_LINE_LEN];
1313   char chunk_name[CHUNK_ID_LEN + 1];
1314   FILE *file;
1315   int chunk_size;
1316
1317   /* always start with reliable default values */
1318   setTapeInfoToDefaults();
1319
1320   if (!(file = fopen(filename, MODE_READ)))
1321     return;
1322
1323   getFileChunkBE(file, chunk_name, NULL);
1324   if (strcmp(chunk_name, "RND1") == 0)
1325   {
1326     getFile32BitBE(file);               /* not used */
1327
1328     getFileChunkBE(file, chunk_name, NULL);
1329     if (strcmp(chunk_name, "TAPE") != 0)
1330     {
1331       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1332       fclose(file);
1333       return;
1334     }
1335   }
1336   else  /* check for pre-2.0 file format with cookie string */
1337   {
1338     strcpy(cookie, chunk_name);
1339     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1340     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1341       cookie[strlen(cookie) - 1] = '\0';
1342
1343     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
1344     {
1345       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1346       fclose(file);
1347       return;
1348     }
1349
1350     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
1351     {
1352       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
1353       fclose(file);
1354       return;
1355     }
1356
1357     /* pre-2.0 tape files have no game version, so use file version here */
1358     tape.game_version = tape.file_version;
1359   }
1360
1361   if (tape.file_version < FILE_VERSION_1_2)
1362   {
1363     /* tape files from versions before 1.2.0 without chunk structure */
1364     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
1365     LoadTape_BODY(file, 2 * tape.length,  &tape);
1366   }
1367   else
1368   {
1369     static struct
1370     {
1371       char *name;
1372       int size;
1373       int (*loader)(FILE *, int, struct TapeInfo *);
1374     }
1375     chunk_info[] =
1376     {
1377       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
1378       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
1379       { "INFO", -1,                     LoadTape_INFO },
1380       { "BODY", -1,                     LoadTape_BODY },
1381       {  NULL,  0,                      NULL }
1382     };
1383
1384     while (getFileChunkBE(file, chunk_name, &chunk_size))
1385     {
1386       int i = 0;
1387
1388       while (chunk_info[i].name != NULL &&
1389              strcmp(chunk_name, chunk_info[i].name) != 0)
1390         i++;
1391
1392       if (chunk_info[i].name == NULL)
1393       {
1394         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
1395               chunk_name, filename);
1396         ReadUnusedBytesFromFile(file, chunk_size);
1397       }
1398       else if (chunk_info[i].size != -1 &&
1399                chunk_info[i].size != chunk_size)
1400       {
1401         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1402               chunk_size, chunk_name, filename);
1403         ReadUnusedBytesFromFile(file, chunk_size);
1404       }
1405       else
1406       {
1407         /* call function to load this tape chunk */
1408         int chunk_size_expected =
1409           (chunk_info[i].loader)(file, chunk_size, &tape);
1410
1411         /* the size of some chunks cannot be checked before reading other
1412            chunks first (like "HEAD" and "BODY") that contain some header
1413            information, so check them here */
1414         if (chunk_size_expected != chunk_size)
1415         {
1416           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1417                 chunk_size, chunk_name, filename);
1418         }
1419       }
1420     }
1421   }
1422
1423   fclose(file);
1424
1425   tape.length_seconds = GetTapeLength();
1426
1427 #if 0
1428   printf("tape version: %d\n", tape.game_version);
1429 #endif
1430 }
1431
1432 void LoadTape(int level_nr)
1433 {
1434   char *filename = getTapeFilename(level_nr);
1435
1436   LoadTapeFromFilename(filename);
1437 }
1438
1439 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
1440 {
1441   putFileVersion(file, tape->file_version);
1442   putFileVersion(file, tape->game_version);
1443 }
1444
1445 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
1446 {
1447   int i;
1448   byte store_participating_players = 0;
1449
1450   /* set bits for participating players for compact storage */
1451   for(i=0; i<MAX_PLAYERS; i++)
1452     if (tape->player_participates[i])
1453       store_participating_players |= (1 << i);
1454
1455   putFile32BitBE(file, tape->random_seed);
1456   putFile32BitBE(file, tape->date);
1457   putFile32BitBE(file, tape->length);
1458
1459   fputc(store_participating_players, file);
1460
1461   /* unused bytes not at the end here for 4-byte alignment of engine_version */
1462   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
1463
1464   putFileVersion(file, tape->engine_version);
1465 }
1466
1467 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
1468 {
1469   int level_identifier_size = strlen(tape->level_identifier) + 1;
1470   int i;
1471
1472   putFile16BitBE(file, level_identifier_size);
1473
1474   for(i=0; i < level_identifier_size; i++)
1475     fputc(tape->level_identifier[i], file);
1476
1477   putFile16BitBE(file, tape->level_nr);
1478 }
1479
1480 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
1481 {
1482   int i, j;
1483
1484   for(i=0; i<tape->length; i++)
1485   {
1486     for(j=0; j<MAX_PLAYERS; j++)
1487       if (tape->player_participates[j])
1488         fputc(tape->pos[i].action[j], file);
1489
1490     fputc(tape->pos[i].delay, file);
1491   }
1492 }
1493
1494 void SaveTape(int level_nr)
1495 {
1496   char *filename = getTapeFilename(level_nr);
1497   FILE *file;
1498   boolean new_tape = TRUE;
1499   int num_participating_players = 0;
1500   int info_chunk_size;
1501   int body_chunk_size;
1502   int i;
1503
1504   InitTapeDirectory(leveldir_current->filename);
1505
1506   /* if a tape still exists, ask to overwrite it */
1507   if (access(filename, F_OK) == 0)
1508   {
1509     new_tape = FALSE;
1510     if (!Request("Replace old tape ?", REQ_ASK))
1511       return;
1512   }
1513
1514   if (!(file = fopen(filename, MODE_WRITE)))
1515   {
1516     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1517     return;
1518   }
1519
1520   tape.file_version = FILE_VERSION_ACTUAL;
1521   tape.game_version = GAME_VERSION_ACTUAL;
1522
1523   /* count number of participating players  */
1524   for(i=0; i<MAX_PLAYERS; i++)
1525     if (tape.player_participates[i])
1526       num_participating_players++;
1527
1528   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
1529   body_chunk_size = (num_participating_players + 1) * tape.length;
1530
1531   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1532   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1533
1534   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1535   SaveTape_VERS(file, &tape);
1536
1537   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1538   SaveTape_HEAD(file, &tape);
1539
1540   putFileChunkBE(file, "INFO", info_chunk_size);
1541   SaveTape_INFO(file, &tape);
1542
1543   putFileChunkBE(file, "BODY", body_chunk_size);
1544   SaveTape_BODY(file, &tape);
1545
1546   fclose(file);
1547
1548   SetFilePermissions(filename, PERMS_PRIVATE);
1549
1550   tape.changed = FALSE;
1551
1552   if (new_tape)
1553     Request("tape saved !", REQ_CONFIRM);
1554 }
1555
1556 void DumpTape(struct TapeInfo *tape)
1557 {
1558   int i, j;
1559
1560   if (TAPE_IS_EMPTY(*tape))
1561   {
1562     Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1563     return;
1564   }
1565
1566   printf_line("-", 79);
1567   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
1568          tape->level_nr, tape->file_version, tape->game_version);
1569   printf("Level series identifier: '%s'\n", tape->level_identifier);
1570   printf_line("-", 79);
1571
1572   for(i=0; i<tape->length; i++)
1573   {
1574     if (i >= MAX_TAPELEN)
1575       break;
1576
1577     printf("%03d: ", i);
1578
1579     for(j=0; j<MAX_PLAYERS; j++)
1580     {
1581       if (tape->player_participates[j])
1582       {
1583         int action = tape->pos[i].action[j];
1584
1585         printf("%d:%02x ", j, action);
1586         printf("[%c%c%c%c|%c%c] - ",
1587                (action & JOY_LEFT ? '<' : ' '),
1588                (action & JOY_RIGHT ? '>' : ' '),
1589                (action & JOY_UP ? '^' : ' '),
1590                (action & JOY_DOWN ? 'v' : ' '),
1591                (action & JOY_BUTTON_1 ? '1' : ' '),
1592                (action & JOY_BUTTON_2 ? '2' : ' '));
1593       }
1594     }
1595
1596     printf("(%03d)\n", tape->pos[i].delay);
1597   }
1598
1599   printf_line("-", 79);
1600 }
1601
1602
1603 /* ========================================================================= */
1604 /* score file functions                                                      */
1605 /* ========================================================================= */
1606
1607 void LoadScore(int level_nr)
1608 {
1609   int i;
1610   char *filename = getScoreFilename(level_nr);
1611   char cookie[MAX_LINE_LEN];
1612   char line[MAX_LINE_LEN];
1613   char *line_ptr;
1614   FILE *file;
1615
1616   /* always start with reliable default values */
1617   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1618   {
1619     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1620     highscore[i].Score = 0;
1621   }
1622
1623   if (!(file = fopen(filename, MODE_READ)))
1624     return;
1625
1626   /* check file identifier */
1627   fgets(cookie, MAX_LINE_LEN, file);
1628   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1629     cookie[strlen(cookie) - 1] = '\0';
1630
1631   if (!checkCookieString(cookie, SCORE_COOKIE))
1632   {
1633     Error(ERR_WARN, "unknown format of score file '%s'", filename);
1634     fclose(file);
1635     return;
1636   }
1637
1638   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1639   {
1640     fscanf(file, "%d", &highscore[i].Score);
1641     fgets(line, MAX_LINE_LEN, file);
1642
1643     if (line[strlen(line) - 1] == '\n')
1644       line[strlen(line) - 1] = '\0';
1645
1646     for (line_ptr = line; *line_ptr; line_ptr++)
1647     {
1648       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1649       {
1650         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1651         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1652         break;
1653       }
1654     }
1655   }
1656
1657   fclose(file);
1658 }
1659
1660 void SaveScore(int level_nr)
1661 {
1662   int i;
1663   char *filename = getScoreFilename(level_nr);
1664   FILE *file;
1665
1666   InitScoreDirectory(leveldir_current->filename);
1667
1668   if (!(file = fopen(filename, MODE_WRITE)))
1669   {
1670     Error(ERR_WARN, "cannot save score for level %d", level_nr);
1671     return;
1672   }
1673
1674   fprintf(file, "%s\n\n", SCORE_COOKIE);
1675
1676   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1677     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1678
1679   fclose(file);
1680
1681   SetFilePermissions(filename, PERMS_PUBLIC);
1682 }
1683
1684
1685 /* ========================================================================= */
1686 /* setup file functions                                                      */
1687 /* ========================================================================= */
1688
1689 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
1690
1691 /* global setup */
1692 #define SETUP_TOKEN_PLAYER_NAME                 0
1693 #define SETUP_TOKEN_SOUND                       1
1694 #define SETUP_TOKEN_SOUND_LOOPS                 2
1695 #define SETUP_TOKEN_SOUND_MUSIC                 3
1696 #define SETUP_TOKEN_SOUND_SIMPLE                4
1697 #define SETUP_TOKEN_TOONS                       5
1698 #define SETUP_TOKEN_SCROLL_DELAY                6
1699 #define SETUP_TOKEN_SOFT_SCROLLING              7
1700 #define SETUP_TOKEN_FADING                      8
1701 #define SETUP_TOKEN_AUTORECORD                  9
1702 #define SETUP_TOKEN_QUICK_DOORS                 10
1703 #define SETUP_TOKEN_TEAM_MODE                   11
1704 #define SETUP_TOKEN_HANDICAP                    12
1705 #define SETUP_TOKEN_TIME_LIMIT                  13
1706 #define SETUP_TOKEN_FULLSCREEN                  14
1707 #define SETUP_TOKEN_ASK_ON_ESCAPE               15
1708 #define SETUP_TOKEN_GRAPHICS_SET                16
1709 #define SETUP_TOKEN_SOUNDS_SET                  17
1710 #define SETUP_TOKEN_MUSIC_SET                   18
1711 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     19
1712 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       20
1713 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        21
1714
1715 #define NUM_GLOBAL_SETUP_TOKENS                 22
1716
1717 /* editor setup */
1718 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
1719 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
1720 #define SETUP_TOKEN_EDITOR_EL_MORE              2
1721 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           3
1722 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          4
1723 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     5
1724 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    6
1725 #define SETUP_TOKEN_EDITOR_EL_CHARS             7
1726 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            8
1727
1728 #define NUM_EDITOR_SETUP_TOKENS                 9
1729
1730 /* shortcut setup */
1731 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
1732 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
1733 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
1734
1735 #define NUM_SHORTCUT_SETUP_TOKENS               3
1736
1737 /* player setup */
1738 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
1739 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
1740 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
1741 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
1742 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
1743 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
1744 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
1745 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
1746 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
1747 #define SETUP_TOKEN_PLAYER_JOY_BOMB             9
1748 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
1749 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
1750 #define SETUP_TOKEN_PLAYER_KEY_UP               12
1751 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
1752 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
1753 #define SETUP_TOKEN_PLAYER_KEY_BOMB             15
1754
1755 #define NUM_PLAYER_SETUP_TOKENS                 16
1756
1757 /* system setup */
1758 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
1759 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
1760
1761 #define NUM_SYSTEM_SETUP_TOKENS                 2
1762
1763 /* options setup */
1764 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
1765
1766 #define NUM_OPTIONS_SETUP_TOKENS                1
1767
1768
1769 static struct SetupInfo si;
1770 static struct SetupEditorInfo sei;
1771 static struct SetupShortcutInfo ssi;
1772 static struct SetupInputInfo sii;
1773 static struct SetupSystemInfo syi;
1774 static struct OptionInfo soi;
1775
1776 static struct TokenInfo global_setup_tokens[] =
1777 {
1778   { TYPE_STRING, &si.player_name,       "player_name"                   },
1779   { TYPE_SWITCH, &si.sound,             "sound"                         },
1780   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
1781   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
1782   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
1783   { TYPE_SWITCH, &si.toons,             "toons"                         },
1784   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
1785   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
1786   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
1787   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
1788   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
1789   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
1790   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
1791   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
1792   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
1793   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
1794   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
1795   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
1796   { TYPE_STRING, &si.music_set,         "music_set"                     },
1797   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1798   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
1799   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
1800 };
1801
1802 static struct TokenInfo editor_setup_tokens[] =
1803 {
1804   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
1805   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
1806   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
1807   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
1808   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
1809   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
1810   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
1811   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
1812   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
1813 };
1814
1815 static struct TokenInfo shortcut_setup_tokens[] =
1816 {
1817   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
1818   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
1819   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         }
1820 };
1821
1822 static struct TokenInfo player_setup_tokens[] =
1823 {
1824   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
1825   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
1826   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
1827   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
1828   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
1829   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
1830   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
1831   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
1832   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
1833   { TYPE_INTEGER, &sii.joy.bomb,        ".joy.place_bomb"               },
1834   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
1835   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
1836   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
1837   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
1838   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
1839   { TYPE_KEY_X11, &sii.key.bomb,        ".key.place_bomb"               }
1840 };
1841
1842 static struct TokenInfo system_setup_tokens[] =
1843 {
1844   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
1845   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
1846 };
1847
1848 static struct TokenInfo options_setup_tokens[] =
1849 {
1850   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               }
1851 };
1852
1853 static char *get_corrected_login_name(char *login_name)
1854 {
1855   /* needed because player name must be a fixed length string */
1856   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1857
1858   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
1859   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
1860
1861   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
1862     if (strchr(login_name_new, ' '))
1863       *strchr(login_name_new, ' ') = '\0';
1864
1865   return login_name_new;
1866 }
1867
1868 static void setSetupInfoToDefaults(struct SetupInfo *si)
1869 {
1870   int i;
1871
1872   si->player_name = get_corrected_login_name(getLoginName());
1873
1874   si->sound = TRUE;
1875   si->sound_loops = TRUE;
1876   si->sound_music = TRUE;
1877   si->sound_simple = TRUE;
1878   si->toons = TRUE;
1879   si->double_buffering = TRUE;
1880   si->direct_draw = !si->double_buffering;
1881   si->scroll_delay = TRUE;
1882   si->soft_scrolling = TRUE;
1883   si->fading = FALSE;
1884   si->autorecord = TRUE;
1885   si->quick_doors = FALSE;
1886   si->team_mode = FALSE;
1887   si->handicap = TRUE;
1888   si->time_limit = TRUE;
1889   si->fullscreen = FALSE;
1890   si->ask_on_escape = TRUE;
1891
1892   si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1893   si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1894   si->music_set = getStringCopy(MUSIC_SUBDIR);
1895   si->override_level_graphics = FALSE;
1896   si->override_level_sounds = FALSE;
1897   si->override_level_music = FALSE;
1898
1899   si->editor.el_boulderdash = TRUE;
1900   si->editor.el_emerald_mine = TRUE;
1901   si->editor.el_more = TRUE;
1902   si->editor.el_sokoban = TRUE;
1903   si->editor.el_supaplex = TRUE;
1904   si->editor.el_diamond_caves = TRUE;
1905   si->editor.el_dx_boulderdash = TRUE;
1906   si->editor.el_chars = TRUE;
1907   si->editor.el_custom = TRUE;
1908
1909   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1910   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1911   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1912
1913   for (i=0; i<MAX_PLAYERS; i++)
1914   {
1915     si->input[i].use_joystick = FALSE;
1916     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1917     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
1918     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1919     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
1920     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
1921     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1922     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
1923     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
1924     si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
1925     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
1926     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1927     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
1928     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
1929     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
1930     si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
1931   }
1932
1933   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
1934   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
1935
1936   si->options.verbose = FALSE;
1937 }
1938
1939 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
1940 {
1941   int i, pnr;
1942
1943   if (!setup_file_hash)
1944     return;
1945
1946   /* global setup */
1947   si = setup;
1948   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1949     setSetupInfo(global_setup_tokens, i,
1950                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
1951   setup = si;
1952
1953   /* editor setup */
1954   sei = setup.editor;
1955   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
1956     setSetupInfo(editor_setup_tokens, i,
1957                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
1958   setup.editor = sei;
1959
1960   /* shortcut setup */
1961   ssi = setup.shortcut;
1962   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1963     setSetupInfo(shortcut_setup_tokens, i,
1964                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
1965   setup.shortcut = ssi;
1966
1967   /* player setup */
1968   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1969   {
1970     char prefix[30];
1971
1972     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1973
1974     sii = setup.input[pnr];
1975     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1976     {
1977       char full_token[100];
1978
1979       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1980       setSetupInfo(player_setup_tokens, i,
1981                    getHashEntry(setup_file_hash, full_token));
1982     }
1983     setup.input[pnr] = sii;
1984   }
1985
1986   /* system setup */
1987   syi = setup.system;
1988   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
1989     setSetupInfo(system_setup_tokens, i,
1990                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
1991   setup.system = syi;
1992
1993   /* options setup */
1994   soi = setup.options;
1995   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
1996     setSetupInfo(options_setup_tokens, i,
1997                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
1998   setup.options = soi;
1999 }
2000
2001 void LoadSetup()
2002 {
2003   char *filename = getSetupFilename();
2004   SetupFileHash *setup_file_hash = NULL;
2005
2006   /* always start with reliable default values */
2007   setSetupInfoToDefaults(&setup);
2008
2009   setup_file_hash = loadSetupFileHash(filename);
2010
2011   if (setup_file_hash)
2012   {
2013     char *player_name_new;
2014
2015     checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
2016     decodeSetupFileHash(setup_file_hash);
2017
2018     setup.direct_draw = !setup.double_buffering;
2019
2020     freeSetupFileHash(setup_file_hash);
2021
2022     /* needed to work around problems with fixed length strings */
2023     player_name_new = get_corrected_login_name(setup.player_name);
2024     free(setup.player_name);
2025     setup.player_name = player_name_new;
2026   }
2027   else
2028     Error(ERR_WARN, "using default setup values");
2029 }
2030
2031 void SaveSetup()
2032 {
2033   char *filename = getSetupFilename();
2034   FILE *file;
2035   int i, pnr;
2036
2037   InitUserDataDirectory();
2038
2039   if (!(file = fopen(filename, MODE_WRITE)))
2040   {
2041     Error(ERR_WARN, "cannot write setup file '%s'", filename);
2042     return;
2043   }
2044
2045   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
2046                                                getCookie("SETUP")));
2047   fprintf(file, "\n");
2048
2049   /* global setup */
2050   si = setup;
2051   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
2052   {
2053     /* just to make things nicer :) */
2054     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
2055         i == SETUP_TOKEN_GRAPHICS_SET)
2056       fprintf(file, "\n");
2057
2058     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
2059   }
2060
2061   /* editor setup */
2062   sei = setup.editor;
2063   fprintf(file, "\n");
2064   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
2065     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
2066
2067   /* shortcut setup */
2068   ssi = setup.shortcut;
2069   fprintf(file, "\n");
2070   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
2071     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
2072
2073   /* player setup */
2074   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
2075   {
2076     char prefix[30];
2077
2078     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
2079     fprintf(file, "\n");
2080
2081     sii = setup.input[pnr];
2082     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
2083       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
2084   }
2085
2086   /* system setup */
2087   syi = setup.system;
2088   fprintf(file, "\n");
2089   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
2090     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
2091
2092   /* options setup */
2093   soi = setup.options;
2094   fprintf(file, "\n");
2095   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2096     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
2097
2098   fclose(file);
2099
2100   SetFilePermissions(filename, PERMS_PRIVATE);
2101 }
2102
2103 void LoadCustomElementDescriptions()
2104 {
2105   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2106   SetupFileHash *setup_file_hash;
2107   int i;
2108
2109   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2110   {
2111     if (element_info[i].custom_description != NULL)
2112     {
2113       free(element_info[i].custom_description);
2114       element_info[i].custom_description = NULL;
2115     }
2116   }
2117
2118   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2119     return;
2120
2121   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2122   {
2123     char *token = getStringCat2(element_info[i].token_name, ".name");
2124     char *value = getHashEntry(setup_file_hash, token);
2125
2126     if (value != NULL)
2127       element_info[i].custom_description = getStringCopy(value);
2128
2129     free(token);
2130   }
2131
2132   freeSetupFileHash(setup_file_hash);
2133 }
2134
2135 void LoadSpecialMenuDesignSettings()
2136 {
2137   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2138   SetupFileHash *setup_file_hash;
2139   int i, j;
2140
2141   /* always start with reliable default values from default config */
2142   for (i=0; image_config_vars[i].token != NULL; i++)
2143     for (j=0; image_config[j].token != NULL; j++)
2144       if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
2145         *image_config_vars[i].value =
2146           get_integer_from_string(image_config[j].value);
2147
2148   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2149     return;
2150
2151   /* special case: initialize with default values that may be overwritten */
2152   for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
2153   {
2154     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
2155     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
2156     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
2157
2158     if (value_x != NULL)
2159       menu.draw_xoffset[i] = get_integer_from_string(value_x);
2160     if (value_y != NULL)
2161       menu.draw_yoffset[i] = get_integer_from_string(value_y);
2162     if (list_size != NULL)
2163       menu.list_size[i] = get_integer_from_string(list_size);
2164   }
2165
2166   /* read (and overwrite with) values that may be specified in config file */
2167   for (i=0; image_config_vars[i].token != NULL; i++)
2168   {
2169     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
2170
2171     if (value != NULL)
2172       *image_config_vars[i].value = get_integer_from_string(value);
2173   }
2174
2175   freeSetupFileHash(setup_file_hash);
2176 }