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