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