rnd-20031019-4-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_CHUNK_CNT3_HEADER 16      /* size of level CNT3 header  */
34 #define LEVEL_CHUNK_CNT3_UNUSED 10      /* unused CNT3 chunk bytes    */
35 #define LEVEL_CPART_CUS3_SIZE   134     /* size of CUS3 chunk part    */
36 #define LEVEL_CPART_CUS3_UNUSED 15      /* unused CUS3 bytes / part   */
37 #define TAPE_HEADER_SIZE        20      /* size of tape file header   */
38 #define TAPE_HEADER_UNUSED      3       /* unused tape header bytes   */
39
40 #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
41 #define LEVEL_CHUNK_CUS4_SIZE(x) (48 + 48 + (x) * 48)
42
43 /* file identifier strings */
44 #define LEVEL_COOKIE_TMPL       "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
45 #define TAPE_COOKIE_TMPL        "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
46 #define SCORE_COOKIE            "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
47
48
49 /* ========================================================================= */
50 /* level file functions                                                      */
51 /* ========================================================================= */
52
53 void setElementChangePages(struct ElementInfo *ei, int change_pages)
54 {
55   int change_page_size = sizeof(struct ElementChangeInfo);
56
57   ei->num_change_pages = MAX(1, change_pages);
58
59   ei->change_page =
60     checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
61
62   if (ei->current_change_page >= ei->num_change_pages)
63     ei->current_change_page = ei->num_change_pages - 1;
64
65   ei->change = &ei->change_page[ei->current_change_page];
66 }
67
68 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
69 {
70   int x, y;
71
72   change->can_change = FALSE;
73
74   change->events = CE_BITMASK_DEFAULT;
75   change->sides = CH_SIDE_ANY;
76
77   change->target_element = EL_EMPTY_SPACE;
78
79   change->delay_fixed = 0;
80   change->delay_random = 0;
81   change->delay_frames = 1;
82
83   change->trigger_element = EL_EMPTY_SPACE;
84
85   change->explode = FALSE;
86   change->use_content = FALSE;
87   change->only_complete = FALSE;
88   change->use_random_change = FALSE;
89   change->random = 100;
90   change->power = CP_NON_DESTRUCTIVE;
91
92   for(x=0; x<3; x++)
93     for(y=0; y<3; y++)
94       change->content[x][y] = EL_EMPTY_SPACE;
95
96   change->direct_action = 0;
97   change->other_action = 0;
98
99   change->pre_change_function = NULL;
100   change->change_function = NULL;
101   change->post_change_function = NULL;
102 }
103
104 static void setLevelInfoToDefaults(struct LevelInfo *level)
105 {
106   int i, j, x, y;
107
108   level->file_version = FILE_VERSION_ACTUAL;
109   level->game_version = GAME_VERSION_ACTUAL;
110
111   level->encoding_16bit_field  = FALSE; /* default: only 8-bit elements */
112   level->encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
113   level->encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
114
115   level->fieldx = STD_LEV_FIELDX;
116   level->fieldy = STD_LEV_FIELDY;
117
118   for(x=0; x<MAX_LEV_FIELDX; x++)
119     for(y=0; y<MAX_LEV_FIELDY; y++)
120       level->field[x][y] = EL_SAND;
121
122   level->time = 100;
123   level->gems_needed = 0;
124   level->amoeba_speed = 10;
125   level->time_magic_wall = 10;
126   level->time_wheel = 10;
127   level->time_light = 10;
128   level->time_timegate = 10;
129   level->amoeba_content = EL_DIAMOND;
130   level->double_speed = FALSE;
131   level->initial_gravity = FALSE;
132   level->em_slippery_gems = FALSE;
133
134   level->use_custom_template = FALSE;
135
136   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
137     level->name[i] = '\0';
138   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
139     level->author[i] = '\0';
140
141   strcpy(level->name, NAMELESS_LEVEL_NAME);
142   strcpy(level->author, ANONYMOUS_NAME);
143
144   for (i=0; i<4; i++)
145   {
146     level->envelope_text[i][0] = '\0';
147     level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
148     level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
149   }
150
151   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
152     level->score[i] = 10;
153
154   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
155   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
156     for(x=0; x<3; x++)
157       for(y=0; y<3; y++)
158         level->yamyam_content[i][x][y] =
159           (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
160
161   level->field[0][0] = EL_PLAYER_1;
162   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
163
164   for (i=0; i < MAX_NUM_ELEMENTS; i++)
165   {
166     setElementChangePages(&element_info[i], 1);
167     setElementChangeInfoToDefaults(element_info[i].change);
168   }
169
170   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
171   {
172     int element = EL_CUSTOM_START + i;
173
174     for(j=0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
175       element_info[element].description[j] = '\0';
176     if (element_info[element].custom_description != NULL)
177       strncpy(element_info[element].description,
178               element_info[element].custom_description, MAX_ELEMENT_NAME_LEN);
179     else
180       strcpy(element_info[element].description,
181              element_info[element].editor_description);
182
183     element_info[element].use_gfx_element = FALSE;
184     element_info[element].gfx_element = EL_EMPTY_SPACE;
185
186     element_info[element].collect_score = 10;           /* special default */
187     element_info[element].collect_count = 1;            /* special default */
188
189     element_info[element].push_delay_fixed = -1;        /* initialize later */
190     element_info[element].push_delay_random = -1;       /* initialize later */
191     element_info[element].move_delay_fixed = 0;
192     element_info[element].move_delay_random = 0;
193
194     element_info[element].move_pattern = MV_ALL_DIRECTIONS;
195     element_info[element].move_direction_initial = MV_NO_MOVING;
196     element_info[element].move_stepsize = TILEX / 8;
197
198     element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
199
200     for(x=0; x<3; x++)
201       for(y=0; y<3; y++)
202         element_info[element].content[x][y] = EL_EMPTY_SPACE;
203
204     element_info[element].access_type = 0;
205     element_info[element].access_layer = 0;
206     element_info[element].walk_to_action = 0;
207     element_info[element].smash_targets = 0;
208     element_info[element].deadliness = 0;
209     element_info[element].consistency = 0;
210
211     element_info[element].can_explode_by_fire = FALSE;
212     element_info[element].can_explode_smashed = FALSE;
213     element_info[element].can_explode_impact = FALSE;
214
215     element_info[element].current_change_page = 0;
216
217     /* start with no properties at all */
218     for (j=0; j < NUM_EP_BITFIELDS; j++)
219       Properties[element][j] = EP_BITMASK_DEFAULT;
220
221     element_info[element].modified_settings = FALSE;
222   }
223
224   BorderElement = EL_STEELWALL;
225
226   level->no_level_file = FALSE;
227
228   if (leveldir_current == NULL)         /* only when dumping level */
229     return;
230
231   /* try to determine better author name than 'anonymous' */
232   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
233   {
234     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
235     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
236   }
237   else
238   {
239     switch (LEVELCLASS(leveldir_current))
240     {
241       case LEVELCLASS_TUTORIAL:
242         strcpy(level->author, PROGRAM_AUTHOR_STRING);
243         break;
244
245       case LEVELCLASS_CONTRIB:
246         strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
247         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
248         break;
249
250       case LEVELCLASS_PRIVATE:
251         strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
252         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
253         break;
254
255       default:
256         /* keep default value */
257         break;
258     }
259   }
260 }
261
262 static void ActivateLevelTemplate()
263 {
264   /* Currently there is no special action needed to activate the template
265      data, because 'element_info' and 'Properties' overwrite the original
266      level data, while all other variables do not change. */
267 }
268
269 boolean LevelFileExists(int level_nr)
270 {
271   char *filename = getLevelFilename(level_nr);
272
273   return (access(filename, F_OK) == 0);
274 }
275
276 static int checkLevelElement(int element)
277 {
278   /* map some (historic, now obsolete) elements */
279
280 #if 1
281   switch (element)
282   {
283     case EL_PLAYER_OBSOLETE:
284       element = EL_PLAYER_1;
285       break;
286
287     case EL_KEY_OBSOLETE:
288       element = EL_KEY_1;
289
290     case EL_EM_KEY_1_FILE_OBSOLETE:
291       element = EL_EM_KEY_1;
292       break;
293
294     case EL_EM_KEY_2_FILE_OBSOLETE:
295       element = EL_EM_KEY_2;
296       break;
297
298     case EL_EM_KEY_3_FILE_OBSOLETE:
299       element = EL_EM_KEY_3;
300       break;
301
302     case EL_EM_KEY_4_FILE_OBSOLETE:
303       element = EL_EM_KEY_4;
304       break;
305
306     case EL_ENVELOPE_OBSOLETE:
307       element = EL_ENVELOPE_1;
308       break;
309
310     case EL_SP_EMPTY:
311       element = EL_EMPTY;
312       break;
313
314     default:
315       if (element >= NUM_FILE_ELEMENTS)
316       {
317         Error(ERR_WARN, "invalid level element %d", element);
318
319         element = EL_CHAR_QUESTION;
320       }
321       break;
322   }
323 #else
324   if (element >= NUM_FILE_ELEMENTS)
325   {
326     Error(ERR_WARN, "invalid level element %d", element);
327
328     element = EL_CHAR_QUESTION;
329   }
330   else if (element == EL_PLAYER_OBSOLETE)
331     element = EL_PLAYER_1;
332   else if (element == EL_KEY_OBSOLETE)
333     element = EL_KEY_1;
334 #endif
335
336   return element;
337 }
338
339 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
340 {
341   level->file_version = getFileVersion(file);
342   level->game_version = getFileVersion(file);
343
344   return chunk_size;
345 }
346
347 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
348 {
349   int i, x, y;
350
351   level->fieldx = getFile8Bit(file);
352   level->fieldy = getFile8Bit(file);
353
354   level->time           = getFile16BitBE(file);
355   level->gems_needed    = getFile16BitBE(file);
356
357   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
358     level->name[i] = getFile8Bit(file);
359   level->name[MAX_LEVEL_NAME_LEN] = 0;
360
361   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
362     level->score[i] = getFile8Bit(file);
363
364   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
365   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
366     for(y=0; y<3; y++)
367       for(x=0; x<3; x++)
368         level->yamyam_content[i][x][y] = checkLevelElement(getFile8Bit(file));
369
370   level->amoeba_speed           = getFile8Bit(file);
371   level->time_magic_wall        = getFile8Bit(file);
372   level->time_wheel             = getFile8Bit(file);
373   level->amoeba_content         = checkLevelElement(getFile8Bit(file));
374   level->double_speed           = (getFile8Bit(file) == 1 ? TRUE : FALSE);
375   level->initial_gravity        = (getFile8Bit(file) == 1 ? TRUE : FALSE);
376   level->encoding_16bit_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
377   level->em_slippery_gems       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
378
379   level->use_custom_template    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
380
381   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
382
383   return chunk_size;
384 }
385
386 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
387 {
388   int i;
389
390   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
391     level->author[i] = getFile8Bit(file);
392   level->author[MAX_LEVEL_NAME_LEN] = 0;
393
394   return chunk_size;
395 }
396
397 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
398 {
399   int x, y;
400   int chunk_size_expected = level->fieldx * level->fieldy;
401
402   /* Note: "chunk_size" was wrong before version 2.0 when elements are
403      stored with 16-bit encoding (and should be twice as big then).
404      Even worse, playfield data was stored 16-bit when only yamyam content
405      contained 16-bit elements and vice versa. */
406
407   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
408     chunk_size_expected *= 2;
409
410   if (chunk_size_expected != chunk_size)
411   {
412     ReadUnusedBytesFromFile(file, chunk_size);
413     return chunk_size_expected;
414   }
415
416   for(y=0; y<level->fieldy; y++)
417     for(x=0; x<level->fieldx; x++)
418       level->field[x][y] =
419         checkLevelElement(level->encoding_16bit_field ? getFile16BitBE(file) :
420                           getFile8Bit(file));
421   return chunk_size;
422 }
423
424 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
425 {
426   int i, x, y;
427   int header_size = 4;
428   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
429   int chunk_size_expected = header_size + content_size;
430
431   /* Note: "chunk_size" was wrong before version 2.0 when elements are
432      stored with 16-bit encoding (and should be twice as big then).
433      Even worse, playfield data was stored 16-bit when only yamyam content
434      contained 16-bit elements and vice versa. */
435
436   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
437     chunk_size_expected += content_size;
438
439   if (chunk_size_expected != chunk_size)
440   {
441     ReadUnusedBytesFromFile(file, chunk_size);
442     return chunk_size_expected;
443   }
444
445   getFile8Bit(file);
446   level->num_yamyam_contents = getFile8Bit(file);
447   getFile8Bit(file);
448   getFile8Bit(file);
449
450   /* correct invalid number of content fields -- should never happen */
451   if (level->num_yamyam_contents < 1 ||
452       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
453     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
454
455   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
456     for(y=0; y<3; y++)
457       for(x=0; x<3; x++)
458         level->yamyam_content[i][x][y] =
459           checkLevelElement(level->encoding_16bit_field ?
460                             getFile16BitBE(file) : getFile8Bit(file));
461   return chunk_size;
462 }
463
464 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
465 {
466   int i, x, y;
467   int element;
468   int num_contents, content_xsize, content_ysize;
469   int content_array[MAX_ELEMENT_CONTENTS][3][3];
470
471   element = checkLevelElement(getFile16BitBE(file));
472   num_contents = getFile8Bit(file);
473   content_xsize = getFile8Bit(file);
474   content_ysize = getFile8Bit(file);
475
476   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
477
478   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
479     for(y=0; y<3; y++)
480       for(x=0; x<3; x++)
481         content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
482
483   /* correct invalid number of content fields -- should never happen */
484   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
485     num_contents = STD_ELEMENT_CONTENTS;
486
487   if (element == EL_YAMYAM)
488   {
489     level->num_yamyam_contents = num_contents;
490
491     for(i=0; i<num_contents; i++)
492       for(y=0; y<3; y++)
493         for(x=0; x<3; x++)
494           level->yamyam_content[i][x][y] = content_array[i][x][y];
495   }
496   else if (element == EL_BD_AMOEBA)
497   {
498     level->amoeba_content = content_array[0][0][0];
499   }
500   else
501   {
502     Error(ERR_WARN, "cannot load content for element '%d'", element);
503   }
504
505   return chunk_size;
506 }
507
508 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
509 {
510   int i;
511   int element;
512   int envelope_nr;
513   int envelope_len;
514   int chunk_size_expected;
515
516   element = checkLevelElement(getFile16BitBE(file));
517   if (!IS_ENVELOPE(element))
518     element = EL_ENVELOPE_1;
519
520   envelope_nr = element - EL_ENVELOPE_1;
521
522   envelope_len = getFile16BitBE(file);
523
524   level->envelope_xsize[envelope_nr] = getFile8Bit(file);
525   level->envelope_ysize[envelope_nr] = getFile8Bit(file);
526
527   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
528
529   chunk_size_expected = LEVEL_CHUNK_CNT3_HEADER + envelope_len;
530
531   if (chunk_size_expected != chunk_size)
532   {
533     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
534     return chunk_size_expected;
535   }
536
537   for(i=0; i < envelope_len; i++)
538     level->envelope_text[envelope_nr][i] = getFile8Bit(file);
539
540   return chunk_size;
541 }
542
543 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
544 {
545   int num_changed_custom_elements = getFile16BitBE(file);
546   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
547   int i;
548
549   if (chunk_size_expected != chunk_size)
550   {
551     ReadUnusedBytesFromFile(file, chunk_size - 2);
552     return chunk_size_expected;
553   }
554
555   for (i=0; i < num_changed_custom_elements; i++)
556   {
557     int element = getFile16BitBE(file);
558     int properties = getFile32BitBE(file);
559
560     if (IS_CUSTOM_ELEMENT(element))
561       Properties[element][EP_BITFIELD_BASE] = properties;
562     else
563       Error(ERR_WARN, "invalid custom element number %d", element);
564   }
565
566   return chunk_size;
567 }
568
569 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
570 {
571   int num_changed_custom_elements = getFile16BitBE(file);
572   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
573   int i;
574
575   if (chunk_size_expected != chunk_size)
576   {
577     ReadUnusedBytesFromFile(file, chunk_size - 2);
578     return chunk_size_expected;
579   }
580
581   for (i=0; i < num_changed_custom_elements; i++)
582   {
583     int element = getFile16BitBE(file);
584     int custom_target_element = getFile16BitBE(file);
585
586     if (IS_CUSTOM_ELEMENT(element))
587       element_info[element].change->target_element = custom_target_element;
588     else
589       Error(ERR_WARN, "invalid custom element number %d", element);
590   }
591
592   return chunk_size;
593 }
594
595 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
596 {
597   int num_changed_custom_elements = getFile16BitBE(file);
598   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
599   int i, j, x, y;
600
601   if (chunk_size_expected != chunk_size)
602   {
603     ReadUnusedBytesFromFile(file, chunk_size - 2);
604     return chunk_size_expected;
605   }
606
607   for (i=0; i < num_changed_custom_elements; i++)
608   {
609     int element = getFile16BitBE(file);
610
611     if (!IS_CUSTOM_ELEMENT(element))
612     {
613       Error(ERR_WARN, "invalid custom element number %d", element);
614
615       element = EL_DEFAULT;     /* dummy element used for artwork config */
616     }
617
618     for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
619       element_info[element].description[j] = getFile8Bit(file);
620     element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
621
622     Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
623
624     /* some free bytes for future properties and padding */
625     ReadUnusedBytesFromFile(file, 7);
626
627     element_info[element].use_gfx_element = getFile8Bit(file);
628     element_info[element].gfx_element =
629       checkLevelElement(getFile16BitBE(file));
630
631     element_info[element].collect_score = getFile8Bit(file);
632     element_info[element].collect_count = getFile8Bit(file);
633
634     element_info[element].push_delay_fixed = getFile16BitBE(file);
635     element_info[element].push_delay_random = getFile16BitBE(file);
636     element_info[element].move_delay_fixed = getFile16BitBE(file);
637     element_info[element].move_delay_random = getFile16BitBE(file);
638
639     element_info[element].move_pattern = getFile16BitBE(file);
640     element_info[element].move_direction_initial = getFile8Bit(file);
641     element_info[element].move_stepsize = getFile8Bit(file);
642
643     for(y=0; y<3; y++)
644       for(x=0; x<3; x++)
645         element_info[element].content[x][y] =
646           checkLevelElement(getFile16BitBE(file));
647
648     element_info[element].change->events = getFile32BitBE(file);
649
650     element_info[element].change->target_element =
651       checkLevelElement(getFile16BitBE(file));
652
653     element_info[element].change->delay_fixed = getFile16BitBE(file);
654     element_info[element].change->delay_random = getFile16BitBE(file);
655     element_info[element].change->delay_frames = getFile16BitBE(file);
656
657     element_info[element].change->trigger_element =
658       checkLevelElement(getFile16BitBE(file));
659
660     element_info[element].change->explode = getFile8Bit(file);
661     element_info[element].change->use_content = getFile8Bit(file);
662     element_info[element].change->only_complete = getFile8Bit(file);
663     element_info[element].change->use_random_change = getFile8Bit(file);
664
665     element_info[element].change->random = getFile8Bit(file);
666     element_info[element].change->power = getFile8Bit(file);
667
668     for(y=0; y<3; y++)
669       for(x=0; x<3; x++)
670         element_info[element].change->content[x][y] =
671           checkLevelElement(getFile16BitBE(file));
672
673     element_info[element].slippery_type = getFile8Bit(file);
674
675     /* some free bytes for future properties and padding */
676     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
677
678     /* mark that this custom element has been modified */
679     element_info[element].modified_settings = TRUE;
680   }
681
682   return chunk_size;
683 }
684
685 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
686 {
687   struct ElementInfo *ei;
688   int chunk_size_expected;
689   int element;
690   int i, x, y;
691
692   element = getFile16BitBE(file);
693
694   if (!IS_CUSTOM_ELEMENT(element))
695   {
696     Error(ERR_WARN, "invalid custom element number %d", element);
697
698     element = EL_DEFAULT;       /* dummy element used for artwork config */
699   }
700
701   ei = &element_info[element];
702
703   for(i=0; i < MAX_ELEMENT_NAME_LEN; i++)
704     ei->description[i] = getFile8Bit(file);
705   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
706
707   Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
708   ReadUnusedBytesFromFile(file, 4);     /* reserved for more base properties */
709
710   ei->num_change_pages = getFile8Bit(file);
711
712   /* some free bytes for future base property values and padding */
713   ReadUnusedBytesFromFile(file, 5);
714
715   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
716   if (chunk_size_expected != chunk_size)
717   {
718     ReadUnusedBytesFromFile(file, chunk_size - 48);
719     return chunk_size_expected;
720   }
721
722   /* read custom property values */
723
724   ei->use_gfx_element = getFile8Bit(file);
725   ei->gfx_element = checkLevelElement(getFile16BitBE(file));
726
727   ei->collect_score = getFile8Bit(file);
728   ei->collect_count = getFile8Bit(file);
729
730   ei->push_delay_fixed = getFile16BitBE(file);
731   ei->push_delay_random = getFile16BitBE(file);
732   ei->move_delay_fixed = getFile16BitBE(file);
733   ei->move_delay_random = getFile16BitBE(file);
734
735   ei->move_pattern = getFile16BitBE(file);
736   ei->move_direction_initial = getFile8Bit(file);
737   ei->move_stepsize = getFile8Bit(file);
738
739   ei->slippery_type = getFile8Bit(file);
740
741   for(y=0; y<3; y++)
742     for(x=0; x<3; x++)
743       ei->content[x][y] = checkLevelElement(getFile16BitBE(file));
744
745   /* some free bytes for future custom property values and padding */
746   ReadUnusedBytesFromFile(file, 12);
747
748   /* read change property values */
749
750   setElementChangePages(ei, ei->num_change_pages);
751
752   for (i=0; i < ei->num_change_pages; i++)
753   {
754     struct ElementChangeInfo *change = &ei->change_page[i];
755
756     /* always start with reliable default values */
757     setElementChangeInfoToDefaults(change);
758
759     change->events = getFile32BitBE(file);
760
761     change->target_element = checkLevelElement(getFile16BitBE(file));
762
763     change->delay_fixed = getFile16BitBE(file);
764     change->delay_random = getFile16BitBE(file);
765     change->delay_frames = getFile16BitBE(file);
766
767     change->trigger_element = checkLevelElement(getFile16BitBE(file));
768
769     change->explode = getFile8Bit(file);
770     change->use_content = getFile8Bit(file);
771     change->only_complete = getFile8Bit(file);
772     change->use_random_change = getFile8Bit(file);
773
774     change->random = getFile8Bit(file);
775     change->power = getFile8Bit(file);
776
777     for(y=0; y<3; y++)
778       for(x=0; x<3; x++)
779         change->content[x][y] = checkLevelElement(getFile16BitBE(file));
780
781     change->can_change = getFile8Bit(file);
782
783     change->sides = getFile8Bit(file);
784
785     if (change->sides == CH_SIDE_NONE)  /* correct empty sides field */
786       change->sides = CH_SIDE_ANY;
787
788     /* some free bytes for future change property values and padding */
789     ReadUnusedBytesFromFile(file, 8);
790   }
791
792   /* mark this custom element as modified */
793   ei->modified_settings = TRUE;
794
795   return chunk_size;
796 }
797
798 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
799 {
800   char cookie[MAX_LINE_LEN];
801   char chunk_name[CHUNK_ID_LEN + 1];
802   int chunk_size;
803   FILE *file;
804
805   /* always start with reliable default values */
806   setLevelInfoToDefaults(level);
807
808   if (!(file = fopen(filename, MODE_READ)))
809   {
810     level->no_level_file = TRUE;
811
812     if (level != &level_template)
813       Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
814
815     return;
816   }
817
818   getFileChunkBE(file, chunk_name, NULL);
819   if (strcmp(chunk_name, "RND1") == 0)
820   {
821     getFile32BitBE(file);               /* not used */
822
823     getFileChunkBE(file, chunk_name, NULL);
824     if (strcmp(chunk_name, "CAVE") != 0)
825     {
826       Error(ERR_WARN, "unknown format of level file '%s'", filename);
827       fclose(file);
828       return;
829     }
830   }
831   else  /* check for pre-2.0 file format with cookie string */
832   {
833     strcpy(cookie, chunk_name);
834     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
835     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
836       cookie[strlen(cookie) - 1] = '\0';
837
838     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
839     {
840       Error(ERR_WARN, "unknown format of level file '%s'", filename);
841       fclose(file);
842       return;
843     }
844
845     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
846     {
847       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
848       fclose(file);
849       return;
850     }
851
852     /* pre-2.0 level files have no game version, so use file version here */
853     level->game_version = level->file_version;
854   }
855
856   if (level->file_version < FILE_VERSION_1_2)
857   {
858     /* level files from versions before 1.2.0 without chunk structure */
859     LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,             level);
860     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
861   }
862   else
863   {
864     static struct
865     {
866       char *name;
867       int size;
868       int (*loader)(FILE *, int, struct LevelInfo *);
869     }
870     chunk_info[] =
871     {
872       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadLevel_VERS },
873       { "HEAD", LEVEL_HEADER_SIZE,      LoadLevel_HEAD },
874       { "AUTH", MAX_LEVEL_AUTHOR_LEN,   LoadLevel_AUTH },
875       { "BODY", -1,                     LoadLevel_BODY },
876       { "CONT", -1,                     LoadLevel_CONT },
877       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
878       { "CNT3", -1,                     LoadLevel_CNT3 },
879       { "CUS1", -1,                     LoadLevel_CUS1 },
880       { "CUS2", -1,                     LoadLevel_CUS2 },
881       { "CUS3", -1,                     LoadLevel_CUS3 },
882       { "CUS4", -1,                     LoadLevel_CUS4 },
883       {  NULL,  0,                      NULL }
884     };
885
886     while (getFileChunkBE(file, chunk_name, &chunk_size))
887     {
888       int i = 0;
889
890       while (chunk_info[i].name != NULL &&
891              strcmp(chunk_name, chunk_info[i].name) != 0)
892         i++;
893
894       if (chunk_info[i].name == NULL)
895       {
896         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
897               chunk_name, filename);
898         ReadUnusedBytesFromFile(file, chunk_size);
899       }
900       else if (chunk_info[i].size != -1 &&
901                chunk_info[i].size != chunk_size)
902       {
903         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
904               chunk_size, chunk_name, filename);
905         ReadUnusedBytesFromFile(file, chunk_size);
906       }
907       else
908       {
909         /* call function to load this level chunk */
910         int chunk_size_expected =
911           (chunk_info[i].loader)(file, chunk_size, level);
912
913         /* the size of some chunks cannot be checked before reading other
914            chunks first (like "HEAD" and "BODY") that contain some header
915            information, so check them here */
916         if (chunk_size_expected != chunk_size)
917         {
918           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
919                 chunk_size, chunk_name, filename);
920         }
921       }
922     }
923   }
924
925   fclose(file);
926 }
927
928 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
929 {
930   if (leveldir_current == NULL)         /* only when dumping level */
931     return;
932
933 #if 0
934   printf("::: sort_priority: %d\n", leveldir_current->sort_priority);
935 #endif
936
937   /* determine correct game engine version of current level */
938 #if 1
939   if (!leveldir_current->latest_engine)
940 #else
941   if (IS_LEVELCLASS_CONTRIB(leveldir_current) ||
942       IS_LEVELCLASS_PRIVATE(leveldir_current) ||
943       IS_LEVELCLASS_UNDEFINED(leveldir_current))
944 #endif
945   {
946 #if 0
947     printf("\n::: This level is private or contributed: '%s'\n", filename);
948 #endif
949
950 #if 1
951     printf("\n::: Use the stored game engine version for this level\n");
952 #endif
953
954     /* For all levels which are not forced to use the latest game engine
955        version (normally user contributed, private and undefined levels),
956        use the version of the game engine the levels were created for.
957
958        Since 2.0.1, the game engine version is now directly stored
959        in the level file (chunk "VERS"), so there is no need anymore
960        to set the game version from the file version (except for old,
961        pre-2.0 levels, where the game version is still taken from the
962        file format version used to store the level -- see above). */
963
964     /* do some special adjustments to support older level versions */
965     if (level->file_version == FILE_VERSION_1_0)
966     {
967       Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
968       Error(ERR_WARN, "using high speed movement for player");
969
970       /* player was faster than monsters in (pre-)1.0 levels */
971       level->double_speed = TRUE;
972     }
973
974     /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
975     if (level->game_version == VERSION_IDENT(2,0,1))
976       level->em_slippery_gems = TRUE;
977   }
978   else
979   {
980 #if 0
981     printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n",
982            leveldir_current->sort_priority, filename);
983 #endif
984
985 #if 1
986     printf("\n::: Use latest game engine version for this level.\n");
987 #endif
988
989     /* For all levels which are forced to use the latest game engine version
990        (normally all but user contributed, private and undefined levels), set
991        the game engine version to the actual version; this allows for actual
992        corrections in the game engine to take effect for existing, converted
993        levels (from "classic" or other existing games) to make the emulation
994        of the corresponding game more accurate, while (hopefully) not breaking
995        existing levels created from other players. */
996
997 #if 0
998     printf("::: changing engine from %d to %d\n",
999            level->game_version, GAME_VERSION_ACTUAL);
1000 #endif
1001
1002     level->game_version = GAME_VERSION_ACTUAL;
1003
1004     /* Set special EM style gems behaviour: EM style gems slip down from
1005        normal, steel and growing wall. As this is a more fundamental change,
1006        it seems better to set the default behaviour to "off" (as it is more
1007        natural) and make it configurable in the level editor (as a property
1008        of gem style elements). Already existing converted levels (neither
1009        private nor contributed levels) are changed to the new behaviour. */
1010
1011     if (level->file_version < FILE_VERSION_2_0)
1012       level->em_slippery_gems = TRUE;
1013   }
1014
1015 #if 0
1016   printf("::: => %d\n", level->game_version);
1017 #endif
1018 }
1019
1020 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
1021 {
1022   int i, j;
1023
1024   /* map custom element change events that have changed in newer versions
1025      (these following values were accidentally changed in version 3.0.1) */
1026   if (level->game_version <= VERSION_IDENT(3,0,0))
1027   {
1028     for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1029     {
1030       int element = EL_CUSTOM_START + i;
1031
1032       /* order of checking and copying events to be mapped is important */
1033       for (j=CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER; j--)
1034       {
1035         if (HAS_CHANGE_EVENT(element, j - 2))
1036         {
1037           SET_CHANGE_EVENT(element, j - 2, FALSE);
1038           SET_CHANGE_EVENT(element, j, TRUE);
1039         }
1040       }
1041
1042       /* order of checking and copying events to be mapped is important */
1043       for (j=CE_OTHER_GETS_COLLECTED; j >= CE_COLLISION; j--)
1044       {
1045         if (HAS_CHANGE_EVENT(element, j - 1))
1046         {
1047           SET_CHANGE_EVENT(element, j - 1, FALSE);
1048           SET_CHANGE_EVENT(element, j, TRUE);
1049         }
1050       }
1051     }
1052   }
1053
1054   /* some custom element change events get mapped since version 3.0.3 */
1055   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1056   {
1057     int element = EL_CUSTOM_START + i;
1058
1059     if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER) ||
1060         HAS_CHANGE_EVENT(element, CE_BY_COLLISION))
1061     {
1062       SET_CHANGE_EVENT(element, CE_BY_PLAYER, FALSE);
1063       SET_CHANGE_EVENT(element, CE_BY_COLLISION, FALSE);
1064
1065       SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, TRUE);
1066     }
1067   }
1068
1069   /* initialize "can_change" field for old levels with only one change page */
1070   if (level->game_version <= VERSION_IDENT(3,0,2))
1071   {
1072     for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1073     {
1074       int element = EL_CUSTOM_START + i;
1075
1076       if (CAN_CHANGE(element))
1077         element_info[element].change->can_change = TRUE;
1078     }
1079   }
1080
1081   /* set default push delay values (corrected since version 3.0.7) */
1082   if (level->game_version < VERSION_IDENT(3,0,7))
1083   {
1084     game.default_push_delay_fixed = 2;
1085     game.default_push_delay_random = 8;
1086   }
1087   else
1088   {
1089     game.default_push_delay_fixed = 8;
1090     game.default_push_delay_random = 8;
1091   }
1092
1093   /* set uninitialized push delay values of custom elements in older levels */
1094   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1095   {
1096     int element = EL_CUSTOM_START + i;
1097
1098     if (element_info[element].push_delay_fixed == -1)
1099       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
1100     if (element_info[element].push_delay_random == -1)
1101       element_info[element].push_delay_random = game.default_push_delay_random;
1102   }
1103
1104   /* initialize element properties for level editor etc. */
1105   InitElementPropertiesEngine(level->game_version);
1106 }
1107
1108 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
1109 {
1110   int x, y;
1111
1112   /* map elements that have changed in newer versions */
1113   for(y=0; y<level->fieldy; y++)
1114   {
1115     for(x=0; x<level->fieldx; x++)
1116     {
1117       int element = level->field[x][y];
1118
1119       if (level->game_version <= VERSION_IDENT(2,2,0))
1120       {
1121         /* map game font elements */
1122         element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
1123                    element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
1124                    element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
1125                    element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
1126       }
1127
1128       if (level->game_version < VERSION_IDENT(3,0,0))
1129       {
1130         /* map Supaplex gravity tube elements */
1131         element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
1132                    element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
1133                    element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
1134                    element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
1135                    element);
1136       }
1137
1138       level->field[x][y] = element;
1139     }
1140   }
1141
1142   /* copy elements to runtime playfield array */
1143   for(x=0; x<MAX_LEV_FIELDX; x++)
1144     for(y=0; y<MAX_LEV_FIELDY; y++)
1145       Feld[x][y] = level->field[x][y];
1146
1147   /* initialize level size variables for faster access */
1148   lev_fieldx = level->fieldx;
1149   lev_fieldy = level->fieldy;
1150
1151   /* determine border element for this level */
1152   SetBorderElement();
1153 }
1154
1155 void LoadLevelTemplate(int level_nr)
1156 {
1157   char *filename = getLevelFilename(level_nr);
1158
1159   LoadLevelFromFilename(&level_template, filename);
1160
1161   LoadLevel_InitVersion(&level, filename);
1162   LoadLevel_InitElements(&level, filename);
1163
1164   ActivateLevelTemplate();
1165 }
1166
1167 void LoadLevel(int level_nr)
1168 {
1169   char *filename = getLevelFilename(level_nr);
1170
1171   LoadLevelFromFilename(&level, filename);
1172
1173   if (level.use_custom_template)
1174     LoadLevelTemplate(-1);
1175
1176 #if 1
1177   LoadLevel_InitVersion(&level, filename);
1178   LoadLevel_InitElements(&level, filename);
1179   LoadLevel_InitPlayfield(&level, filename);
1180 #else
1181   LoadLevel_InitLevel(&level, filename);
1182 #endif
1183 }
1184
1185 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
1186 {
1187   putFileVersion(file, level->file_version);
1188   putFileVersion(file, level->game_version);
1189 }
1190
1191 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
1192 {
1193   int i, x, y;
1194
1195   putFile8Bit(file, level->fieldx);
1196   putFile8Bit(file, level->fieldy);
1197
1198   putFile16BitBE(file, level->time);
1199   putFile16BitBE(file, level->gems_needed);
1200
1201   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
1202     putFile8Bit(file, level->name[i]);
1203
1204   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
1205     putFile8Bit(file, level->score[i]);
1206
1207   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
1208     for(y=0; y<3; y++)
1209       for(x=0; x<3; x++)
1210         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
1211                            level->yamyam_content[i][x][y]));
1212   putFile8Bit(file, level->amoeba_speed);
1213   putFile8Bit(file, level->time_magic_wall);
1214   putFile8Bit(file, level->time_wheel);
1215   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
1216                      level->amoeba_content));
1217   putFile8Bit(file, (level->double_speed ? 1 : 0));
1218   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
1219   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
1220   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
1221
1222   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
1223
1224   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
1225 }
1226
1227 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
1228 {
1229   int i;
1230
1231   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
1232     putFile8Bit(file, level->author[i]);
1233 }
1234
1235 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
1236 {
1237   int x, y;
1238
1239   for(y=0; y<level->fieldy; y++) 
1240     for(x=0; x<level->fieldx; x++) 
1241       if (level->encoding_16bit_field)
1242         putFile16BitBE(file, level->field[x][y]);
1243       else
1244         putFile8Bit(file, level->field[x][y]);
1245 }
1246
1247 #if 0
1248 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
1249 {
1250   int i, x, y;
1251
1252   putFile8Bit(file, EL_YAMYAM);
1253   putFile8Bit(file, level->num_yamyam_contents);
1254   putFile8Bit(file, 0);
1255   putFile8Bit(file, 0);
1256
1257   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1258     for(y=0; y<3; y++)
1259       for(x=0; x<3; x++)
1260         if (level->encoding_16bit_field)
1261           putFile16BitBE(file, level->yamyam_content[i][x][y]);
1262         else
1263           putFile8Bit(file, level->yamyam_content[i][x][y]);
1264 }
1265 #endif
1266
1267 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
1268 {
1269   int i, x, y;
1270   int num_contents, content_xsize, content_ysize;
1271   int content_array[MAX_ELEMENT_CONTENTS][3][3];
1272
1273   if (element == EL_YAMYAM)
1274   {
1275     num_contents = level->num_yamyam_contents;
1276     content_xsize = 3;
1277     content_ysize = 3;
1278
1279     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1280       for(y=0; y<3; y++)
1281         for(x=0; x<3; x++)
1282           content_array[i][x][y] = level->yamyam_content[i][x][y];
1283   }
1284   else if (element == EL_BD_AMOEBA)
1285   {
1286     num_contents = 1;
1287     content_xsize = 1;
1288     content_ysize = 1;
1289
1290     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1291       for(y=0; y<3; y++)
1292         for(x=0; x<3; x++)
1293           content_array[i][x][y] = EL_EMPTY;
1294     content_array[0][0][0] = level->amoeba_content;
1295   }
1296   else
1297   {
1298     /* chunk header already written -- write empty chunk data */
1299     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
1300
1301     Error(ERR_WARN, "cannot save content for element '%d'", element);
1302     return;
1303   }
1304
1305   putFile16BitBE(file, element);
1306   putFile8Bit(file, num_contents);
1307   putFile8Bit(file, content_xsize);
1308   putFile8Bit(file, content_ysize);
1309
1310   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
1311
1312   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1313     for(y=0; y<3; y++)
1314       for(x=0; x<3; x++)
1315         putFile16BitBE(file, content_array[i][x][y]);
1316 }
1317
1318 static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
1319 {
1320   int i;
1321   int envelope_nr = element - EL_ENVELOPE_1;
1322   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
1323
1324   putFile16BitBE(file, element);
1325   putFile16BitBE(file, envelope_len);
1326   putFile8Bit(file, level->envelope_xsize[envelope_nr]);
1327   putFile8Bit(file, level->envelope_ysize[envelope_nr]);
1328
1329   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
1330
1331   for(i=0; i < envelope_len; i++)
1332     putFile8Bit(file, level->envelope_text[envelope_nr][i]);
1333 }
1334
1335 #if 0
1336 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
1337                            int num_changed_custom_elements)
1338 {
1339   int i, check = 0;
1340
1341   putFile16BitBE(file, num_changed_custom_elements);
1342
1343   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1344   {
1345     int element = EL_CUSTOM_START + i;
1346
1347     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
1348     {
1349       if (check < num_changed_custom_elements)
1350       {
1351         putFile16BitBE(file, element);
1352         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1353       }
1354
1355       check++;
1356     }
1357   }
1358
1359   if (check != num_changed_custom_elements)     /* should not happen */
1360     Error(ERR_WARN, "inconsistent number of custom element properties");
1361 }
1362 #endif
1363
1364 #if 0
1365 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
1366                            int num_changed_custom_elements)
1367 {
1368   int i, check = 0;
1369
1370   putFile16BitBE(file, num_changed_custom_elements);
1371
1372   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1373   {
1374     int element = EL_CUSTOM_START + i;
1375
1376     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
1377     {
1378       if (check < num_changed_custom_elements)
1379       {
1380         putFile16BitBE(file, element);
1381         putFile16BitBE(file, element_info[element].change->target_element);
1382       }
1383
1384       check++;
1385     }
1386   }
1387
1388   if (check != num_changed_custom_elements)     /* should not happen */
1389     Error(ERR_WARN, "inconsistent number of custom target elements");
1390 }
1391 #endif
1392
1393 #if 0
1394 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
1395                            int num_changed_custom_elements)
1396 {
1397   int i, j, x, y, check = 0;
1398
1399   putFile16BitBE(file, num_changed_custom_elements);
1400
1401   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1402   {
1403     int element = EL_CUSTOM_START + i;
1404
1405     if (element_info[element].modified_settings)
1406     {
1407       if (check < num_changed_custom_elements)
1408       {
1409         putFile16BitBE(file, element);
1410
1411         for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
1412           putFile8Bit(file, element_info[element].description[j]);
1413
1414         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1415
1416         /* some free bytes for future properties and padding */
1417         WriteUnusedBytesToFile(file, 7);
1418
1419         putFile8Bit(file, element_info[element].use_gfx_element);
1420         putFile16BitBE(file, element_info[element].gfx_element);
1421
1422         putFile8Bit(file, element_info[element].collect_score);
1423         putFile8Bit(file, element_info[element].collect_count);
1424
1425         putFile16BitBE(file, element_info[element].push_delay_fixed);
1426         putFile16BitBE(file, element_info[element].push_delay_random);
1427         putFile16BitBE(file, element_info[element].move_delay_fixed);
1428         putFile16BitBE(file, element_info[element].move_delay_random);
1429
1430         putFile16BitBE(file, element_info[element].move_pattern);
1431         putFile8Bit(file, element_info[element].move_direction_initial);
1432         putFile8Bit(file, element_info[element].move_stepsize);
1433
1434         for(y=0; y<3; y++)
1435           for(x=0; x<3; x++)
1436             putFile16BitBE(file, element_info[element].content[x][y]);
1437
1438         putFile32BitBE(file, element_info[element].change->events);
1439
1440         putFile16BitBE(file, element_info[element].change->target_element);
1441
1442         putFile16BitBE(file, element_info[element].change->delay_fixed);
1443         putFile16BitBE(file, element_info[element].change->delay_random);
1444         putFile16BitBE(file, element_info[element].change->delay_frames);
1445
1446         putFile16BitBE(file, element_info[element].change->trigger_element);
1447
1448         putFile8Bit(file, element_info[element].change->explode);
1449         putFile8Bit(file, element_info[element].change->use_content);
1450         putFile8Bit(file, element_info[element].change->only_complete);
1451         putFile8Bit(file, element_info[element].change->use_random_change);
1452
1453         putFile8Bit(file, element_info[element].change->random);
1454         putFile8Bit(file, element_info[element].change->power);
1455
1456         for(y=0; y<3; y++)
1457           for(x=0; x<3; x++)
1458             putFile16BitBE(file, element_info[element].change->content[x][y]);
1459
1460         putFile8Bit(file, element_info[element].slippery_type);
1461
1462         /* some free bytes for future properties and padding */
1463         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
1464       }
1465
1466       check++;
1467     }
1468   }
1469
1470   if (check != num_changed_custom_elements)     /* should not happen */
1471     Error(ERR_WARN, "inconsistent number of custom element properties");
1472 }
1473 #endif
1474
1475 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
1476 {
1477   struct ElementInfo *ei = &element_info[element];
1478   int i, x, y;
1479
1480   putFile16BitBE(file, element);
1481
1482   for(i=0; i < MAX_ELEMENT_NAME_LEN; i++)
1483     putFile8Bit(file, ei->description[i]);
1484
1485   putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1486   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
1487
1488   putFile8Bit(file, ei->num_change_pages);
1489
1490   /* some free bytes for future base property values and padding */
1491   WriteUnusedBytesToFile(file, 5);
1492
1493   /* write custom property values */
1494
1495   putFile8Bit(file, ei->use_gfx_element);
1496   putFile16BitBE(file, ei->gfx_element);
1497
1498   putFile8Bit(file, ei->collect_score);
1499   putFile8Bit(file, ei->collect_count);
1500
1501   putFile16BitBE(file, ei->push_delay_fixed);
1502   putFile16BitBE(file, ei->push_delay_random);
1503   putFile16BitBE(file, ei->move_delay_fixed);
1504   putFile16BitBE(file, ei->move_delay_random);
1505
1506   putFile16BitBE(file, ei->move_pattern);
1507   putFile8Bit(file, ei->move_direction_initial);
1508   putFile8Bit(file, ei->move_stepsize);
1509
1510   putFile8Bit(file, ei->slippery_type);
1511
1512   for(y=0; y<3; y++)
1513     for(x=0; x<3; x++)
1514       putFile16BitBE(file, ei->content[x][y]);
1515
1516   /* some free bytes for future custom property values and padding */
1517   WriteUnusedBytesToFile(file, 12);
1518
1519   /* write change property values */
1520
1521   for (i=0; i < ei->num_change_pages; i++)
1522   {
1523     struct ElementChangeInfo *change = &ei->change_page[i];
1524
1525     putFile32BitBE(file, change->events);
1526
1527     putFile16BitBE(file, change->target_element);
1528
1529     putFile16BitBE(file, change->delay_fixed);
1530     putFile16BitBE(file, change->delay_random);
1531     putFile16BitBE(file, change->delay_frames);
1532
1533     putFile16BitBE(file, change->trigger_element);
1534
1535     putFile8Bit(file, change->explode);
1536     putFile8Bit(file, change->use_content);
1537     putFile8Bit(file, change->only_complete);
1538     putFile8Bit(file, change->use_random_change);
1539
1540     putFile8Bit(file, change->random);
1541     putFile8Bit(file, change->power);
1542
1543     for(y=0; y<3; y++)
1544       for(x=0; x<3; x++)
1545         putFile16BitBE(file, change->content[x][y]);
1546
1547     putFile8Bit(file, change->can_change);
1548
1549     putFile8Bit(file, change->sides);
1550
1551     /* some free bytes for future change property values and padding */
1552     WriteUnusedBytesToFile(file, 8);
1553   }
1554 }
1555
1556 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
1557 {
1558   int body_chunk_size;
1559   int i, x, y;
1560   FILE *file;
1561
1562   if (!(file = fopen(filename, MODE_WRITE)))
1563   {
1564     Error(ERR_WARN, "cannot save level file '%s'", filename);
1565     return;
1566   }
1567
1568   level->file_version = FILE_VERSION_ACTUAL;
1569   level->game_version = GAME_VERSION_ACTUAL;
1570
1571   /* check level field for 16-bit elements */
1572   level->encoding_16bit_field = FALSE;
1573   for(y=0; y<level->fieldy; y++) 
1574     for(x=0; x<level->fieldx; x++) 
1575       if (level->field[x][y] > 255)
1576         level->encoding_16bit_field = TRUE;
1577
1578   /* check yamyam content for 16-bit elements */
1579   level->encoding_16bit_yamyam = FALSE;
1580   for(i=0; i<level->num_yamyam_contents; i++)
1581     for(y=0; y<3; y++)
1582       for(x=0; x<3; x++)
1583         if (level->yamyam_content[i][x][y] > 255)
1584           level->encoding_16bit_yamyam = TRUE;
1585
1586   /* check amoeba content for 16-bit elements */
1587   level->encoding_16bit_amoeba = FALSE;
1588   if (level->amoeba_content > 255)
1589     level->encoding_16bit_amoeba = TRUE;
1590
1591   /* calculate size of "BODY" chunk */
1592   body_chunk_size =
1593     level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
1594
1595   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1596   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
1597
1598   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1599   SaveLevel_VERS(file, level);
1600
1601   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
1602   SaveLevel_HEAD(file, level);
1603
1604   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
1605   SaveLevel_AUTH(file, level);
1606
1607   putFileChunkBE(file, "BODY", body_chunk_size);
1608   SaveLevel_BODY(file, level);
1609
1610   if (level->encoding_16bit_yamyam ||
1611       level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
1612   {
1613     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1614     SaveLevel_CNT2(file, level, EL_YAMYAM);
1615   }
1616
1617   if (level->encoding_16bit_amoeba)
1618   {
1619     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1620     SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
1621   }
1622
1623   /* check for envelope content */
1624   for (i=0; i<4; i++)
1625   {
1626     if (strlen(level->envelope_text[i]) > 0)
1627     {
1628       int envelope_len = strlen(level->envelope_text[i]) + 1;
1629
1630       putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_HEADER + envelope_len);
1631       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
1632     }
1633   }
1634
1635   /* check for non-default custom elements (unless using template level) */
1636   if (!level->use_custom_template)
1637   {
1638     for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1639     {
1640       int element = EL_CUSTOM_START + i;
1641
1642       if (element_info[element].modified_settings)
1643       {
1644         int num_change_pages = element_info[element].num_change_pages;
1645
1646         putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
1647         SaveLevel_CUS4(file, level, element);
1648       }
1649     }
1650   }
1651
1652   fclose(file);
1653
1654   SetFilePermissions(filename, PERMS_PRIVATE);
1655 }
1656
1657 void SaveLevel(int level_nr)
1658 {
1659   char *filename = getLevelFilename(level_nr);
1660
1661   SaveLevelFromFilename(&level, filename);
1662 }
1663
1664 void SaveLevelTemplate()
1665 {
1666   char *filename = getLevelFilename(-1);
1667
1668   SaveLevelFromFilename(&level, filename);
1669 }
1670
1671 void DumpLevel(struct LevelInfo *level)
1672 {
1673   printf_line("-", 79);
1674   printf("Level xxx (file version %08d, game version %08d)\n",
1675          level->file_version, level->game_version);
1676   printf_line("-", 79);
1677
1678   printf("Level Author: '%s'\n", level->author);
1679   printf("Level Title:  '%s'\n", level->name);
1680   printf("\n");
1681   printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
1682   printf("\n");
1683   printf("Level Time:  %d seconds\n", level->time);
1684   printf("Gems needed: %d\n", level->gems_needed);
1685   printf("\n");
1686   printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
1687   printf("Time for Wheel:      %d seconds\n", level->time_wheel);
1688   printf("Time for Light:      %d seconds\n", level->time_light);
1689   printf("Time for Timegate:   %d seconds\n", level->time_timegate);
1690   printf("\n");
1691   printf("Amoeba Speed: %d\n", level->amoeba_speed);
1692   printf("\n");
1693   printf("Gravity:                %s\n", (level->initial_gravity ? "yes" : "no"));
1694   printf("Double Speed Movement:  %s\n", (level->double_speed ? "yes" : "no"));
1695   printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
1696
1697   printf_line("-", 79);
1698 }
1699
1700
1701 /* ========================================================================= */
1702 /* tape file functions                                                       */
1703 /* ========================================================================= */
1704
1705 static void setTapeInfoToDefaults()
1706 {
1707   int i;
1708
1709   /* always start with reliable default values (empty tape) */
1710   TapeErase();
1711
1712   /* default values (also for pre-1.2 tapes) with only the first player */
1713   tape.player_participates[0] = TRUE;
1714   for(i=1; i<MAX_PLAYERS; i++)
1715     tape.player_participates[i] = FALSE;
1716
1717   /* at least one (default: the first) player participates in every tape */
1718   tape.num_participating_players = 1;
1719
1720   tape.level_nr = level_nr;
1721   tape.counter = 0;
1722   tape.changed = FALSE;
1723
1724   tape.recording = FALSE;
1725   tape.playing = FALSE;
1726   tape.pausing = FALSE;
1727 }
1728
1729 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
1730 {
1731   tape->file_version = getFileVersion(file);
1732   tape->game_version = getFileVersion(file);
1733
1734   return chunk_size;
1735 }
1736
1737 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
1738 {
1739   int i;
1740
1741   tape->random_seed = getFile32BitBE(file);
1742   tape->date        = getFile32BitBE(file);
1743   tape->length      = getFile32BitBE(file);
1744
1745   /* read header fields that are new since version 1.2 */
1746   if (tape->file_version >= FILE_VERSION_1_2)
1747   {
1748     byte store_participating_players = getFile8Bit(file);
1749     int engine_version;
1750
1751     /* since version 1.2, tapes store which players participate in the tape */
1752     tape->num_participating_players = 0;
1753     for(i=0; i<MAX_PLAYERS; i++)
1754     {
1755       tape->player_participates[i] = FALSE;
1756
1757       if (store_participating_players & (1 << i))
1758       {
1759         tape->player_participates[i] = TRUE;
1760         tape->num_participating_players++;
1761       }
1762     }
1763
1764     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
1765
1766     engine_version = getFileVersion(file);
1767     if (engine_version > 0)
1768       tape->engine_version = engine_version;
1769     else
1770       tape->engine_version = tape->game_version;
1771   }
1772
1773   return chunk_size;
1774 }
1775
1776 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
1777 {
1778   int level_identifier_size;
1779   int i;
1780
1781   level_identifier_size = getFile16BitBE(file);
1782
1783   tape->level_identifier =
1784     checked_realloc(tape->level_identifier, level_identifier_size);
1785
1786   for(i=0; i < level_identifier_size; i++)
1787     tape->level_identifier[i] = getFile8Bit(file);
1788
1789   tape->level_nr = getFile16BitBE(file);
1790
1791   chunk_size = 2 + level_identifier_size + 2;
1792
1793   return chunk_size;
1794 }
1795
1796 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
1797 {
1798   int i, j;
1799   int chunk_size_expected =
1800     (tape->num_participating_players + 1) * tape->length;
1801
1802   if (chunk_size_expected != chunk_size)
1803   {
1804     ReadUnusedBytesFromFile(file, chunk_size);
1805     return chunk_size_expected;
1806   }
1807
1808   for(i=0; i<tape->length; i++)
1809   {
1810     if (i >= MAX_TAPELEN)
1811       break;
1812
1813     for(j=0; j<MAX_PLAYERS; j++)
1814     {
1815       tape->pos[i].action[j] = MV_NO_MOVING;
1816
1817       if (tape->player_participates[j])
1818         tape->pos[i].action[j] = getFile8Bit(file);
1819     }
1820
1821     tape->pos[i].delay = getFile8Bit(file);
1822
1823     if (tape->file_version == FILE_VERSION_1_0)
1824     {
1825       /* eliminate possible diagonal moves in old tapes */
1826       /* this is only for backward compatibility */
1827
1828       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
1829       byte action = tape->pos[i].action[0];
1830       int k, num_moves = 0;
1831
1832       for (k=0; k<4; k++)
1833       {
1834         if (action & joy_dir[k])
1835         {
1836           tape->pos[i + num_moves].action[0] = joy_dir[k];
1837           if (num_moves > 0)
1838             tape->pos[i + num_moves].delay = 0;
1839           num_moves++;
1840         }
1841       }
1842
1843       if (num_moves > 1)
1844       {
1845         num_moves--;
1846         i += num_moves;
1847         tape->length += num_moves;
1848       }
1849     }
1850     else if (tape->file_version < FILE_VERSION_2_0)
1851     {
1852       /* convert pre-2.0 tapes to new tape format */
1853
1854       if (tape->pos[i].delay > 1)
1855       {
1856         /* action part */
1857         tape->pos[i + 1] = tape->pos[i];
1858         tape->pos[i + 1].delay = 1;
1859
1860         /* delay part */
1861         for(j=0; j<MAX_PLAYERS; j++)
1862           tape->pos[i].action[j] = MV_NO_MOVING;
1863         tape->pos[i].delay--;
1864
1865         i++;
1866         tape->length++;
1867       }
1868     }
1869
1870     if (feof(file))
1871       break;
1872   }
1873
1874   if (i != tape->length)
1875     chunk_size = (tape->num_participating_players + 1) * i;
1876
1877   return chunk_size;
1878 }
1879
1880 void LoadTapeFromFilename(char *filename)
1881 {
1882   char cookie[MAX_LINE_LEN];
1883   char chunk_name[CHUNK_ID_LEN + 1];
1884   FILE *file;
1885   int chunk_size;
1886
1887   /* always start with reliable default values */
1888   setTapeInfoToDefaults();
1889
1890   if (!(file = fopen(filename, MODE_READ)))
1891     return;
1892
1893   getFileChunkBE(file, chunk_name, NULL);
1894   if (strcmp(chunk_name, "RND1") == 0)
1895   {
1896     getFile32BitBE(file);               /* not used */
1897
1898     getFileChunkBE(file, chunk_name, NULL);
1899     if (strcmp(chunk_name, "TAPE") != 0)
1900     {
1901       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1902       fclose(file);
1903       return;
1904     }
1905   }
1906   else  /* check for pre-2.0 file format with cookie string */
1907   {
1908     strcpy(cookie, chunk_name);
1909     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1910     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1911       cookie[strlen(cookie) - 1] = '\0';
1912
1913     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
1914     {
1915       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1916       fclose(file);
1917       return;
1918     }
1919
1920     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
1921     {
1922       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
1923       fclose(file);
1924       return;
1925     }
1926
1927     /* pre-2.0 tape files have no game version, so use file version here */
1928     tape.game_version = tape.file_version;
1929   }
1930
1931   if (tape.file_version < FILE_VERSION_1_2)
1932   {
1933     /* tape files from versions before 1.2.0 without chunk structure */
1934     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
1935     LoadTape_BODY(file, 2 * tape.length,  &tape);
1936   }
1937   else
1938   {
1939     static struct
1940     {
1941       char *name;
1942       int size;
1943       int (*loader)(FILE *, int, struct TapeInfo *);
1944     }
1945     chunk_info[] =
1946     {
1947       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
1948       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
1949       { "INFO", -1,                     LoadTape_INFO },
1950       { "BODY", -1,                     LoadTape_BODY },
1951       {  NULL,  0,                      NULL }
1952     };
1953
1954     while (getFileChunkBE(file, chunk_name, &chunk_size))
1955     {
1956       int i = 0;
1957
1958       while (chunk_info[i].name != NULL &&
1959              strcmp(chunk_name, chunk_info[i].name) != 0)
1960         i++;
1961
1962       if (chunk_info[i].name == NULL)
1963       {
1964         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
1965               chunk_name, filename);
1966         ReadUnusedBytesFromFile(file, chunk_size);
1967       }
1968       else if (chunk_info[i].size != -1 &&
1969                chunk_info[i].size != chunk_size)
1970       {
1971         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1972               chunk_size, chunk_name, filename);
1973         ReadUnusedBytesFromFile(file, chunk_size);
1974       }
1975       else
1976       {
1977         /* call function to load this tape chunk */
1978         int chunk_size_expected =
1979           (chunk_info[i].loader)(file, chunk_size, &tape);
1980
1981         /* the size of some chunks cannot be checked before reading other
1982            chunks first (like "HEAD" and "BODY") that contain some header
1983            information, so check them here */
1984         if (chunk_size_expected != chunk_size)
1985         {
1986           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1987                 chunk_size, chunk_name, filename);
1988         }
1989       }
1990     }
1991   }
1992
1993   fclose(file);
1994
1995   tape.length_seconds = GetTapeLength();
1996
1997 #if 0
1998   printf("tape game version: %d\n", tape.game_version);
1999   printf("tape engine version: %d\n", tape.engine_version);
2000 #endif
2001 }
2002
2003 void LoadTape(int level_nr)
2004 {
2005   char *filename = getTapeFilename(level_nr);
2006
2007   LoadTapeFromFilename(filename);
2008 }
2009
2010 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
2011 {
2012   putFileVersion(file, tape->file_version);
2013   putFileVersion(file, tape->game_version);
2014 }
2015
2016 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
2017 {
2018   int i;
2019   byte store_participating_players = 0;
2020
2021   /* set bits for participating players for compact storage */
2022   for(i=0; i<MAX_PLAYERS; i++)
2023     if (tape->player_participates[i])
2024       store_participating_players |= (1 << i);
2025
2026   putFile32BitBE(file, tape->random_seed);
2027   putFile32BitBE(file, tape->date);
2028   putFile32BitBE(file, tape->length);
2029
2030   putFile8Bit(file, store_participating_players);
2031
2032   /* unused bytes not at the end here for 4-byte alignment of engine_version */
2033   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
2034
2035   putFileVersion(file, tape->engine_version);
2036 }
2037
2038 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
2039 {
2040   int level_identifier_size = strlen(tape->level_identifier) + 1;
2041   int i;
2042
2043   putFile16BitBE(file, level_identifier_size);
2044
2045   for(i=0; i < level_identifier_size; i++)
2046     putFile8Bit(file, tape->level_identifier[i]);
2047
2048   putFile16BitBE(file, tape->level_nr);
2049 }
2050
2051 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
2052 {
2053   int i, j;
2054
2055   for(i=0; i<tape->length; i++)
2056   {
2057     for(j=0; j<MAX_PLAYERS; j++)
2058       if (tape->player_participates[j])
2059         putFile8Bit(file, tape->pos[i].action[j]);
2060
2061     putFile8Bit(file, tape->pos[i].delay);
2062   }
2063 }
2064
2065 void SaveTape(int level_nr)
2066 {
2067   char *filename = getTapeFilename(level_nr);
2068   FILE *file;
2069   boolean new_tape = TRUE;
2070   int num_participating_players = 0;
2071   int info_chunk_size;
2072   int body_chunk_size;
2073   int i;
2074
2075   InitTapeDirectory(leveldir_current->filename);
2076
2077   /* if a tape still exists, ask to overwrite it */
2078   if (access(filename, F_OK) == 0)
2079   {
2080     new_tape = FALSE;
2081     if (!Request("Replace old tape ?", REQ_ASK))
2082       return;
2083   }
2084
2085   if (!(file = fopen(filename, MODE_WRITE)))
2086   {
2087     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
2088     return;
2089   }
2090
2091   tape.file_version = FILE_VERSION_ACTUAL;
2092   tape.game_version = GAME_VERSION_ACTUAL;
2093
2094   /* count number of participating players  */
2095   for(i=0; i<MAX_PLAYERS; i++)
2096     if (tape.player_participates[i])
2097       num_participating_players++;
2098
2099   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
2100   body_chunk_size = (num_participating_players + 1) * tape.length;
2101
2102   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
2103   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
2104
2105   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
2106   SaveTape_VERS(file, &tape);
2107
2108   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
2109   SaveTape_HEAD(file, &tape);
2110
2111   putFileChunkBE(file, "INFO", info_chunk_size);
2112   SaveTape_INFO(file, &tape);
2113
2114   putFileChunkBE(file, "BODY", body_chunk_size);
2115   SaveTape_BODY(file, &tape);
2116
2117   fclose(file);
2118
2119   SetFilePermissions(filename, PERMS_PRIVATE);
2120
2121   tape.changed = FALSE;
2122
2123   if (new_tape)
2124     Request("tape saved !", REQ_CONFIRM);
2125 }
2126
2127 void DumpTape(struct TapeInfo *tape)
2128 {
2129   int i, j;
2130
2131   if (TAPE_IS_EMPTY(*tape))
2132   {
2133     Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
2134     return;
2135   }
2136
2137   printf_line("-", 79);
2138   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
2139          tape->level_nr, tape->file_version, tape->game_version);
2140   printf("Level series identifier: '%s'\n", tape->level_identifier);
2141   printf_line("-", 79);
2142
2143   for(i=0; i<tape->length; i++)
2144   {
2145     if (i >= MAX_TAPELEN)
2146       break;
2147
2148     printf("%03d: ", i);
2149
2150     for(j=0; j<MAX_PLAYERS; j++)
2151     {
2152       if (tape->player_participates[j])
2153       {
2154         int action = tape->pos[i].action[j];
2155
2156         printf("%d:%02x ", j, action);
2157         printf("[%c%c%c%c|%c%c] - ",
2158                (action & JOY_LEFT ? '<' : ' '),
2159                (action & JOY_RIGHT ? '>' : ' '),
2160                (action & JOY_UP ? '^' : ' '),
2161                (action & JOY_DOWN ? 'v' : ' '),
2162                (action & JOY_BUTTON_1 ? '1' : ' '),
2163                (action & JOY_BUTTON_2 ? '2' : ' '));
2164       }
2165     }
2166
2167     printf("(%03d)\n", tape->pos[i].delay);
2168   }
2169
2170   printf_line("-", 79);
2171 }
2172
2173
2174 /* ========================================================================= */
2175 /* score file functions                                                      */
2176 /* ========================================================================= */
2177
2178 void LoadScore(int level_nr)
2179 {
2180   int i;
2181   char *filename = getScoreFilename(level_nr);
2182   char cookie[MAX_LINE_LEN];
2183   char line[MAX_LINE_LEN];
2184   char *line_ptr;
2185   FILE *file;
2186
2187   /* always start with reliable default values */
2188   for(i=0; i<MAX_SCORE_ENTRIES; i++)
2189   {
2190     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
2191     highscore[i].Score = 0;
2192   }
2193
2194   if (!(file = fopen(filename, MODE_READ)))
2195     return;
2196
2197   /* check file identifier */
2198   fgets(cookie, MAX_LINE_LEN, file);
2199   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
2200     cookie[strlen(cookie) - 1] = '\0';
2201
2202   if (!checkCookieString(cookie, SCORE_COOKIE))
2203   {
2204     Error(ERR_WARN, "unknown format of score file '%s'", filename);
2205     fclose(file);
2206     return;
2207   }
2208
2209   for(i=0; i<MAX_SCORE_ENTRIES; i++)
2210   {
2211     fscanf(file, "%d", &highscore[i].Score);
2212     fgets(line, MAX_LINE_LEN, file);
2213
2214     if (line[strlen(line) - 1] == '\n')
2215       line[strlen(line) - 1] = '\0';
2216
2217     for (line_ptr = line; *line_ptr; line_ptr++)
2218     {
2219       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
2220       {
2221         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
2222         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
2223         break;
2224       }
2225     }
2226   }
2227
2228   fclose(file);
2229 }
2230
2231 void SaveScore(int level_nr)
2232 {
2233   int i;
2234   char *filename = getScoreFilename(level_nr);
2235   FILE *file;
2236
2237   InitScoreDirectory(leveldir_current->filename);
2238
2239   if (!(file = fopen(filename, MODE_WRITE)))
2240   {
2241     Error(ERR_WARN, "cannot save score for level %d", level_nr);
2242     return;
2243   }
2244
2245   fprintf(file, "%s\n\n", SCORE_COOKIE);
2246
2247   for(i=0; i<MAX_SCORE_ENTRIES; i++)
2248     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
2249
2250   fclose(file);
2251
2252   SetFilePermissions(filename, PERMS_PUBLIC);
2253 }
2254
2255
2256 /* ========================================================================= */
2257 /* setup file functions                                                      */
2258 /* ========================================================================= */
2259
2260 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
2261
2262 /* global setup */
2263 #define SETUP_TOKEN_PLAYER_NAME                 0
2264 #define SETUP_TOKEN_SOUND                       1
2265 #define SETUP_TOKEN_SOUND_LOOPS                 2
2266 #define SETUP_TOKEN_SOUND_MUSIC                 3
2267 #define SETUP_TOKEN_SOUND_SIMPLE                4
2268 #define SETUP_TOKEN_TOONS                       5
2269 #define SETUP_TOKEN_SCROLL_DELAY                6
2270 #define SETUP_TOKEN_SOFT_SCROLLING              7
2271 #define SETUP_TOKEN_FADING                      8
2272 #define SETUP_TOKEN_AUTORECORD                  9
2273 #define SETUP_TOKEN_QUICK_DOORS                 10
2274 #define SETUP_TOKEN_TEAM_MODE                   11
2275 #define SETUP_TOKEN_HANDICAP                    12
2276 #define SETUP_TOKEN_TIME_LIMIT                  13
2277 #define SETUP_TOKEN_FULLSCREEN                  14
2278 #define SETUP_TOKEN_ASK_ON_ESCAPE               15
2279 #define SETUP_TOKEN_GRAPHICS_SET                16
2280 #define SETUP_TOKEN_SOUNDS_SET                  17
2281 #define SETUP_TOKEN_MUSIC_SET                   18
2282 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     19
2283 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       20
2284 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        21
2285
2286 #define NUM_GLOBAL_SETUP_TOKENS                 22
2287
2288 /* editor setup */
2289 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
2290 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
2291 #define SETUP_TOKEN_EDITOR_EL_MORE              2
2292 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           3
2293 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          4
2294 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     5
2295 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    6
2296 #define SETUP_TOKEN_EDITOR_EL_CHARS             7
2297 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            8
2298 #define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE       9
2299 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         10
2300
2301 #define NUM_EDITOR_SETUP_TOKENS                 11
2302
2303 /* shortcut setup */
2304 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
2305 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
2306 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
2307
2308 #define NUM_SHORTCUT_SETUP_TOKENS               3
2309
2310 /* player setup */
2311 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
2312 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
2313 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
2314 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
2315 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
2316 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
2317 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
2318 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
2319 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
2320 #define SETUP_TOKEN_PLAYER_JOY_BOMB             9
2321 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
2322 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
2323 #define SETUP_TOKEN_PLAYER_KEY_UP               12
2324 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
2325 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
2326 #define SETUP_TOKEN_PLAYER_KEY_BOMB             15
2327
2328 #define NUM_PLAYER_SETUP_TOKENS                 16
2329
2330 /* system setup */
2331 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
2332 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
2333
2334 #define NUM_SYSTEM_SETUP_TOKENS                 2
2335
2336 /* options setup */
2337 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
2338
2339 #define NUM_OPTIONS_SETUP_TOKENS                1
2340
2341
2342 static struct SetupInfo si;
2343 static struct SetupEditorInfo sei;
2344 static struct SetupShortcutInfo ssi;
2345 static struct SetupInputInfo sii;
2346 static struct SetupSystemInfo syi;
2347 static struct OptionInfo soi;
2348
2349 static struct TokenInfo global_setup_tokens[] =
2350 {
2351   { TYPE_STRING, &si.player_name,       "player_name"                   },
2352   { TYPE_SWITCH, &si.sound,             "sound"                         },
2353   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
2354   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
2355   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
2356   { TYPE_SWITCH, &si.toons,             "toons"                         },
2357   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
2358   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
2359   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
2360   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
2361   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
2362   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
2363   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
2364   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
2365   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
2366   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
2367   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
2368   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
2369   { TYPE_STRING, &si.music_set,         "music_set"                     },
2370   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
2371   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
2372   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
2373 };
2374
2375 static struct TokenInfo editor_setup_tokens[] =
2376 {
2377   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
2378   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
2379   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
2380   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
2381   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
2382   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
2383   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
2384   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
2385   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
2386   { TYPE_SWITCH, &sei.el_custom_more,   "editor.el_custom_more"         },
2387   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
2388 };
2389
2390 static struct TokenInfo shortcut_setup_tokens[] =
2391 {
2392   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
2393   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
2394   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         }
2395 };
2396
2397 static struct TokenInfo player_setup_tokens[] =
2398 {
2399   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
2400   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
2401   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
2402   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
2403   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
2404   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
2405   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
2406   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
2407   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
2408   { TYPE_INTEGER, &sii.joy.bomb,        ".joy.place_bomb"               },
2409   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
2410   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
2411   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
2412   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
2413   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
2414   { TYPE_KEY_X11, &sii.key.bomb,        ".key.place_bomb"               }
2415 };
2416
2417 static struct TokenInfo system_setup_tokens[] =
2418 {
2419   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
2420   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
2421 };
2422
2423 static struct TokenInfo options_setup_tokens[] =
2424 {
2425   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               }
2426 };
2427
2428 static char *get_corrected_login_name(char *login_name)
2429 {
2430   /* needed because player name must be a fixed length string */
2431   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
2432
2433   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
2434   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
2435
2436   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
2437     if (strchr(login_name_new, ' '))
2438       *strchr(login_name_new, ' ') = '\0';
2439
2440   return login_name_new;
2441 }
2442
2443 static void setSetupInfoToDefaults(struct SetupInfo *si)
2444 {
2445   int i;
2446
2447   si->player_name = get_corrected_login_name(getLoginName());
2448
2449   si->sound = TRUE;
2450   si->sound_loops = TRUE;
2451   si->sound_music = TRUE;
2452   si->sound_simple = TRUE;
2453   si->toons = TRUE;
2454   si->double_buffering = TRUE;
2455   si->direct_draw = !si->double_buffering;
2456   si->scroll_delay = TRUE;
2457   si->soft_scrolling = TRUE;
2458   si->fading = FALSE;
2459   si->autorecord = TRUE;
2460   si->quick_doors = FALSE;
2461   si->team_mode = FALSE;
2462   si->handicap = TRUE;
2463   si->time_limit = TRUE;
2464   si->fullscreen = FALSE;
2465   si->ask_on_escape = TRUE;
2466
2467   si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
2468   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
2469   si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
2470   si->override_level_graphics = FALSE;
2471   si->override_level_sounds = FALSE;
2472   si->override_level_music = FALSE;
2473
2474   si->editor.el_boulderdash = TRUE;
2475   si->editor.el_emerald_mine = TRUE;
2476   si->editor.el_more = TRUE;
2477   si->editor.el_sokoban = TRUE;
2478   si->editor.el_supaplex = TRUE;
2479   si->editor.el_diamond_caves = TRUE;
2480   si->editor.el_dx_boulderdash = TRUE;
2481   si->editor.el_chars = TRUE;
2482   si->editor.el_custom = TRUE;
2483   si->editor.el_custom_more = FALSE;
2484
2485   si->editor.el_headlines = TRUE;
2486
2487   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
2488   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
2489   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
2490
2491   for (i=0; i<MAX_PLAYERS; i++)
2492   {
2493     si->input[i].use_joystick = FALSE;
2494     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
2495     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
2496     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
2497     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
2498     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
2499     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
2500     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
2501     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
2502     si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
2503     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
2504     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
2505     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
2506     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
2507     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
2508     si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
2509   }
2510
2511   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
2512   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
2513
2514   si->options.verbose = FALSE;
2515 }
2516
2517 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
2518 {
2519   int i, pnr;
2520
2521   if (!setup_file_hash)
2522     return;
2523
2524   /* global setup */
2525   si = setup;
2526   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
2527     setSetupInfo(global_setup_tokens, i,
2528                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
2529   setup = si;
2530
2531   /* editor setup */
2532   sei = setup.editor;
2533   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
2534     setSetupInfo(editor_setup_tokens, i,
2535                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
2536   setup.editor = sei;
2537
2538   /* shortcut setup */
2539   ssi = setup.shortcut;
2540   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
2541     setSetupInfo(shortcut_setup_tokens, i,
2542                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
2543   setup.shortcut = ssi;
2544
2545   /* player setup */
2546   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
2547   {
2548     char prefix[30];
2549
2550     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
2551
2552     sii = setup.input[pnr];
2553     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
2554     {
2555       char full_token[100];
2556
2557       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
2558       setSetupInfo(player_setup_tokens, i,
2559                    getHashEntry(setup_file_hash, full_token));
2560     }
2561     setup.input[pnr] = sii;
2562   }
2563
2564   /* system setup */
2565   syi = setup.system;
2566   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
2567     setSetupInfo(system_setup_tokens, i,
2568                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
2569   setup.system = syi;
2570
2571   /* options setup */
2572   soi = setup.options;
2573   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2574     setSetupInfo(options_setup_tokens, i,
2575                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
2576   setup.options = soi;
2577 }
2578
2579 void LoadSetup()
2580 {
2581   char *filename = getSetupFilename();
2582   SetupFileHash *setup_file_hash = NULL;
2583
2584   /* always start with reliable default values */
2585   setSetupInfoToDefaults(&setup);
2586
2587   setup_file_hash = loadSetupFileHash(filename);
2588
2589   if (setup_file_hash)
2590   {
2591     char *player_name_new;
2592
2593     checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
2594     decodeSetupFileHash(setup_file_hash);
2595
2596     setup.direct_draw = !setup.double_buffering;
2597
2598     freeSetupFileHash(setup_file_hash);
2599
2600     /* needed to work around problems with fixed length strings */
2601     player_name_new = get_corrected_login_name(setup.player_name);
2602     free(setup.player_name);
2603     setup.player_name = player_name_new;
2604   }
2605   else
2606     Error(ERR_WARN, "using default setup values");
2607 }
2608
2609 void SaveSetup()
2610 {
2611   char *filename = getSetupFilename();
2612   FILE *file;
2613   int i, pnr;
2614
2615   InitUserDataDirectory();
2616
2617   if (!(file = fopen(filename, MODE_WRITE)))
2618   {
2619     Error(ERR_WARN, "cannot write setup file '%s'", filename);
2620     return;
2621   }
2622
2623   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
2624                                                getCookie("SETUP")));
2625   fprintf(file, "\n");
2626
2627   /* global setup */
2628   si = setup;
2629   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
2630   {
2631     /* just to make things nicer :) */
2632     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
2633         i == SETUP_TOKEN_GRAPHICS_SET)
2634       fprintf(file, "\n");
2635
2636     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
2637   }
2638
2639   /* editor setup */
2640   sei = setup.editor;
2641   fprintf(file, "\n");
2642   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
2643     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
2644
2645   /* shortcut setup */
2646   ssi = setup.shortcut;
2647   fprintf(file, "\n");
2648   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
2649     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
2650
2651   /* player setup */
2652   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
2653   {
2654     char prefix[30];
2655
2656     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
2657     fprintf(file, "\n");
2658
2659     sii = setup.input[pnr];
2660     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
2661       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
2662   }
2663
2664   /* system setup */
2665   syi = setup.system;
2666   fprintf(file, "\n");
2667   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
2668     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
2669
2670   /* options setup */
2671   soi = setup.options;
2672   fprintf(file, "\n");
2673   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2674     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
2675
2676   fclose(file);
2677
2678   SetFilePermissions(filename, PERMS_PRIVATE);
2679 }
2680
2681 void LoadCustomElementDescriptions()
2682 {
2683   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2684   SetupFileHash *setup_file_hash;
2685   int i;
2686
2687   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2688   {
2689     if (element_info[i].custom_description != NULL)
2690     {
2691       free(element_info[i].custom_description);
2692       element_info[i].custom_description = NULL;
2693     }
2694   }
2695
2696   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2697     return;
2698
2699   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2700   {
2701     char *token = getStringCat2(element_info[i].token_name, ".name");
2702     char *value = getHashEntry(setup_file_hash, token);
2703
2704     if (value != NULL)
2705       element_info[i].custom_description = getStringCopy(value);
2706
2707     free(token);
2708   }
2709
2710   freeSetupFileHash(setup_file_hash);
2711 }
2712
2713 void LoadSpecialMenuDesignSettings()
2714 {
2715   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2716   SetupFileHash *setup_file_hash;
2717   int i, j;
2718
2719   /* always start with reliable default values from default config */
2720   for (i=0; image_config_vars[i].token != NULL; i++)
2721     for (j=0; image_config[j].token != NULL; j++)
2722       if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
2723         *image_config_vars[i].value =
2724           get_auto_parameter_value(image_config_vars[i].token,
2725                                    image_config[j].value);
2726
2727   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2728     return;
2729
2730   /* special case: initialize with default values that may be overwritten */
2731   for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
2732   {
2733     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
2734     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
2735     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
2736
2737     if (value_x != NULL)
2738       menu.draw_xoffset[i] = get_integer_from_string(value_x);
2739     if (value_y != NULL)
2740       menu.draw_yoffset[i] = get_integer_from_string(value_y);
2741     if (list_size != NULL)
2742       menu.list_size[i] = get_integer_from_string(list_size);
2743   }
2744
2745   /* read (and overwrite with) values that may be specified in config file */
2746   for (i=0; image_config_vars[i].token != NULL; i++)
2747   {
2748     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
2749
2750     if (value != NULL)
2751       *image_config_vars[i].value =
2752         get_auto_parameter_value(image_config_vars[i].token, value);
2753   }
2754
2755   freeSetupFileHash(setup_file_hash);
2756 }