rnd-20031102-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * files.c                                                  *
12 ***********************************************************/
13
14 #include <ctype.h>
15 #include <sys/stat.h>
16
17 #include "libgame/libgame.h"
18
19 #include "files.h"
20 #include "init.h"
21 #include "tools.h"
22 #include "tape.h"
23
24
25 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
26 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
27 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
28 #define FILE_VERS_CHUNK_SIZE    8       /* size of file version chunk */
29 #define LEVEL_HEADER_SIZE       80      /* size of level file header  */
30 #define LEVEL_HEADER_UNUSED     13      /* unused level header bytes  */
31 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
32 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
33 #define LEVEL_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 0
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,0))
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 0
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,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,0))
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 #if 0
1082   /* set default push delay values (corrected since version 3.0.7-1) */
1083   if (level->game_version < VERSION_IDENT(3,0,7,1))
1084   {
1085     game.default_push_delay_fixed = 2;
1086     game.default_push_delay_random = 8;
1087   }
1088   else
1089   {
1090     game.default_push_delay_fixed = 8;
1091     game.default_push_delay_random = 8;
1092   }
1093
1094   /* set uninitialized push delay values of custom elements in older levels */
1095   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1096   {
1097     int element = EL_CUSTOM_START + i;
1098
1099     if (element_info[element].push_delay_fixed == -1)
1100       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
1101     if (element_info[element].push_delay_random == -1)
1102       element_info[element].push_delay_random = game.default_push_delay_random;
1103   }
1104 #endif
1105
1106   /* initialize element properties for level editor etc. */
1107   InitElementPropertiesEngine(level->game_version);
1108 }
1109
1110 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
1111 {
1112   int x, y;
1113
1114   /* map elements that have changed in newer versions */
1115   for(y=0; y<level->fieldy; y++)
1116   {
1117     for(x=0; x<level->fieldx; x++)
1118     {
1119       int element = level->field[x][y];
1120
1121       if (level->game_version <= VERSION_IDENT(2,2,0,0))
1122       {
1123         /* map game font elements */
1124         element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
1125                    element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
1126                    element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
1127                    element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
1128       }
1129
1130       if (level->game_version < VERSION_IDENT(3,0,0,0))
1131       {
1132         /* map Supaplex gravity tube elements */
1133         element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
1134                    element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
1135                    element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
1136                    element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
1137                    element);
1138       }
1139
1140       level->field[x][y] = element;
1141     }
1142   }
1143
1144   /* copy elements to runtime playfield array */
1145   for(x=0; x<MAX_LEV_FIELDX; x++)
1146     for(y=0; y<MAX_LEV_FIELDY; y++)
1147       Feld[x][y] = level->field[x][y];
1148
1149   /* initialize level size variables for faster access */
1150   lev_fieldx = level->fieldx;
1151   lev_fieldy = level->fieldy;
1152
1153   /* determine border element for this level */
1154   SetBorderElement();
1155 }
1156
1157 void LoadLevelTemplate(int level_nr)
1158 {
1159   char *filename = getLevelFilename(level_nr);
1160
1161   LoadLevelFromFilename(&level_template, filename);
1162
1163   LoadLevel_InitVersion(&level, filename);
1164   LoadLevel_InitElements(&level, filename);
1165
1166   ActivateLevelTemplate();
1167 }
1168
1169 void LoadLevel(int level_nr)
1170 {
1171   char *filename = getLevelFilename(level_nr);
1172
1173   LoadLevelFromFilename(&level, filename);
1174
1175   if (level.use_custom_template)
1176     LoadLevelTemplate(-1);
1177
1178 #if 1
1179   LoadLevel_InitVersion(&level, filename);
1180   LoadLevel_InitElements(&level, filename);
1181   LoadLevel_InitPlayfield(&level, filename);
1182 #else
1183   LoadLevel_InitLevel(&level, filename);
1184 #endif
1185 }
1186
1187 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
1188 {
1189   putFileVersion(file, level->file_version);
1190   putFileVersion(file, level->game_version);
1191 }
1192
1193 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
1194 {
1195   int i, x, y;
1196
1197   putFile8Bit(file, level->fieldx);
1198   putFile8Bit(file, level->fieldy);
1199
1200   putFile16BitBE(file, level->time);
1201   putFile16BitBE(file, level->gems_needed);
1202
1203   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
1204     putFile8Bit(file, level->name[i]);
1205
1206   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
1207     putFile8Bit(file, level->score[i]);
1208
1209   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
1210     for(y=0; y<3; y++)
1211       for(x=0; x<3; x++)
1212         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
1213                            level->yamyam_content[i][x][y]));
1214   putFile8Bit(file, level->amoeba_speed);
1215   putFile8Bit(file, level->time_magic_wall);
1216   putFile8Bit(file, level->time_wheel);
1217   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
1218                      level->amoeba_content));
1219   putFile8Bit(file, (level->double_speed ? 1 : 0));
1220   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
1221   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
1222   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
1223
1224   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
1225
1226   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
1227 }
1228
1229 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
1230 {
1231   int i;
1232
1233   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
1234     putFile8Bit(file, level->author[i]);
1235 }
1236
1237 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
1238 {
1239   int x, y;
1240
1241   for(y=0; y<level->fieldy; y++) 
1242     for(x=0; x<level->fieldx; x++) 
1243       if (level->encoding_16bit_field)
1244         putFile16BitBE(file, level->field[x][y]);
1245       else
1246         putFile8Bit(file, level->field[x][y]);
1247 }
1248
1249 #if 0
1250 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
1251 {
1252   int i, x, y;
1253
1254   putFile8Bit(file, EL_YAMYAM);
1255   putFile8Bit(file, level->num_yamyam_contents);
1256   putFile8Bit(file, 0);
1257   putFile8Bit(file, 0);
1258
1259   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1260     for(y=0; y<3; y++)
1261       for(x=0; x<3; x++)
1262         if (level->encoding_16bit_field)
1263           putFile16BitBE(file, level->yamyam_content[i][x][y]);
1264         else
1265           putFile8Bit(file, level->yamyam_content[i][x][y]);
1266 }
1267 #endif
1268
1269 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
1270 {
1271   int i, x, y;
1272   int num_contents, content_xsize, content_ysize;
1273   int content_array[MAX_ELEMENT_CONTENTS][3][3];
1274
1275   if (element == EL_YAMYAM)
1276   {
1277     num_contents = level->num_yamyam_contents;
1278     content_xsize = 3;
1279     content_ysize = 3;
1280
1281     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1282       for(y=0; y<3; y++)
1283         for(x=0; x<3; x++)
1284           content_array[i][x][y] = level->yamyam_content[i][x][y];
1285   }
1286   else if (element == EL_BD_AMOEBA)
1287   {
1288     num_contents = 1;
1289     content_xsize = 1;
1290     content_ysize = 1;
1291
1292     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1293       for(y=0; y<3; y++)
1294         for(x=0; x<3; x++)
1295           content_array[i][x][y] = EL_EMPTY;
1296     content_array[0][0][0] = level->amoeba_content;
1297   }
1298   else
1299   {
1300     /* chunk header already written -- write empty chunk data */
1301     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
1302
1303     Error(ERR_WARN, "cannot save content for element '%d'", element);
1304     return;
1305   }
1306
1307   putFile16BitBE(file, element);
1308   putFile8Bit(file, num_contents);
1309   putFile8Bit(file, content_xsize);
1310   putFile8Bit(file, content_ysize);
1311
1312   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
1313
1314   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
1315     for(y=0; y<3; y++)
1316       for(x=0; x<3; x++)
1317         putFile16BitBE(file, content_array[i][x][y]);
1318 }
1319
1320 static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
1321 {
1322   int i;
1323   int envelope_nr = element - EL_ENVELOPE_1;
1324   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
1325
1326   putFile16BitBE(file, element);
1327   putFile16BitBE(file, envelope_len);
1328   putFile8Bit(file, level->envelope_xsize[envelope_nr]);
1329   putFile8Bit(file, level->envelope_ysize[envelope_nr]);
1330
1331   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
1332
1333   for(i=0; i < envelope_len; i++)
1334     putFile8Bit(file, level->envelope_text[envelope_nr][i]);
1335 }
1336
1337 #if 0
1338 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
1339                            int num_changed_custom_elements)
1340 {
1341   int i, check = 0;
1342
1343   putFile16BitBE(file, num_changed_custom_elements);
1344
1345   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1346   {
1347     int element = EL_CUSTOM_START + i;
1348
1349     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
1350     {
1351       if (check < num_changed_custom_elements)
1352       {
1353         putFile16BitBE(file, element);
1354         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1355       }
1356
1357       check++;
1358     }
1359   }
1360
1361   if (check != num_changed_custom_elements)     /* should not happen */
1362     Error(ERR_WARN, "inconsistent number of custom element properties");
1363 }
1364 #endif
1365
1366 #if 0
1367 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
1368                            int num_changed_custom_elements)
1369 {
1370   int i, check = 0;
1371
1372   putFile16BitBE(file, num_changed_custom_elements);
1373
1374   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1375   {
1376     int element = EL_CUSTOM_START + i;
1377
1378     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
1379     {
1380       if (check < num_changed_custom_elements)
1381       {
1382         putFile16BitBE(file, element);
1383         putFile16BitBE(file, element_info[element].change->target_element);
1384       }
1385
1386       check++;
1387     }
1388   }
1389
1390   if (check != num_changed_custom_elements)     /* should not happen */
1391     Error(ERR_WARN, "inconsistent number of custom target elements");
1392 }
1393 #endif
1394
1395 #if 0
1396 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
1397                            int num_changed_custom_elements)
1398 {
1399   int i, j, x, y, check = 0;
1400
1401   putFile16BitBE(file, num_changed_custom_elements);
1402
1403   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1404   {
1405     int element = EL_CUSTOM_START + i;
1406
1407     if (element_info[element].modified_settings)
1408     {
1409       if (check < num_changed_custom_elements)
1410       {
1411         putFile16BitBE(file, element);
1412
1413         for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
1414           putFile8Bit(file, element_info[element].description[j]);
1415
1416         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1417
1418         /* some free bytes for future properties and padding */
1419         WriteUnusedBytesToFile(file, 7);
1420
1421         putFile8Bit(file, element_info[element].use_gfx_element);
1422         putFile16BitBE(file, element_info[element].gfx_element);
1423
1424         putFile8Bit(file, element_info[element].collect_score);
1425         putFile8Bit(file, element_info[element].collect_count);
1426
1427         putFile16BitBE(file, element_info[element].push_delay_fixed);
1428         putFile16BitBE(file, element_info[element].push_delay_random);
1429         putFile16BitBE(file, element_info[element].move_delay_fixed);
1430         putFile16BitBE(file, element_info[element].move_delay_random);
1431
1432         putFile16BitBE(file, element_info[element].move_pattern);
1433         putFile8Bit(file, element_info[element].move_direction_initial);
1434         putFile8Bit(file, element_info[element].move_stepsize);
1435
1436         for(y=0; y<3; y++)
1437           for(x=0; x<3; x++)
1438             putFile16BitBE(file, element_info[element].content[x][y]);
1439
1440         putFile32BitBE(file, element_info[element].change->events);
1441
1442         putFile16BitBE(file, element_info[element].change->target_element);
1443
1444         putFile16BitBE(file, element_info[element].change->delay_fixed);
1445         putFile16BitBE(file, element_info[element].change->delay_random);
1446         putFile16BitBE(file, element_info[element].change->delay_frames);
1447
1448         putFile16BitBE(file, element_info[element].change->trigger_element);
1449
1450         putFile8Bit(file, element_info[element].change->explode);
1451         putFile8Bit(file, element_info[element].change->use_content);
1452         putFile8Bit(file, element_info[element].change->only_complete);
1453         putFile8Bit(file, element_info[element].change->use_random_change);
1454
1455         putFile8Bit(file, element_info[element].change->random);
1456         putFile8Bit(file, element_info[element].change->power);
1457
1458         for(y=0; y<3; y++)
1459           for(x=0; x<3; x++)
1460             putFile16BitBE(file, element_info[element].change->content[x][y]);
1461
1462         putFile8Bit(file, element_info[element].slippery_type);
1463
1464         /* some free bytes for future properties and padding */
1465         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
1466       }
1467
1468       check++;
1469     }
1470   }
1471
1472   if (check != num_changed_custom_elements)     /* should not happen */
1473     Error(ERR_WARN, "inconsistent number of custom element properties");
1474 }
1475 #endif
1476
1477 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
1478 {
1479   struct ElementInfo *ei = &element_info[element];
1480   int i, x, y;
1481
1482   putFile16BitBE(file, element);
1483
1484   for(i=0; i < MAX_ELEMENT_NAME_LEN; i++)
1485     putFile8Bit(file, ei->description[i]);
1486
1487   putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
1488   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
1489
1490   putFile8Bit(file, ei->num_change_pages);
1491
1492   /* some free bytes for future base property values and padding */
1493   WriteUnusedBytesToFile(file, 5);
1494
1495   /* write custom property values */
1496
1497   putFile8Bit(file, ei->use_gfx_element);
1498   putFile16BitBE(file, ei->gfx_element);
1499
1500   putFile8Bit(file, ei->collect_score);
1501   putFile8Bit(file, ei->collect_count);
1502
1503   putFile16BitBE(file, ei->push_delay_fixed);
1504   putFile16BitBE(file, ei->push_delay_random);
1505   putFile16BitBE(file, ei->move_delay_fixed);
1506   putFile16BitBE(file, ei->move_delay_random);
1507
1508   putFile16BitBE(file, ei->move_pattern);
1509   putFile8Bit(file, ei->move_direction_initial);
1510   putFile8Bit(file, ei->move_stepsize);
1511
1512   putFile8Bit(file, ei->slippery_type);
1513
1514   for(y=0; y<3; y++)
1515     for(x=0; x<3; x++)
1516       putFile16BitBE(file, ei->content[x][y]);
1517
1518   /* some free bytes for future custom property values and padding */
1519   WriteUnusedBytesToFile(file, 12);
1520
1521   /* write change property values */
1522
1523   for (i=0; i < ei->num_change_pages; i++)
1524   {
1525     struct ElementChangeInfo *change = &ei->change_page[i];
1526
1527     putFile32BitBE(file, change->events);
1528
1529     putFile16BitBE(file, change->target_element);
1530
1531     putFile16BitBE(file, change->delay_fixed);
1532     putFile16BitBE(file, change->delay_random);
1533     putFile16BitBE(file, change->delay_frames);
1534
1535     putFile16BitBE(file, change->trigger_element);
1536
1537     putFile8Bit(file, change->explode);
1538     putFile8Bit(file, change->use_content);
1539     putFile8Bit(file, change->only_complete);
1540     putFile8Bit(file, change->use_random_change);
1541
1542     putFile8Bit(file, change->random);
1543     putFile8Bit(file, change->power);
1544
1545     for(y=0; y<3; y++)
1546       for(x=0; x<3; x++)
1547         putFile16BitBE(file, change->content[x][y]);
1548
1549     putFile8Bit(file, change->can_change);
1550
1551     putFile8Bit(file, change->sides);
1552
1553     /* some free bytes for future change property values and padding */
1554     WriteUnusedBytesToFile(file, 8);
1555   }
1556 }
1557
1558 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
1559 {
1560   int body_chunk_size;
1561   int i, x, y;
1562   FILE *file;
1563
1564   if (!(file = fopen(filename, MODE_WRITE)))
1565   {
1566     Error(ERR_WARN, "cannot save level file '%s'", filename);
1567     return;
1568   }
1569
1570   level->file_version = FILE_VERSION_ACTUAL;
1571   level->game_version = GAME_VERSION_ACTUAL;
1572
1573   /* check level field for 16-bit elements */
1574   level->encoding_16bit_field = FALSE;
1575   for(y=0; y<level->fieldy; y++) 
1576     for(x=0; x<level->fieldx; x++) 
1577       if (level->field[x][y] > 255)
1578         level->encoding_16bit_field = TRUE;
1579
1580   /* check yamyam content for 16-bit elements */
1581   level->encoding_16bit_yamyam = FALSE;
1582   for(i=0; i<level->num_yamyam_contents; i++)
1583     for(y=0; y<3; y++)
1584       for(x=0; x<3; x++)
1585         if (level->yamyam_content[i][x][y] > 255)
1586           level->encoding_16bit_yamyam = TRUE;
1587
1588   /* check amoeba content for 16-bit elements */
1589   level->encoding_16bit_amoeba = FALSE;
1590   if (level->amoeba_content > 255)
1591     level->encoding_16bit_amoeba = TRUE;
1592
1593   /* calculate size of "BODY" chunk */
1594   body_chunk_size =
1595     level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
1596
1597   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1598   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
1599
1600   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1601   SaveLevel_VERS(file, level);
1602
1603   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
1604   SaveLevel_HEAD(file, level);
1605
1606   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
1607   SaveLevel_AUTH(file, level);
1608
1609   putFileChunkBE(file, "BODY", body_chunk_size);
1610   SaveLevel_BODY(file, level);
1611
1612   if (level->encoding_16bit_yamyam ||
1613       level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
1614   {
1615     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1616     SaveLevel_CNT2(file, level, EL_YAMYAM);
1617   }
1618
1619   if (level->encoding_16bit_amoeba)
1620   {
1621     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1622     SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
1623   }
1624
1625   /* check for envelope content */
1626   for (i=0; i<4; i++)
1627   {
1628     if (strlen(level->envelope_text[i]) > 0)
1629     {
1630       int envelope_len = strlen(level->envelope_text[i]) + 1;
1631
1632       putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_HEADER + envelope_len);
1633       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
1634     }
1635   }
1636
1637   /* check for non-default custom elements (unless using template level) */
1638   if (!level->use_custom_template)
1639   {
1640     for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1641     {
1642       int element = EL_CUSTOM_START + i;
1643
1644       if (element_info[element].modified_settings)
1645       {
1646         int num_change_pages = element_info[element].num_change_pages;
1647
1648         putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
1649         SaveLevel_CUS4(file, level, element);
1650       }
1651     }
1652   }
1653
1654   fclose(file);
1655
1656   SetFilePermissions(filename, PERMS_PRIVATE);
1657 }
1658
1659 void SaveLevel(int level_nr)
1660 {
1661   char *filename = getLevelFilename(level_nr);
1662
1663   SaveLevelFromFilename(&level, filename);
1664 }
1665
1666 void SaveLevelTemplate()
1667 {
1668   char *filename = getLevelFilename(-1);
1669
1670   SaveLevelFromFilename(&level, filename);
1671 }
1672
1673 void DumpLevel(struct LevelInfo *level)
1674 {
1675   printf_line("-", 79);
1676   printf("Level xxx (file version %08d, game version %08d)\n",
1677          level->file_version, level->game_version);
1678   printf_line("-", 79);
1679
1680   printf("Level Author: '%s'\n", level->author);
1681   printf("Level Title:  '%s'\n", level->name);
1682   printf("\n");
1683   printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
1684   printf("\n");
1685   printf("Level Time:  %d seconds\n", level->time);
1686   printf("Gems needed: %d\n", level->gems_needed);
1687   printf("\n");
1688   printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
1689   printf("Time for Wheel:      %d seconds\n", level->time_wheel);
1690   printf("Time for Light:      %d seconds\n", level->time_light);
1691   printf("Time for Timegate:   %d seconds\n", level->time_timegate);
1692   printf("\n");
1693   printf("Amoeba Speed: %d\n", level->amoeba_speed);
1694   printf("\n");
1695   printf("Gravity:                %s\n", (level->initial_gravity ? "yes" : "no"));
1696   printf("Double Speed Movement:  %s\n", (level->double_speed ? "yes" : "no"));
1697   printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
1698
1699   printf_line("-", 79);
1700 }
1701
1702
1703 /* ========================================================================= */
1704 /* tape file functions                                                       */
1705 /* ========================================================================= */
1706
1707 static void setTapeInfoToDefaults()
1708 {
1709   int i;
1710
1711   /* always start with reliable default values (empty tape) */
1712   TapeErase();
1713
1714   /* default values (also for pre-1.2 tapes) with only the first player */
1715   tape.player_participates[0] = TRUE;
1716   for(i=1; i<MAX_PLAYERS; i++)
1717     tape.player_participates[i] = FALSE;
1718
1719   /* at least one (default: the first) player participates in every tape */
1720   tape.num_participating_players = 1;
1721
1722   tape.level_nr = level_nr;
1723   tape.counter = 0;
1724   tape.changed = FALSE;
1725
1726   tape.recording = FALSE;
1727   tape.playing = FALSE;
1728   tape.pausing = FALSE;
1729 }
1730
1731 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
1732 {
1733   tape->file_version = getFileVersion(file);
1734   tape->game_version = getFileVersion(file);
1735
1736   return chunk_size;
1737 }
1738
1739 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
1740 {
1741   int i;
1742
1743   tape->random_seed = getFile32BitBE(file);
1744   tape->date        = getFile32BitBE(file);
1745   tape->length      = getFile32BitBE(file);
1746
1747   /* read header fields that are new since version 1.2 */
1748   if (tape->file_version >= FILE_VERSION_1_2)
1749   {
1750     byte store_participating_players = getFile8Bit(file);
1751     int engine_version;
1752
1753     /* since version 1.2, tapes store which players participate in the tape */
1754     tape->num_participating_players = 0;
1755     for(i=0; i<MAX_PLAYERS; i++)
1756     {
1757       tape->player_participates[i] = FALSE;
1758
1759       if (store_participating_players & (1 << i))
1760       {
1761         tape->player_participates[i] = TRUE;
1762         tape->num_participating_players++;
1763       }
1764     }
1765
1766     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
1767
1768     engine_version = getFileVersion(file);
1769     if (engine_version > 0)
1770       tape->engine_version = engine_version;
1771     else
1772       tape->engine_version = tape->game_version;
1773   }
1774
1775   return chunk_size;
1776 }
1777
1778 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
1779 {
1780   int level_identifier_size;
1781   int i;
1782
1783   level_identifier_size = getFile16BitBE(file);
1784
1785   tape->level_identifier =
1786     checked_realloc(tape->level_identifier, level_identifier_size);
1787
1788   for(i=0; i < level_identifier_size; i++)
1789     tape->level_identifier[i] = getFile8Bit(file);
1790
1791   tape->level_nr = getFile16BitBE(file);
1792
1793   chunk_size = 2 + level_identifier_size + 2;
1794
1795   return chunk_size;
1796 }
1797
1798 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
1799 {
1800   int i, j;
1801   int chunk_size_expected =
1802     (tape->num_participating_players + 1) * tape->length;
1803
1804   if (chunk_size_expected != chunk_size)
1805   {
1806     ReadUnusedBytesFromFile(file, chunk_size);
1807     return chunk_size_expected;
1808   }
1809
1810   for(i=0; i<tape->length; i++)
1811   {
1812     if (i >= MAX_TAPELEN)
1813       break;
1814
1815     for(j=0; j<MAX_PLAYERS; j++)
1816     {
1817       tape->pos[i].action[j] = MV_NO_MOVING;
1818
1819       if (tape->player_participates[j])
1820         tape->pos[i].action[j] = getFile8Bit(file);
1821     }
1822
1823     tape->pos[i].delay = getFile8Bit(file);
1824
1825     if (tape->file_version == FILE_VERSION_1_0)
1826     {
1827       /* eliminate possible diagonal moves in old tapes */
1828       /* this is only for backward compatibility */
1829
1830       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
1831       byte action = tape->pos[i].action[0];
1832       int k, num_moves = 0;
1833
1834       for (k=0; k<4; k++)
1835       {
1836         if (action & joy_dir[k])
1837         {
1838           tape->pos[i + num_moves].action[0] = joy_dir[k];
1839           if (num_moves > 0)
1840             tape->pos[i + num_moves].delay = 0;
1841           num_moves++;
1842         }
1843       }
1844
1845       if (num_moves > 1)
1846       {
1847         num_moves--;
1848         i += num_moves;
1849         tape->length += num_moves;
1850       }
1851     }
1852     else if (tape->file_version < FILE_VERSION_2_0)
1853     {
1854       /* convert pre-2.0 tapes to new tape format */
1855
1856       if (tape->pos[i].delay > 1)
1857       {
1858         /* action part */
1859         tape->pos[i + 1] = tape->pos[i];
1860         tape->pos[i + 1].delay = 1;
1861
1862         /* delay part */
1863         for(j=0; j<MAX_PLAYERS; j++)
1864           tape->pos[i].action[j] = MV_NO_MOVING;
1865         tape->pos[i].delay--;
1866
1867         i++;
1868         tape->length++;
1869       }
1870     }
1871
1872     if (feof(file))
1873       break;
1874   }
1875
1876   if (i != tape->length)
1877     chunk_size = (tape->num_participating_players + 1) * i;
1878
1879   return chunk_size;
1880 }
1881
1882 void LoadTapeFromFilename(char *filename)
1883 {
1884   char cookie[MAX_LINE_LEN];
1885   char chunk_name[CHUNK_ID_LEN + 1];
1886   FILE *file;
1887   int chunk_size;
1888
1889   /* always start with reliable default values */
1890   setTapeInfoToDefaults();
1891
1892   if (!(file = fopen(filename, MODE_READ)))
1893     return;
1894
1895   getFileChunkBE(file, chunk_name, NULL);
1896   if (strcmp(chunk_name, "RND1") == 0)
1897   {
1898     getFile32BitBE(file);               /* not used */
1899
1900     getFileChunkBE(file, chunk_name, NULL);
1901     if (strcmp(chunk_name, "TAPE") != 0)
1902     {
1903       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1904       fclose(file);
1905       return;
1906     }
1907   }
1908   else  /* check for pre-2.0 file format with cookie string */
1909   {
1910     strcpy(cookie, chunk_name);
1911     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1912     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1913       cookie[strlen(cookie) - 1] = '\0';
1914
1915     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
1916     {
1917       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1918       fclose(file);
1919       return;
1920     }
1921
1922     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
1923     {
1924       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
1925       fclose(file);
1926       return;
1927     }
1928
1929     /* pre-2.0 tape files have no game version, so use file version here */
1930     tape.game_version = tape.file_version;
1931   }
1932
1933   if (tape.file_version < FILE_VERSION_1_2)
1934   {
1935     /* tape files from versions before 1.2.0 without chunk structure */
1936     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
1937     LoadTape_BODY(file, 2 * tape.length,  &tape);
1938   }
1939   else
1940   {
1941     static struct
1942     {
1943       char *name;
1944       int size;
1945       int (*loader)(FILE *, int, struct TapeInfo *);
1946     }
1947     chunk_info[] =
1948     {
1949       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
1950       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
1951       { "INFO", -1,                     LoadTape_INFO },
1952       { "BODY", -1,                     LoadTape_BODY },
1953       {  NULL,  0,                      NULL }
1954     };
1955
1956     while (getFileChunkBE(file, chunk_name, &chunk_size))
1957     {
1958       int i = 0;
1959
1960       while (chunk_info[i].name != NULL &&
1961              strcmp(chunk_name, chunk_info[i].name) != 0)
1962         i++;
1963
1964       if (chunk_info[i].name == NULL)
1965       {
1966         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
1967               chunk_name, filename);
1968         ReadUnusedBytesFromFile(file, chunk_size);
1969       }
1970       else if (chunk_info[i].size != -1 &&
1971                chunk_info[i].size != chunk_size)
1972       {
1973         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1974               chunk_size, chunk_name, filename);
1975         ReadUnusedBytesFromFile(file, chunk_size);
1976       }
1977       else
1978       {
1979         /* call function to load this tape chunk */
1980         int chunk_size_expected =
1981           (chunk_info[i].loader)(file, chunk_size, &tape);
1982
1983         /* the size of some chunks cannot be checked before reading other
1984            chunks first (like "HEAD" and "BODY") that contain some header
1985            information, so check them here */
1986         if (chunk_size_expected != chunk_size)
1987         {
1988           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1989                 chunk_size, chunk_name, filename);
1990         }
1991       }
1992     }
1993   }
1994
1995   fclose(file);
1996
1997   tape.length_seconds = GetTapeLength();
1998
1999 #if 0
2000   printf("tape game version: %d\n", tape.game_version);
2001   printf("tape engine version: %d\n", tape.engine_version);
2002 #endif
2003 }
2004
2005 void LoadTape(int level_nr)
2006 {
2007   char *filename = getTapeFilename(level_nr);
2008
2009   LoadTapeFromFilename(filename);
2010 }
2011
2012 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
2013 {
2014   putFileVersion(file, tape->file_version);
2015   putFileVersion(file, tape->game_version);
2016 }
2017
2018 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
2019 {
2020   int i;
2021   byte store_participating_players = 0;
2022
2023   /* set bits for participating players for compact storage */
2024   for(i=0; i<MAX_PLAYERS; i++)
2025     if (tape->player_participates[i])
2026       store_participating_players |= (1 << i);
2027
2028   putFile32BitBE(file, tape->random_seed);
2029   putFile32BitBE(file, tape->date);
2030   putFile32BitBE(file, tape->length);
2031
2032   putFile8Bit(file, store_participating_players);
2033
2034   /* unused bytes not at the end here for 4-byte alignment of engine_version */
2035   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
2036
2037   putFileVersion(file, tape->engine_version);
2038 }
2039
2040 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
2041 {
2042   int level_identifier_size = strlen(tape->level_identifier) + 1;
2043   int i;
2044
2045   putFile16BitBE(file, level_identifier_size);
2046
2047   for(i=0; i < level_identifier_size; i++)
2048     putFile8Bit(file, tape->level_identifier[i]);
2049
2050   putFile16BitBE(file, tape->level_nr);
2051 }
2052
2053 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
2054 {
2055   int i, j;
2056
2057   for(i=0; i<tape->length; i++)
2058   {
2059     for(j=0; j<MAX_PLAYERS; j++)
2060       if (tape->player_participates[j])
2061         putFile8Bit(file, tape->pos[i].action[j]);
2062
2063     putFile8Bit(file, tape->pos[i].delay);
2064   }
2065 }
2066
2067 void SaveTape(int level_nr)
2068 {
2069   char *filename = getTapeFilename(level_nr);
2070   FILE *file;
2071   boolean new_tape = TRUE;
2072   int num_participating_players = 0;
2073   int info_chunk_size;
2074   int body_chunk_size;
2075   int i;
2076
2077   InitTapeDirectory(leveldir_current->filename);
2078
2079   /* if a tape still exists, ask to overwrite it */
2080   if (access(filename, F_OK) == 0)
2081   {
2082     new_tape = FALSE;
2083     if (!Request("Replace old tape ?", REQ_ASK))
2084       return;
2085   }
2086
2087   if (!(file = fopen(filename, MODE_WRITE)))
2088   {
2089     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
2090     return;
2091   }
2092
2093   tape.file_version = FILE_VERSION_ACTUAL;
2094   tape.game_version = GAME_VERSION_ACTUAL;
2095
2096   /* count number of participating players  */
2097   for(i=0; i<MAX_PLAYERS; i++)
2098     if (tape.player_participates[i])
2099       num_participating_players++;
2100
2101   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
2102   body_chunk_size = (num_participating_players + 1) * tape.length;
2103
2104   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
2105   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
2106
2107   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
2108   SaveTape_VERS(file, &tape);
2109
2110   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
2111   SaveTape_HEAD(file, &tape);
2112
2113   putFileChunkBE(file, "INFO", info_chunk_size);
2114   SaveTape_INFO(file, &tape);
2115
2116   putFileChunkBE(file, "BODY", body_chunk_size);
2117   SaveTape_BODY(file, &tape);
2118
2119   fclose(file);
2120
2121   SetFilePermissions(filename, PERMS_PRIVATE);
2122
2123   tape.changed = FALSE;
2124
2125   if (new_tape)
2126     Request("tape saved !", REQ_CONFIRM);
2127 }
2128
2129 void DumpTape(struct TapeInfo *tape)
2130 {
2131   int i, j;
2132
2133   if (TAPE_IS_EMPTY(*tape))
2134   {
2135     Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
2136     return;
2137   }
2138
2139   printf_line("-", 79);
2140   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
2141          tape->level_nr, tape->file_version, tape->game_version);
2142   printf("Level series identifier: '%s'\n", tape->level_identifier);
2143   printf_line("-", 79);
2144
2145   for(i=0; i<tape->length; i++)
2146   {
2147     if (i >= MAX_TAPELEN)
2148       break;
2149
2150     printf("%03d: ", i);
2151
2152     for(j=0; j<MAX_PLAYERS; j++)
2153     {
2154       if (tape->player_participates[j])
2155       {
2156         int action = tape->pos[i].action[j];
2157
2158         printf("%d:%02x ", j, action);
2159         printf("[%c%c%c%c|%c%c] - ",
2160                (action & JOY_LEFT ? '<' : ' '),
2161                (action & JOY_RIGHT ? '>' : ' '),
2162                (action & JOY_UP ? '^' : ' '),
2163                (action & JOY_DOWN ? 'v' : ' '),
2164                (action & JOY_BUTTON_1 ? '1' : ' '),
2165                (action & JOY_BUTTON_2 ? '2' : ' '));
2166       }
2167     }
2168
2169     printf("(%03d)\n", tape->pos[i].delay);
2170   }
2171
2172   printf_line("-", 79);
2173 }
2174
2175
2176 /* ========================================================================= */
2177 /* score file functions                                                      */
2178 /* ========================================================================= */
2179
2180 void LoadScore(int level_nr)
2181 {
2182   int i;
2183   char *filename = getScoreFilename(level_nr);
2184   char cookie[MAX_LINE_LEN];
2185   char line[MAX_LINE_LEN];
2186   char *line_ptr;
2187   FILE *file;
2188
2189   /* always start with reliable default values */
2190   for(i=0; i<MAX_SCORE_ENTRIES; i++)
2191   {
2192     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
2193     highscore[i].Score = 0;
2194   }
2195
2196   if (!(file = fopen(filename, MODE_READ)))
2197     return;
2198
2199   /* check file identifier */
2200   fgets(cookie, MAX_LINE_LEN, file);
2201   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
2202     cookie[strlen(cookie) - 1] = '\0';
2203
2204   if (!checkCookieString(cookie, SCORE_COOKIE))
2205   {
2206     Error(ERR_WARN, "unknown format of score file '%s'", filename);
2207     fclose(file);
2208     return;
2209   }
2210
2211   for(i=0; i<MAX_SCORE_ENTRIES; i++)
2212   {
2213     fscanf(file, "%d", &highscore[i].Score);
2214     fgets(line, MAX_LINE_LEN, file);
2215
2216     if (line[strlen(line) - 1] == '\n')
2217       line[strlen(line) - 1] = '\0';
2218
2219     for (line_ptr = line; *line_ptr; line_ptr++)
2220     {
2221       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
2222       {
2223         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
2224         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
2225         break;
2226       }
2227     }
2228   }
2229
2230   fclose(file);
2231 }
2232
2233 void SaveScore(int level_nr)
2234 {
2235   int i;
2236   char *filename = getScoreFilename(level_nr);
2237   FILE *file;
2238
2239   InitScoreDirectory(leveldir_current->filename);
2240
2241   if (!(file = fopen(filename, MODE_WRITE)))
2242   {
2243     Error(ERR_WARN, "cannot save score for level %d", level_nr);
2244     return;
2245   }
2246
2247   fprintf(file, "%s\n\n", SCORE_COOKIE);
2248
2249   for(i=0; i<MAX_SCORE_ENTRIES; i++)
2250     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
2251
2252   fclose(file);
2253
2254   SetFilePermissions(filename, PERMS_PUBLIC);
2255 }
2256
2257
2258 /* ========================================================================= */
2259 /* setup file functions                                                      */
2260 /* ========================================================================= */
2261
2262 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
2263
2264 /* global setup */
2265 #define SETUP_TOKEN_PLAYER_NAME                 0
2266 #define SETUP_TOKEN_SOUND                       1
2267 #define SETUP_TOKEN_SOUND_LOOPS                 2
2268 #define SETUP_TOKEN_SOUND_MUSIC                 3
2269 #define SETUP_TOKEN_SOUND_SIMPLE                4
2270 #define SETUP_TOKEN_TOONS                       5
2271 #define SETUP_TOKEN_SCROLL_DELAY                6
2272 #define SETUP_TOKEN_SOFT_SCROLLING              7
2273 #define SETUP_TOKEN_FADING                      8
2274 #define SETUP_TOKEN_AUTORECORD                  9
2275 #define SETUP_TOKEN_QUICK_DOORS                 10
2276 #define SETUP_TOKEN_TEAM_MODE                   11
2277 #define SETUP_TOKEN_HANDICAP                    12
2278 #define SETUP_TOKEN_TIME_LIMIT                  13
2279 #define SETUP_TOKEN_FULLSCREEN                  14
2280 #define SETUP_TOKEN_ASK_ON_ESCAPE               15
2281 #define SETUP_TOKEN_GRAPHICS_SET                16
2282 #define SETUP_TOKEN_SOUNDS_SET                  17
2283 #define SETUP_TOKEN_MUSIC_SET                   18
2284 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     19
2285 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       20
2286 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        21
2287
2288 #define NUM_GLOBAL_SETUP_TOKENS                 22
2289
2290 /* editor setup */
2291 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
2292 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
2293 #define SETUP_TOKEN_EDITOR_EL_MORE              2
2294 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           3
2295 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          4
2296 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     5
2297 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    6
2298 #define SETUP_TOKEN_EDITOR_EL_CHARS             7
2299 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            8
2300 #define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE       9
2301 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         10
2302
2303 #define NUM_EDITOR_SETUP_TOKENS                 11
2304
2305 /* shortcut setup */
2306 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
2307 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
2308 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
2309
2310 #define NUM_SHORTCUT_SETUP_TOKENS               3
2311
2312 /* player setup */
2313 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
2314 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
2315 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
2316 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
2317 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
2318 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
2319 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
2320 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
2321 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
2322 #define SETUP_TOKEN_PLAYER_JOY_BOMB             9
2323 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
2324 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
2325 #define SETUP_TOKEN_PLAYER_KEY_UP               12
2326 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
2327 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
2328 #define SETUP_TOKEN_PLAYER_KEY_BOMB             15
2329
2330 #define NUM_PLAYER_SETUP_TOKENS                 16
2331
2332 /* system setup */
2333 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
2334 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
2335
2336 #define NUM_SYSTEM_SETUP_TOKENS                 2
2337
2338 /* options setup */
2339 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
2340
2341 #define NUM_OPTIONS_SETUP_TOKENS                1
2342
2343
2344 static struct SetupInfo si;
2345 static struct SetupEditorInfo sei;
2346 static struct SetupShortcutInfo ssi;
2347 static struct SetupInputInfo sii;
2348 static struct SetupSystemInfo syi;
2349 static struct OptionInfo soi;
2350
2351 static struct TokenInfo global_setup_tokens[] =
2352 {
2353   { TYPE_STRING, &si.player_name,       "player_name"                   },
2354   { TYPE_SWITCH, &si.sound,             "sound"                         },
2355   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
2356   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
2357   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
2358   { TYPE_SWITCH, &si.toons,             "toons"                         },
2359   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
2360   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
2361   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
2362   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
2363   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
2364   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
2365   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
2366   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
2367   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
2368   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
2369   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
2370   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
2371   { TYPE_STRING, &si.music_set,         "music_set"                     },
2372   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
2373   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
2374   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
2375 };
2376
2377 static struct TokenInfo editor_setup_tokens[] =
2378 {
2379   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
2380   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
2381   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
2382   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
2383   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
2384   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
2385   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
2386   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
2387   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
2388   { TYPE_SWITCH, &sei.el_custom_more,   "editor.el_custom_more"         },
2389   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
2390 };
2391
2392 static struct TokenInfo shortcut_setup_tokens[] =
2393 {
2394   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
2395   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
2396   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         }
2397 };
2398
2399 static struct TokenInfo player_setup_tokens[] =
2400 {
2401   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
2402   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
2403   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
2404   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
2405   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
2406   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
2407   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
2408   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
2409   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
2410   { TYPE_INTEGER, &sii.joy.bomb,        ".joy.place_bomb"               },
2411   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
2412   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
2413   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
2414   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
2415   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
2416   { TYPE_KEY_X11, &sii.key.bomb,        ".key.place_bomb"               }
2417 };
2418
2419 static struct TokenInfo system_setup_tokens[] =
2420 {
2421   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
2422   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
2423 };
2424
2425 static struct TokenInfo options_setup_tokens[] =
2426 {
2427   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               }
2428 };
2429
2430 static char *get_corrected_login_name(char *login_name)
2431 {
2432   /* needed because player name must be a fixed length string */
2433   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
2434
2435   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
2436   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
2437
2438   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
2439     if (strchr(login_name_new, ' '))
2440       *strchr(login_name_new, ' ') = '\0';
2441
2442   return login_name_new;
2443 }
2444
2445 static void setSetupInfoToDefaults(struct SetupInfo *si)
2446 {
2447   int i;
2448
2449   si->player_name = get_corrected_login_name(getLoginName());
2450
2451   si->sound = TRUE;
2452   si->sound_loops = TRUE;
2453   si->sound_music = TRUE;
2454   si->sound_simple = TRUE;
2455   si->toons = TRUE;
2456   si->double_buffering = TRUE;
2457   si->direct_draw = !si->double_buffering;
2458   si->scroll_delay = TRUE;
2459   si->soft_scrolling = TRUE;
2460   si->fading = FALSE;
2461   si->autorecord = TRUE;
2462   si->quick_doors = FALSE;
2463   si->team_mode = FALSE;
2464   si->handicap = TRUE;
2465   si->time_limit = TRUE;
2466   si->fullscreen = FALSE;
2467   si->ask_on_escape = TRUE;
2468
2469   si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
2470   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
2471   si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
2472   si->override_level_graphics = FALSE;
2473   si->override_level_sounds = FALSE;
2474   si->override_level_music = FALSE;
2475
2476   si->editor.el_boulderdash = TRUE;
2477   si->editor.el_emerald_mine = TRUE;
2478   si->editor.el_more = TRUE;
2479   si->editor.el_sokoban = TRUE;
2480   si->editor.el_supaplex = TRUE;
2481   si->editor.el_diamond_caves = TRUE;
2482   si->editor.el_dx_boulderdash = TRUE;
2483   si->editor.el_chars = TRUE;
2484   si->editor.el_custom = TRUE;
2485   si->editor.el_custom_more = FALSE;
2486
2487   si->editor.el_headlines = TRUE;
2488
2489   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
2490   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
2491   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
2492
2493   for (i=0; i<MAX_PLAYERS; i++)
2494   {
2495     si->input[i].use_joystick = FALSE;
2496     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
2497     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
2498     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
2499     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
2500     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
2501     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
2502     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
2503     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
2504     si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
2505     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
2506     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
2507     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
2508     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
2509     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
2510     si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
2511   }
2512
2513   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
2514   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
2515
2516   si->options.verbose = FALSE;
2517 }
2518
2519 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
2520 {
2521   int i, pnr;
2522
2523   if (!setup_file_hash)
2524     return;
2525
2526   /* global setup */
2527   si = setup;
2528   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
2529     setSetupInfo(global_setup_tokens, i,
2530                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
2531   setup = si;
2532
2533   /* editor setup */
2534   sei = setup.editor;
2535   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
2536     setSetupInfo(editor_setup_tokens, i,
2537                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
2538   setup.editor = sei;
2539
2540   /* shortcut setup */
2541   ssi = setup.shortcut;
2542   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
2543     setSetupInfo(shortcut_setup_tokens, i,
2544                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
2545   setup.shortcut = ssi;
2546
2547   /* player setup */
2548   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
2549   {
2550     char prefix[30];
2551
2552     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
2553
2554     sii = setup.input[pnr];
2555     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
2556     {
2557       char full_token[100];
2558
2559       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
2560       setSetupInfo(player_setup_tokens, i,
2561                    getHashEntry(setup_file_hash, full_token));
2562     }
2563     setup.input[pnr] = sii;
2564   }
2565
2566   /* system setup */
2567   syi = setup.system;
2568   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
2569     setSetupInfo(system_setup_tokens, i,
2570                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
2571   setup.system = syi;
2572
2573   /* options setup */
2574   soi = setup.options;
2575   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2576     setSetupInfo(options_setup_tokens, i,
2577                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
2578   setup.options = soi;
2579 }
2580
2581 void LoadSetup()
2582 {
2583   char *filename = getSetupFilename();
2584   SetupFileHash *setup_file_hash = NULL;
2585
2586   /* always start with reliable default values */
2587   setSetupInfoToDefaults(&setup);
2588
2589   setup_file_hash = loadSetupFileHash(filename);
2590
2591   if (setup_file_hash)
2592   {
2593     char *player_name_new;
2594
2595     checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
2596     decodeSetupFileHash(setup_file_hash);
2597
2598     setup.direct_draw = !setup.double_buffering;
2599
2600     freeSetupFileHash(setup_file_hash);
2601
2602     /* needed to work around problems with fixed length strings */
2603     player_name_new = get_corrected_login_name(setup.player_name);
2604     free(setup.player_name);
2605     setup.player_name = player_name_new;
2606   }
2607   else
2608     Error(ERR_WARN, "using default setup values");
2609 }
2610
2611 void SaveSetup()
2612 {
2613   char *filename = getSetupFilename();
2614   FILE *file;
2615   int i, pnr;
2616
2617   InitUserDataDirectory();
2618
2619   if (!(file = fopen(filename, MODE_WRITE)))
2620   {
2621     Error(ERR_WARN, "cannot write setup file '%s'", filename);
2622     return;
2623   }
2624
2625   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
2626                                                getCookie("SETUP")));
2627   fprintf(file, "\n");
2628
2629   /* global setup */
2630   si = setup;
2631   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
2632   {
2633     /* just to make things nicer :) */
2634     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
2635         i == SETUP_TOKEN_GRAPHICS_SET)
2636       fprintf(file, "\n");
2637
2638     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
2639   }
2640
2641   /* editor setup */
2642   sei = setup.editor;
2643   fprintf(file, "\n");
2644   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
2645     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
2646
2647   /* shortcut setup */
2648   ssi = setup.shortcut;
2649   fprintf(file, "\n");
2650   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
2651     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
2652
2653   /* player setup */
2654   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
2655   {
2656     char prefix[30];
2657
2658     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
2659     fprintf(file, "\n");
2660
2661     sii = setup.input[pnr];
2662     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
2663       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
2664   }
2665
2666   /* system setup */
2667   syi = setup.system;
2668   fprintf(file, "\n");
2669   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
2670     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
2671
2672   /* options setup */
2673   soi = setup.options;
2674   fprintf(file, "\n");
2675   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2676     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
2677
2678   fclose(file);
2679
2680   SetFilePermissions(filename, PERMS_PRIVATE);
2681 }
2682
2683 void LoadCustomElementDescriptions()
2684 {
2685   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2686   SetupFileHash *setup_file_hash;
2687   int i;
2688
2689   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2690   {
2691     if (element_info[i].custom_description != NULL)
2692     {
2693       free(element_info[i].custom_description);
2694       element_info[i].custom_description = NULL;
2695     }
2696   }
2697
2698   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2699     return;
2700
2701   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2702   {
2703     char *token = getStringCat2(element_info[i].token_name, ".name");
2704     char *value = getHashEntry(setup_file_hash, token);
2705
2706     if (value != NULL)
2707       element_info[i].custom_description = getStringCopy(value);
2708
2709     free(token);
2710   }
2711
2712   freeSetupFileHash(setup_file_hash);
2713 }
2714
2715 void LoadSpecialMenuDesignSettings()
2716 {
2717   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2718   SetupFileHash *setup_file_hash;
2719   int i, j;
2720
2721   /* always start with reliable default values from default config */
2722   for (i=0; image_config_vars[i].token != NULL; i++)
2723     for (j=0; image_config[j].token != NULL; j++)
2724       if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
2725         *image_config_vars[i].value =
2726           get_auto_parameter_value(image_config_vars[i].token,
2727                                    image_config[j].value);
2728
2729   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2730     return;
2731
2732   /* special case: initialize with default values that may be overwritten */
2733   for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
2734   {
2735     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
2736     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
2737     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
2738
2739     if (value_x != NULL)
2740       menu.draw_xoffset[i] = get_integer_from_string(value_x);
2741     if (value_y != NULL)
2742       menu.draw_yoffset[i] = get_integer_from_string(value_y);
2743     if (list_size != NULL)
2744       menu.list_size[i] = get_integer_from_string(list_size);
2745   }
2746
2747   /* read (and overwrite with) values that may be specified in config file */
2748   for (i=0; image_config_vars[i].token != NULL; i++)
2749   {
2750     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
2751
2752     if (value != NULL)
2753       *image_config_vars[i].value =
2754         get_auto_parameter_value(image_config_vars[i].token, value);
2755   }
2756
2757   freeSetupFileHash(setup_file_hash);
2758 }