rnd-20061028-1-src
[rocksndiamonds.git] / src / init.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * init.c                                                   *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "init.h"
17 #include "events.h"
18 #include "screens.h"
19 #include "editor.h"
20 #include "game.h"
21 #include "tape.h"
22 #include "tools.h"
23 #include "files.h"
24 #include "network.h"
25 #include "netserv.h"
26 #include "cartoons.h"
27 #include "config.h"
28
29 #include "conf_e2g.c"   /* include auto-generated data structure definitions */
30 #include "conf_esg.c"   /* include auto-generated data structure definitions */
31 #include "conf_e2s.c"   /* include auto-generated data structure definitions */
32 #include "conf_fnt.c"   /* include auto-generated data structure definitions */
33 #include "conf_g2s.c"   /* include auto-generated data structure definitions */
34 #include "conf_g2m.c"   /* include auto-generated data structure definitions */
35
36
37 #define CONFIG_TOKEN_FONT_INITIAL               "font.initial"
38
39
40 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
41
42 static int copy_properties[][5] =
43 {
44   {
45     EL_BUG,
46     EL_BUG_LEFT,                EL_BUG_RIGHT,
47     EL_BUG_UP,                  EL_BUG_DOWN
48   },
49   {
50     EL_SPACESHIP,
51     EL_SPACESHIP_LEFT,          EL_SPACESHIP_RIGHT,
52     EL_SPACESHIP_UP,            EL_SPACESHIP_DOWN
53   },
54   {
55     EL_BD_BUTTERFLY,
56     EL_BD_BUTTERFLY_LEFT,       EL_BD_BUTTERFLY_RIGHT,
57     EL_BD_BUTTERFLY_UP,         EL_BD_BUTTERFLY_DOWN
58   },
59   {
60     EL_BD_FIREFLY,
61     EL_BD_FIREFLY_LEFT,         EL_BD_FIREFLY_RIGHT,
62     EL_BD_FIREFLY_UP,           EL_BD_FIREFLY_DOWN
63   },
64   {
65     EL_PACMAN,
66     EL_PACMAN_LEFT,             EL_PACMAN_RIGHT,
67     EL_PACMAN_UP,               EL_PACMAN_DOWN
68   },
69   {
70     EL_YAMYAM,
71     EL_YAMYAM_LEFT,             EL_YAMYAM_RIGHT,
72     EL_YAMYAM_UP,               EL_YAMYAM_DOWN
73   },
74   {
75     EL_MOLE,
76     EL_MOLE_LEFT,               EL_MOLE_RIGHT,
77     EL_MOLE_UP,                 EL_MOLE_DOWN
78   },
79   {
80     -1,
81     -1, -1, -1, -1
82   }
83 };
84
85 void FreeGadgets()
86 {
87   FreeLevelEditorGadgets();
88   FreeGameButtons();
89   FreeTapeButtons();
90   FreeToolButtons();
91   FreeScreenGadgets();
92 }
93
94 void InitGadgets()
95 {
96   static boolean gadgets_initialized = FALSE;
97
98   if (gadgets_initialized)
99     FreeGadgets();
100
101   CreateLevelEditorGadgets();
102   CreateGameButtons();
103   CreateTapeButtons();
104   CreateToolButtons();
105   CreateScreenGadgets();
106
107   gadgets_initialized = TRUE;
108 }
109
110 inline void InitElementSmallImagesScaledUp(int graphic)
111 {
112   CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
113 }
114
115 void InitElementSmallImages()
116 {
117   static int special_graphics[] =
118   {
119     IMG_EDITOR_ELEMENT_BORDER,
120     IMG_EDITOR_ELEMENT_BORDER_INPUT,
121     IMG_EDITOR_CASCADE_LIST,
122     IMG_EDITOR_CASCADE_LIST_ACTIVE,
123     -1
124   };
125   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
126   int num_property_mappings = getImageListPropertyMappingSize();
127   int i;
128
129   /* initialize normal images from static configuration */
130   for (i = 0; element_to_graphic[i].element > -1; i++)
131     InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
132
133   /* initialize special images from static configuration */
134   for (i = 0; element_to_special_graphic[i].element > -1; i++)
135     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
136
137   /* initialize images from dynamic configuration (may be elements or other) */
138   for (i = 0; i < num_property_mappings; i++)
139     InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
140
141   /* initialize special images from above list (non-element images) */
142   for (i = 0; special_graphics[i] > -1; i++)
143     InitElementSmallImagesScaledUp(special_graphics[i]);
144 }
145
146 void InitScaledImages()
147 {
148   int i;
149
150   /* scale normal images from static configuration, if not already scaled */
151   for (i = 0; i < NUM_IMAGE_FILES; i++)
152     ScaleImage(i, graphic_info[i].scale_up_factor);
153 }
154
155 #if 1
156 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
157 void SetBitmaps_EM(Bitmap **em_bitmap)
158 {
159   em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
160   em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
161 }
162 #endif
163
164 static int getFontBitmapID(int font_nr)
165 {
166   int special = -1;
167
168   if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
169     special = game_status;
170   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
171     special = GFX_SPECIAL_ARG_MAIN;
172   else if (game_status == GAME_MODE_PLAYING)
173     special = GFX_SPECIAL_ARG_DOOR;
174
175   if (special != -1)
176     return font_info[font_nr].special_bitmap_id[special];
177   else
178     return font_nr;
179 }
180
181 void InitFontGraphicInfo()
182 {
183   static struct FontBitmapInfo *font_bitmap_info = NULL;
184   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
185   int num_property_mappings = getImageListPropertyMappingSize();
186   int num_font_bitmaps = NUM_FONTS;
187   int i, j;
188
189   if (graphic_info == NULL)             /* still at startup phase */
190   {
191     InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
192
193     return;
194   }
195
196   /* ---------- initialize font graphic definitions ---------- */
197
198   /* always start with reliable default values (normal font graphics) */
199   for (i = 0; i < NUM_FONTS; i++)
200     font_info[i].graphic = IMG_FONT_INITIAL_1;
201
202   /* initialize normal font/graphic mapping from static configuration */
203   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
204   {
205     int font_nr = font_to_graphic[i].font_nr;
206     int special = font_to_graphic[i].special;
207     int graphic = font_to_graphic[i].graphic;
208
209     if (special != -1)
210       continue;
211
212     font_info[font_nr].graphic = graphic;
213   }
214
215   /* always start with reliable default values (special font graphics) */
216   for (i = 0; i < NUM_FONTS; i++)
217   {
218     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
219     {
220       font_info[i].special_graphic[j] = font_info[i].graphic;
221       font_info[i].special_bitmap_id[j] = i;
222     }
223   }
224
225   /* initialize special font/graphic mapping from static configuration */
226   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
227   {
228     int font_nr      = font_to_graphic[i].font_nr;
229     int special      = font_to_graphic[i].special;
230     int graphic      = font_to_graphic[i].graphic;
231     int base_graphic = font2baseimg(font_nr);
232
233     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
234     {
235       boolean base_redefined =
236         getImageListEntryFromImageID(base_graphic)->redefined;
237       boolean special_redefined =
238         getImageListEntryFromImageID(graphic)->redefined;
239
240       /* if the base font ("font.title_1", for example) has been redefined,
241          but not the special font ("font.title_1.LEVELS", for example), do not
242          use an existing (in this case considered obsolete) special font
243          anymore, but use the automatically determined default font */
244       if (base_redefined && !special_redefined)
245         continue;
246
247       font_info[font_nr].special_graphic[special] = graphic;
248       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
249       num_font_bitmaps++;
250     }
251   }
252
253   /* initialize special font/graphic mapping from dynamic configuration */
254   for (i = 0; i < num_property_mappings; i++)
255   {
256     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
257     int special = property_mapping[i].ext3_index;
258     int graphic = property_mapping[i].artwork_index;
259
260     if (font_nr < 0)
261       continue;
262
263     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
264     {
265       font_info[font_nr].special_graphic[special] = graphic;
266       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
267       num_font_bitmaps++;
268     }
269   }
270
271   /* reset non-redefined ".active" font graphics if normal font is redefined */
272   /* (this different treatment is needed because normal and active fonts are
273      independently defined ("active" is not a property of font definitions!) */
274   for (i = 0; i < NUM_FONTS; i++)
275   {
276     int font_nr_base = i;
277     int font_nr_active = FONT_ACTIVE(font_nr_base);
278
279     /* check only those fonts with exist as normal and ".active" variant */
280     if (font_nr_base != font_nr_active)
281     {
282       int base_graphic = font_info[font_nr_base].graphic;
283       int active_graphic = font_info[font_nr_active].graphic;
284       boolean base_redefined =
285         getImageListEntryFromImageID(base_graphic)->redefined;
286       boolean active_redefined =
287         getImageListEntryFromImageID(active_graphic)->redefined;
288
289       /* if the base font ("font.menu_1", for example) has been redefined,
290          but not the active font ("font.menu_1.active", for example), do not
291          use an existing (in this case considered obsolete) active font
292          anymore, but use the automatically determined default font */
293       if (base_redefined && !active_redefined)
294         font_info[font_nr_active].graphic = base_graphic;
295
296       /* now also check each "special" font (which may be the same as above) */
297       for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
298       {
299         int base_graphic = font_info[font_nr_base].special_graphic[j];
300         int active_graphic = font_info[font_nr_active].special_graphic[j];
301         boolean base_redefined =
302           getImageListEntryFromImageID(base_graphic)->redefined;
303         boolean active_redefined =
304           getImageListEntryFromImageID(active_graphic)->redefined;
305
306         /* same as above, but check special graphic definitions, for example:
307            redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
308         if (base_redefined && !active_redefined)
309         {
310           font_info[font_nr_active].special_graphic[j] =
311             font_info[font_nr_base].special_graphic[j];
312           font_info[font_nr_active].special_bitmap_id[j] =
313             font_info[font_nr_base].special_bitmap_id[j];
314         }
315       }
316     }
317   }
318
319   /* ---------- initialize font bitmap array ---------- */
320
321   if (font_bitmap_info != NULL)
322     FreeFontInfo(font_bitmap_info);
323
324   font_bitmap_info =
325     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
326
327   /* ---------- initialize font bitmap definitions ---------- */
328
329   for (i = 0; i < NUM_FONTS; i++)
330   {
331     if (i < NUM_INITIAL_FONTS)
332     {
333       font_bitmap_info[i] = font_initial[i];
334       continue;
335     }
336
337     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
338     {
339       int font_bitmap_id = font_info[i].special_bitmap_id[j];
340       int graphic = font_info[i].special_graphic[j];
341
342       /* set 'graphic_info' for font entries, if uninitialized (guessed) */
343       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
344       {
345         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
346         graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
347       }
348
349       /* copy font relevant information from graphics information */
350       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
351       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
352       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
353       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
354       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
355
356       font_bitmap_info[font_bitmap_id].draw_xoffset =
357         graphic_info[graphic].draw_xoffset;
358       font_bitmap_info[font_bitmap_id].draw_yoffset =
359         graphic_info[graphic].draw_yoffset;
360
361       font_bitmap_info[font_bitmap_id].num_chars =
362         graphic_info[graphic].anim_frames;
363       font_bitmap_info[font_bitmap_id].num_chars_per_line =
364         graphic_info[graphic].anim_frames_per_line;
365     }
366   }
367
368   InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
369 }
370
371 void InitElementGraphicInfo()
372 {
373   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
374   int num_property_mappings = getImageListPropertyMappingSize();
375   int i, act, dir;
376
377   if (graphic_info == NULL)             /* still at startup phase */
378     return;
379
380   /* set values to -1 to identify later as "uninitialized" values */
381   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
382   {
383     for (act = 0; act < NUM_ACTIONS; act++)
384     {
385       element_info[i].graphic[act] = -1;
386       element_info[i].crumbled[act] = -1;
387
388       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
389       {
390         element_info[i].direction_graphic[act][dir] = -1;
391         element_info[i].direction_crumbled[act][dir] = -1;
392       }
393     }
394   }
395
396   /* initialize normal element/graphic mapping from static configuration */
397   for (i = 0; element_to_graphic[i].element > -1; i++)
398   {
399     int element      = element_to_graphic[i].element;
400     int action       = element_to_graphic[i].action;
401     int direction    = element_to_graphic[i].direction;
402     boolean crumbled = element_to_graphic[i].crumbled;
403     int graphic      = element_to_graphic[i].graphic;
404     int base_graphic = el2baseimg(element);
405
406     if (graphic_info[graphic].bitmap == NULL)
407       continue;
408
409     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
410         base_graphic != -1)
411     {
412       boolean base_redefined =
413         getImageListEntryFromImageID(base_graphic)->redefined;
414       boolean act_dir_redefined =
415         getImageListEntryFromImageID(graphic)->redefined;
416
417       /* if the base graphic ("emerald", for example) has been redefined,
418          but not the action graphic ("emerald.falling", for example), do not
419          use an existing (in this case considered obsolete) action graphic
420          anymore, but use the automatically determined default graphic */
421       if (base_redefined && !act_dir_redefined)
422         continue;
423     }
424
425     if (action < 0)
426       action = ACTION_DEFAULT;
427
428     if (crumbled)
429     {
430       if (direction > -1)
431         element_info[element].direction_crumbled[action][direction] = graphic;
432       else
433         element_info[element].crumbled[action] = graphic;
434     }
435     else
436     {
437       if (direction > -1)
438         element_info[element].direction_graphic[action][direction] = graphic;
439       else
440         element_info[element].graphic[action] = graphic;
441     }
442   }
443
444   /* initialize normal element/graphic mapping from dynamic configuration */
445   for (i = 0; i < num_property_mappings; i++)
446   {
447     int element   = property_mapping[i].base_index;
448     int action    = property_mapping[i].ext1_index;
449     int direction = property_mapping[i].ext2_index;
450     int special   = property_mapping[i].ext3_index;
451     int graphic   = property_mapping[i].artwork_index;
452     boolean crumbled = FALSE;
453
454     if (special == GFX_SPECIAL_ARG_CRUMBLED)
455     {
456       special = -1;
457       crumbled = TRUE;
458     }
459
460     if (graphic_info[graphic].bitmap == NULL)
461       continue;
462
463     if (element >= MAX_NUM_ELEMENTS || special != -1)
464       continue;
465
466     if (action < 0)
467       action = ACTION_DEFAULT;
468
469     if (crumbled)
470     {
471       if (direction < 0)
472         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
473           element_info[element].direction_crumbled[action][dir] = -1;
474
475       if (direction > -1)
476         element_info[element].direction_crumbled[action][direction] = graphic;
477       else
478         element_info[element].crumbled[action] = graphic;
479     }
480     else
481     {
482       if (direction < 0)
483         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
484           element_info[element].direction_graphic[action][dir] = -1;
485
486       if (direction > -1)
487         element_info[element].direction_graphic[action][direction] = graphic;
488       else
489         element_info[element].graphic[action] = graphic;
490     }
491   }
492
493   /* now copy all graphics that are defined to be cloned from other graphics */
494   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
495   {
496     int graphic = element_info[i].graphic[ACTION_DEFAULT];
497     int crumbled_like, diggable_like;
498
499     if (graphic == -1)
500       continue;
501
502     crumbled_like = graphic_info[graphic].crumbled_like;
503     diggable_like = graphic_info[graphic].diggable_like;
504
505     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
506     {
507       for (act = 0; act < NUM_ACTIONS; act++)
508         element_info[i].crumbled[act] =
509           element_info[crumbled_like].crumbled[act];
510       for (act = 0; act < NUM_ACTIONS; act++)
511         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
512           element_info[i].direction_crumbled[act][dir] =
513             element_info[crumbled_like].direction_crumbled[act][dir];
514     }
515
516     if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
517     {
518       element_info[i].graphic[ACTION_DIGGING] =
519         element_info[diggable_like].graphic[ACTION_DIGGING];
520       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
521         element_info[i].direction_graphic[ACTION_DIGGING][dir] =
522           element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
523     }
524   }
525
526 #if 1
527   /* set hardcoded definitions for some runtime elements without graphic */
528   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
529 #endif
530
531 #if 1
532   /* set hardcoded definitions for some internal elements without graphic */
533   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
534   {
535     if (IS_EDITOR_CASCADE_INACTIVE(i))
536       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
537     else if (IS_EDITOR_CASCADE_ACTIVE(i))
538       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
539   }
540 #endif
541
542   /* now set all undefined/invalid graphics to -1 to set to default after it */
543   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
544   {
545     for (act = 0; act < NUM_ACTIONS; act++)
546     {
547       int graphic;
548
549       graphic = element_info[i].graphic[act];
550       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
551         element_info[i].graphic[act] = -1;
552
553       graphic = element_info[i].crumbled[act];
554       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
555         element_info[i].crumbled[act] = -1;
556
557       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
558       {
559         graphic = element_info[i].direction_graphic[act][dir];
560         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
561           element_info[i].direction_graphic[act][dir] = -1;
562
563         graphic = element_info[i].direction_crumbled[act][dir];
564         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
565           element_info[i].direction_crumbled[act][dir] = -1;
566       }
567     }
568   }
569
570   /* adjust graphics with 2nd tile for movement according to direction
571      (do this before correcting '-1' values to minimize calculations) */
572   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
573   {
574     for (act = 0; act < NUM_ACTIONS; act++)
575     {
576       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
577       {
578         int graphic = element_info[i].direction_graphic[act][dir];
579         int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
580
581         if (act == ACTION_FALLING)      /* special case */
582           graphic = element_info[i].graphic[act];
583
584         if (graphic != -1 &&
585             graphic_info[graphic].double_movement &&
586             graphic_info[graphic].swap_double_tiles != 0)
587         {
588           struct GraphicInfo *g = &graphic_info[graphic];
589           int src_x_front = g->src_x;
590           int src_y_front = g->src_y;
591           int src_x_back = g->src_x + g->offset2_x;
592           int src_y_back = g->src_y + g->offset2_y;
593           boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
594                                                    g->offset_y != 0);
595           boolean front_is_left_or_upper = (src_x_front < src_x_back ||
596                                             src_y_front < src_y_back);
597           boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
598           boolean swap_movement_tiles_autodetected =
599             (!frames_are_ordered_diagonally &&
600              ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
601               (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
602               (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
603               (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
604           Bitmap *dummy;
605
606           /* swap frontside and backside graphic tile coordinates, if needed */
607           if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
608           {
609             /* get current (wrong) backside tile coordinates */
610             getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
611                                 TRUE);
612
613             /* set frontside tile coordinates to backside tile coordinates */
614             g->src_x = src_x_back;
615             g->src_y = src_y_back;
616
617             /* invert tile offset to point to new backside tile coordinates */
618             g->offset2_x *= -1;
619             g->offset2_y *= -1;
620
621             /* do not swap front and backside tiles again after correction */
622             g->swap_double_tiles = 0;
623           }
624         }
625       }
626     }
627   }
628
629   /* now set all '-1' values to element specific default values */
630   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
631   {
632     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
633     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
634     int default_direction_graphic[NUM_DIRECTIONS_FULL];
635     int default_direction_crumbled[NUM_DIRECTIONS_FULL];
636
637     if (default_graphic == -1)
638       default_graphic = IMG_UNKNOWN;
639 #if 1
640     if (default_crumbled == -1)
641       default_crumbled = default_graphic;
642 #else
643     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
644     if (default_crumbled == -1)
645       default_crumbled = IMG_EMPTY;
646 #endif
647
648     for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
649     {
650       default_direction_graphic[dir] =
651         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
652       default_direction_crumbled[dir] =
653         element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
654
655       if (default_direction_graphic[dir] == -1)
656         default_direction_graphic[dir] = default_graphic;
657 #if 1
658       if (default_direction_crumbled[dir] == -1)
659         default_direction_crumbled[dir] = default_direction_graphic[dir];
660 #else
661       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
662       if (default_direction_crumbled[dir] == -1)
663         default_direction_crumbled[dir] = default_crumbled;
664 #endif
665     }
666
667     for (act = 0; act < NUM_ACTIONS; act++)
668     {
669       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
670                             (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
671                             (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
672       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
673                              act == ACTION_TURNING_FROM_RIGHT ||
674                              act == ACTION_TURNING_FROM_UP ||
675                              act == ACTION_TURNING_FROM_DOWN);
676
677       /* generic default action graphic (defined by "[default]" directive) */
678       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
679       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
680       int default_remove_graphic = IMG_EMPTY;
681
682       if (act_remove && default_action_graphic != -1)
683         default_remove_graphic = default_action_graphic;
684
685       /* look for special default action graphic (classic game specific) */
686       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
687         default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
688       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
689         default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
690       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
691         default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
692
693       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
694         default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
695       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
696         default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
697       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
698         default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
699
700 #if 1
701       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
702       /* !!! make this better !!! */
703       if (i == EL_EMPTY_SPACE)
704       {
705         default_action_graphic = element_info[EL_DEFAULT].graphic[act];
706         default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
707       }
708 #endif
709
710       if (default_action_graphic == -1)
711         default_action_graphic = default_graphic;
712 #if 1
713       if (default_action_crumbled == -1)
714         default_action_crumbled = default_action_graphic;
715 #else
716       /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
717       if (default_action_crumbled == -1)
718         default_action_crumbled = default_crumbled;
719 #endif
720
721       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
722       {
723         /* use action graphic as the default direction graphic, if undefined */
724         int default_action_direction_graphic = element_info[i].graphic[act];
725         int default_action_direction_crumbled = element_info[i].crumbled[act];
726
727         /* no graphic for current action -- use default direction graphic */
728         if (default_action_direction_graphic == -1)
729           default_action_direction_graphic =
730             (act_remove ? default_remove_graphic :
731              act_turning ?
732              element_info[i].direction_graphic[ACTION_TURNING][dir] :
733              default_action_graphic != default_graphic ?
734              default_action_graphic :
735              default_direction_graphic[dir]);
736
737         if (element_info[i].direction_graphic[act][dir] == -1)
738           element_info[i].direction_graphic[act][dir] =
739             default_action_direction_graphic;
740
741 #if 1
742         if (default_action_direction_crumbled == -1)
743           default_action_direction_crumbled =
744             element_info[i].direction_graphic[act][dir];
745 #else
746         if (default_action_direction_crumbled == -1)
747           default_action_direction_crumbled =
748             (act_remove ? default_remove_graphic :
749              act_turning ?
750              element_info[i].direction_crumbled[ACTION_TURNING][dir] :
751              default_action_crumbled != default_crumbled ?
752              default_action_crumbled :
753              default_direction_crumbled[dir]);
754 #endif
755
756         if (element_info[i].direction_crumbled[act][dir] == -1)
757           element_info[i].direction_crumbled[act][dir] =
758             default_action_direction_crumbled;
759       }
760
761       /* no graphic for this specific action -- use default action graphic */
762       if (element_info[i].graphic[act] == -1)
763         element_info[i].graphic[act] =
764           (act_remove ? default_remove_graphic :
765            act_turning ? element_info[i].graphic[ACTION_TURNING] :
766            default_action_graphic);
767 #if 1
768       if (element_info[i].crumbled[act] == -1)
769         element_info[i].crumbled[act] = element_info[i].graphic[act];
770 #else
771       if (element_info[i].crumbled[act] == -1)
772         element_info[i].crumbled[act] =
773           (act_remove ? default_remove_graphic :
774            act_turning ? element_info[i].crumbled[ACTION_TURNING] :
775            default_action_crumbled);
776 #endif
777     }
778   }
779
780 #if 0
781   /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
782   /* set animation mode to "none" for each graphic with only 1 frame */
783   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
784   {
785     for (act = 0; act < NUM_ACTIONS; act++)
786     {
787       int graphic = element_info[i].graphic[act];
788       int crumbled = element_info[i].crumbled[act];
789
790       if (graphic_info[graphic].anim_frames == 1)
791         graphic_info[graphic].anim_mode = ANIM_NONE;
792       if (graphic_info[crumbled].anim_frames == 1)
793         graphic_info[crumbled].anim_mode = ANIM_NONE;
794
795       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
796       {
797         graphic = element_info[i].direction_graphic[act][dir];
798         crumbled = element_info[i].direction_crumbled[act][dir];
799
800         if (graphic_info[graphic].anim_frames == 1)
801           graphic_info[graphic].anim_mode = ANIM_NONE;
802         if (graphic_info[crumbled].anim_frames == 1)
803           graphic_info[crumbled].anim_mode = ANIM_NONE;
804       }
805     }
806   }
807 #endif
808
809 #if 0
810 #if DEBUG
811   if (options.verbose)
812   {
813     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
814       if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
815           i != EL_UNKNOWN)
816         Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
817               element_info[i].token_name, i);
818   }
819 #endif
820 #endif
821 }
822
823 void InitElementSpecialGraphicInfo()
824 {
825   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
826   int num_property_mappings = getImageListPropertyMappingSize();
827   int i, j;
828
829   /* always start with reliable default values */
830   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
831     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
832       element_info[i].special_graphic[j] =
833         element_info[i].graphic[ACTION_DEFAULT];
834
835   /* initialize special element/graphic mapping from static configuration */
836   for (i = 0; element_to_special_graphic[i].element > -1; i++)
837   {
838     int element = element_to_special_graphic[i].element;
839     int special = element_to_special_graphic[i].special;
840     int graphic = element_to_special_graphic[i].graphic;
841     int base_graphic = el2baseimg(element);
842     boolean base_redefined =
843       getImageListEntryFromImageID(base_graphic)->redefined;
844     boolean special_redefined =
845       getImageListEntryFromImageID(graphic)->redefined;
846
847     /* if the base graphic ("emerald", for example) has been redefined,
848        but not the special graphic ("emerald.EDITOR", for example), do not
849        use an existing (in this case considered obsolete) special graphic
850        anymore, but use the automatically created (down-scaled) graphic */
851     if (base_redefined && !special_redefined)
852       continue;
853
854     element_info[element].special_graphic[special] = graphic;
855   }
856
857   /* initialize special element/graphic mapping from dynamic configuration */
858   for (i = 0; i < num_property_mappings; i++)
859   {
860     int element = property_mapping[i].base_index;
861     int special = property_mapping[i].ext3_index;
862     int graphic = property_mapping[i].artwork_index;
863
864     if (element >= MAX_NUM_ELEMENTS)
865       continue;
866
867     if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
868       element_info[element].special_graphic[special] = graphic;
869   }
870
871   /* now set all undefined/invalid graphics to default */
872   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
873     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
874       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
875         element_info[i].special_graphic[j] =
876           element_info[i].graphic[ACTION_DEFAULT];
877 }
878
879 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
880 {
881   int i;
882   int x = 0;
883
884   if (type != TYPE_TOKEN)
885     return get_parameter_value(value_raw, suffix, type);
886
887   if (strEqual(value_raw, ARG_UNDEFINED))
888     return ARG_UNDEFINED_VALUE;
889
890   /* !!! OPTIMIZE THIS BY USING HASH !!! */
891   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
892     if (strEqual(element_info[i].token_name, value_raw))
893       return i;
894
895   /* !!! OPTIMIZE THIS BY USING HASH !!! */
896   for (i = 0; image_config[i].token != NULL; i++)
897   {
898     int len_config_value = strlen(image_config[i].value);
899
900     if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
901         !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
902         !strEqual(image_config[i].value, UNDEFINED_FILENAME))
903       continue;
904
905     if (strEqual(image_config[i].token, value_raw))
906       return x;
907
908     x++;
909   }
910
911   return -1;
912 }
913
914 static int get_scaled_graphic_width(int graphic)
915 {
916   int original_width = getOriginalImageWidthFromImageID(graphic);
917   int scale_up_factor = graphic_info[graphic].scale_up_factor;
918
919   return original_width * scale_up_factor;
920 }
921
922 static int get_scaled_graphic_height(int graphic)
923 {
924   int original_height = getOriginalImageHeightFromImageID(graphic);
925   int scale_up_factor = graphic_info[graphic].scale_up_factor;
926
927   return original_height * scale_up_factor;
928 }
929
930 static void set_graphic_parameters(int graphic)
931 {
932   struct FileInfo *image = getImageListEntryFromImageID(graphic);
933   char **parameter_raw = image->parameter;
934   Bitmap *src_bitmap = getBitmapFromImageID(graphic);
935   int parameter[NUM_GFX_ARGS];
936   int anim_frames_per_row = 1, anim_frames_per_col = 1;
937   int anim_frames_per_line = 1;
938   int i;
939
940   /* if fallback to default artwork is done, also use the default parameters */
941   if (image->fallback_to_default)
942     parameter_raw = image->default_parameter;
943
944   /* get integer values from string parameters */
945   for (i = 0; i < NUM_GFX_ARGS; i++)
946     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
947                                                image_config_suffix[i].token,
948                                                image_config_suffix[i].type);
949
950   graphic_info[graphic].bitmap = src_bitmap;
951
952   /* always start with reliable default values */
953   graphic_info[graphic].src_image_width = 0;
954   graphic_info[graphic].src_image_height = 0;
955   graphic_info[graphic].src_x = 0;
956   graphic_info[graphic].src_y = 0;
957   graphic_info[graphic].width  = TILEX; /* default for element graphics */
958   graphic_info[graphic].height = TILEY; /* default for element graphics */
959   graphic_info[graphic].offset_x = 0;   /* one or both of these values ... */
960   graphic_info[graphic].offset_y = 0;   /* ... will be corrected later */
961   graphic_info[graphic].offset2_x = 0;  /* one or both of these values ... */
962   graphic_info[graphic].offset2_y = 0;  /* ... will be corrected later */
963   graphic_info[graphic].swap_double_tiles = -1; /* auto-detect tile swapping */
964   graphic_info[graphic].crumbled_like = -1;     /* do not use clone element */
965   graphic_info[graphic].diggable_like = -1;     /* do not use clone element */
966   graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
967   graphic_info[graphic].scale_up_factor = 1;    /* default: no scaling up */
968   graphic_info[graphic].clone_from = -1;        /* do not use clone graphic */
969   graphic_info[graphic].anim_delay_fixed = 0;
970   graphic_info[graphic].anim_delay_random = 0;
971   graphic_info[graphic].post_delay_fixed = 0;
972   graphic_info[graphic].post_delay_random = 0;
973   graphic_info[graphic].fade_delay = -1;
974   graphic_info[graphic].post_delay = -1;
975   graphic_info[graphic].auto_delay = -1;
976
977 #if 1
978   if (graphic_info[graphic].use_image_size)
979   {
980     /* set default bitmap size (with scaling, but without small images) */
981     graphic_info[graphic].width  = get_scaled_graphic_width(graphic);
982     graphic_info[graphic].height = get_scaled_graphic_height(graphic);
983   }
984 #endif
985
986   /* optional x and y tile position of animation frame sequence */
987   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
988     graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
989   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
990     graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
991
992   /* optional x and y pixel position of animation frame sequence */
993   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
994     graphic_info[graphic].src_x = parameter[GFX_ARG_X];
995   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
996     graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
997
998   /* optional width and height of each animation frame */
999   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1000     graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
1001   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1002     graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
1003
1004   /* optional zoom factor for scaling up the image to a larger size */
1005   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1006     graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1007   if (graphic_info[graphic].scale_up_factor < 1)
1008     graphic_info[graphic].scale_up_factor = 1;          /* no scaling */
1009
1010   if (src_bitmap)
1011   {
1012     /* get final bitmap size (with scaling, but without small images) */
1013     int src_image_width  = get_scaled_graphic_width(graphic);
1014     int src_image_height = get_scaled_graphic_height(graphic);
1015
1016     anim_frames_per_row = src_image_width  / graphic_info[graphic].width;
1017     anim_frames_per_col = src_image_height / graphic_info[graphic].height;
1018
1019     graphic_info[graphic].src_image_width  = src_image_width;
1020     graphic_info[graphic].src_image_height = src_image_height;
1021   }
1022
1023   /* correct x or y offset dependent of vertical or horizontal frame order */
1024   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1025   {
1026     graphic_info[graphic].offset_y =
1027       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1028        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
1029     anim_frames_per_line = anim_frames_per_col;
1030   }
1031   else                                  /* frames are ordered horizontally */
1032   {
1033     graphic_info[graphic].offset_x =
1034       (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1035        parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
1036     anim_frames_per_line = anim_frames_per_row;
1037   }
1038
1039   /* optionally, the x and y offset of frames can be specified directly */
1040   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1041     graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
1042   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1043     graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
1044
1045   /* optionally, moving animations may have separate start and end graphics */
1046   graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1047
1048   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1049     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1050
1051   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1052   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1053     graphic_info[graphic].offset2_y =
1054       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1055        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
1056   else                                  /* frames are ordered horizontally */
1057     graphic_info[graphic].offset2_x =
1058       (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1059        parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
1060
1061   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1062   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1063     graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1064   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1065     graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1066
1067   /* optionally, the second movement tile can be specified as start tile */
1068   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1069     graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1070
1071   /* automatically determine correct number of frames, if not defined */
1072   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1073     graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
1074   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1075     graphic_info[graphic].anim_frames = anim_frames_per_row;
1076   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1077     graphic_info[graphic].anim_frames = anim_frames_per_col;
1078   else
1079     graphic_info[graphic].anim_frames = 1;
1080
1081   if (graphic_info[graphic].anim_frames == 0)   /* frames must be at least 1 */
1082     graphic_info[graphic].anim_frames = 1;
1083
1084   graphic_info[graphic].anim_frames_per_line =
1085     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1086      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1087
1088   graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
1089   if (graphic_info[graphic].anim_delay == 0)    /* delay must be at least 1 */
1090     graphic_info[graphic].anim_delay = 1;
1091
1092   graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
1093 #if 0
1094   if (graphic_info[graphic].anim_frames == 1)
1095     graphic_info[graphic].anim_mode = ANIM_NONE;
1096 #endif
1097
1098   /* automatically determine correct start frame, if not defined */
1099   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1100     graphic_info[graphic].anim_start_frame = 0;
1101   else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
1102     graphic_info[graphic].anim_start_frame =
1103       graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1104   else
1105     graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
1106
1107   /* animation synchronized with global frame counter, not move position */
1108   graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1109
1110   /* optional element for cloning crumble graphics */
1111   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1112     graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1113
1114   /* optional element for cloning digging graphics */
1115   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1116     graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1117
1118   /* optional border size for "crumbling" diggable graphics */
1119   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1120     graphic_info[graphic].border_size = parameter[GFX_ARG_BORDER_SIZE];
1121
1122   /* this is only used for player "boring" and "sleeping" actions */
1123   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1124     graphic_info[graphic].anim_delay_fixed =
1125       parameter[GFX_ARG_ANIM_DELAY_FIXED];
1126   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1127     graphic_info[graphic].anim_delay_random =
1128       parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1129   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1130     graphic_info[graphic].post_delay_fixed =
1131       parameter[GFX_ARG_POST_DELAY_FIXED];
1132   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1133     graphic_info[graphic].post_delay_random =
1134       parameter[GFX_ARG_POST_DELAY_RANDOM];
1135
1136   /* this is only used for toon animations */
1137   graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
1138   graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
1139
1140   /* this is only used for drawing font characters */
1141   graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1142   graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1143
1144   /* this is only used for drawing envelope graphics */
1145   graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1146
1147   /* optional graphic for cloning all graphics settings */
1148   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1149     graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
1150
1151   /* optional settings for drawing title screens */
1152   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1153     graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
1154   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1155     graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
1156   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1157     graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1158 }
1159
1160 static void set_cloned_graphic_parameters(int graphic)
1161 {
1162   int fallback_graphic = IMG_CHAR_EXCLAM;
1163   int max_num_images = getImageListSize();
1164   int clone_graphic = graphic_info[graphic].clone_from;
1165   int num_references_followed = 1;
1166
1167   while (graphic_info[clone_graphic].clone_from != -1 &&
1168          num_references_followed < max_num_images)
1169   {
1170     clone_graphic = graphic_info[clone_graphic].clone_from;
1171
1172     num_references_followed++;
1173   }
1174
1175   if (num_references_followed >= max_num_images)
1176   {
1177     Error(ERR_RETURN_LINE, "-");
1178     Error(ERR_RETURN, "warning: error found in config file:");
1179     Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1180     Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
1181     Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
1182     Error(ERR_RETURN, "custom graphic rejected for this element/action");
1183
1184     if (graphic == fallback_graphic)
1185       Error(ERR_EXIT, "fatal error: no fallback graphic available");
1186
1187     Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1188     Error(ERR_RETURN_LINE, "-");
1189
1190     graphic_info[graphic] = graphic_info[fallback_graphic];
1191   }
1192   else
1193   {
1194     graphic_info[graphic] = graphic_info[clone_graphic];
1195     graphic_info[graphic].clone_from = clone_graphic;
1196   }
1197 }
1198
1199 static void InitGraphicInfo()
1200 {
1201   int fallback_graphic = IMG_CHAR_EXCLAM;
1202   int num_images = getImageListSize();
1203   int i;
1204
1205 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1206   static boolean clipmasks_initialized = FALSE;
1207   Pixmap src_pixmap;
1208   XGCValues clip_gc_values;
1209   unsigned long clip_gc_valuemask;
1210   GC copy_clipmask_gc = None;
1211 #endif
1212
1213   /* use image size as default values for width and height for these images */
1214   static int full_size_graphics[] =
1215   {
1216     IMG_GLOBAL_BORDER,
1217     IMG_GLOBAL_DOOR,
1218
1219     IMG_BACKGROUND_ENVELOPE_1,
1220     IMG_BACKGROUND_ENVELOPE_2,
1221     IMG_BACKGROUND_ENVELOPE_3,
1222     IMG_BACKGROUND_ENVELOPE_4,
1223
1224     IMG_BACKGROUND,
1225     IMG_BACKGROUND_TITLE,
1226     IMG_BACKGROUND_MAIN,
1227     IMG_BACKGROUND_LEVELS,
1228     IMG_BACKGROUND_SCORES,
1229     IMG_BACKGROUND_EDITOR,
1230     IMG_BACKGROUND_INFO,
1231     IMG_BACKGROUND_INFO_ELEMENTS,
1232     IMG_BACKGROUND_INFO_MUSIC,
1233     IMG_BACKGROUND_INFO_CREDITS,
1234     IMG_BACKGROUND_INFO_PROGRAM,
1235     IMG_BACKGROUND_INFO_LEVELSET,
1236     IMG_BACKGROUND_SETUP,
1237     IMG_BACKGROUND_DOOR,
1238
1239     IMG_TITLESCREEN_INITIAL_1,
1240     IMG_TITLESCREEN_INITIAL_2,
1241     IMG_TITLESCREEN_INITIAL_3,
1242     IMG_TITLESCREEN_INITIAL_4,
1243     IMG_TITLESCREEN_INITIAL_5,
1244     IMG_TITLESCREEN_1,
1245     IMG_TITLESCREEN_2,
1246     IMG_TITLESCREEN_3,
1247     IMG_TITLESCREEN_4,
1248     IMG_TITLESCREEN_5,
1249
1250     -1
1251   };
1252
1253   checked_free(graphic_info);
1254
1255   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1256
1257 #if 1
1258   /* initialize "use_image_size" flag with default value */
1259   for (i = 0; i < num_images; i++)
1260     graphic_info[i].use_image_size = FALSE;
1261
1262   /* initialize "use_image_size" flag from static configuration above */
1263   for (i = 0; full_size_graphics[i] != -1; i++)
1264     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1265 #endif
1266
1267 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1268   if (clipmasks_initialized)
1269   {
1270     for (i = 0; i < num_images; i++)
1271     {
1272       if (graphic_info[i].clip_mask)
1273         XFreePixmap(display, graphic_info[i].clip_mask);
1274       if (graphic_info[i].clip_gc)
1275         XFreeGC(display, graphic_info[i].clip_gc);
1276
1277       graphic_info[i].clip_mask = None;
1278       graphic_info[i].clip_gc = None;
1279     }
1280   }
1281 #endif
1282
1283   /* first set all graphic paramaters ... */
1284   for (i = 0; i < num_images; i++)
1285     set_graphic_parameters(i);
1286
1287   /* ... then copy these parameters for cloned graphics */
1288   for (i = 0; i < num_images; i++)
1289     if (graphic_info[i].clone_from != -1)
1290       set_cloned_graphic_parameters(i);
1291
1292   for (i = 0; i < num_images; i++)
1293   {
1294     Bitmap *src_bitmap;
1295     int src_x, src_y;
1296     int width, height;
1297     int first_frame, last_frame;
1298     int src_bitmap_width, src_bitmap_height;
1299
1300     /* now check if no animation frames are outside of the loaded image */
1301
1302     if (graphic_info[i].bitmap == NULL)
1303       continue;         /* skip check for optional images that are undefined */
1304
1305     /* get image size (this can differ from the standard element tile size!) */
1306     width  = graphic_info[i].width;
1307     height = graphic_info[i].height;
1308
1309     /* get final bitmap size (with scaling, but without small images) */
1310     src_bitmap_width  = graphic_info[i].src_image_width;
1311     src_bitmap_height = graphic_info[i].src_image_height;
1312
1313     /* check if first animation frame is inside specified bitmap */
1314
1315     first_frame = 0;
1316     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1317
1318 #if 1
1319     /* this avoids calculating wrong start position for out-of-bounds frame */
1320     src_x = graphic_info[i].src_x;
1321     src_y = graphic_info[i].src_y;
1322 #endif
1323
1324     if (src_x < 0 || src_y < 0 ||
1325         src_x + width  > src_bitmap_width ||
1326         src_y + height > src_bitmap_height)
1327     {
1328       Error(ERR_RETURN_LINE, "-");
1329       Error(ERR_RETURN, "warning: error found in config file:");
1330       Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1331       Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1332       Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1333       Error(ERR_RETURN,
1334             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1335             src_x, src_y, src_bitmap_width, src_bitmap_height);
1336       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1337
1338       if (i == fallback_graphic)
1339         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1340
1341       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1342       Error(ERR_RETURN_LINE, "-");
1343
1344       graphic_info[i] = graphic_info[fallback_graphic];
1345     }
1346
1347     /* check if last animation frame is inside specified bitmap */
1348
1349     last_frame = graphic_info[i].anim_frames - 1;
1350     getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1351
1352     if (src_x < 0 || src_y < 0 ||
1353         src_x + width  > src_bitmap_width ||
1354         src_y + height > src_bitmap_height)
1355     {
1356       Error(ERR_RETURN_LINE, "-");
1357       Error(ERR_RETURN, "warning: error found in config file:");
1358       Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
1359       Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
1360       Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
1361       Error(ERR_RETURN,
1362             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1363             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1364       Error(ERR_RETURN, "custom graphic rejected for this element/action");
1365
1366       if (i == fallback_graphic)
1367         Error(ERR_EXIT, "fatal error: no fallback graphic available");
1368
1369       Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
1370       Error(ERR_RETURN_LINE, "-");
1371
1372       graphic_info[i] = graphic_info[fallback_graphic];
1373     }
1374
1375 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1376     /* currently we only need a tile clip mask from the first frame */
1377     getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1378
1379     if (copy_clipmask_gc == None)
1380     {
1381       clip_gc_values.graphics_exposures = False;
1382       clip_gc_valuemask = GCGraphicsExposures;
1383       copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
1384                                    clip_gc_valuemask, &clip_gc_values);
1385     }
1386
1387     graphic_info[i].clip_mask =
1388       XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
1389
1390     src_pixmap = src_bitmap->clip_mask;
1391     XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
1392               copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
1393
1394     clip_gc_values.graphics_exposures = False;
1395     clip_gc_values.clip_mask = graphic_info[i].clip_mask;
1396     clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
1397
1398     graphic_info[i].clip_gc =
1399       XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
1400 #endif
1401   }
1402
1403 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
1404   if (copy_clipmask_gc)
1405     XFreeGC(display, copy_clipmask_gc);
1406
1407   clipmasks_initialized = TRUE;
1408 #endif
1409 }
1410
1411 static void InitElementSoundInfo()
1412 {
1413   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1414   int num_property_mappings = getSoundListPropertyMappingSize();
1415   int i, j, act;
1416
1417   /* set values to -1 to identify later as "uninitialized" values */
1418   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1419     for (act = 0; act < NUM_ACTIONS; act++)
1420       element_info[i].sound[act] = -1;
1421
1422   /* initialize element/sound mapping from static configuration */
1423   for (i = 0; element_to_sound[i].element > -1; i++)
1424   {
1425     int element      = element_to_sound[i].element;
1426     int action       = element_to_sound[i].action;
1427     int sound        = element_to_sound[i].sound;
1428     boolean is_class = element_to_sound[i].is_class;
1429
1430     if (action < 0)
1431       action = ACTION_DEFAULT;
1432
1433     if (!is_class)
1434       element_info[element].sound[action] = sound;
1435     else
1436       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1437         if (strEqual(element_info[j].class_name,
1438                      element_info[element].class_name))
1439           element_info[j].sound[action] = sound;
1440   }
1441
1442   /* initialize element class/sound mapping from dynamic configuration */
1443   for (i = 0; i < num_property_mappings; i++)
1444   {
1445     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1446     int action        = property_mapping[i].ext1_index;
1447     int sound         = property_mapping[i].artwork_index;
1448
1449     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1450       continue;
1451
1452     if (action < 0)
1453       action = ACTION_DEFAULT;
1454
1455     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1456       if (strEqual(element_info[j].class_name,
1457                    element_info[element_class].class_name))
1458         element_info[j].sound[action] = sound;
1459   }
1460
1461   /* initialize element/sound mapping from dynamic configuration */
1462   for (i = 0; i < num_property_mappings; i++)
1463   {
1464     int element = property_mapping[i].base_index;
1465     int action  = property_mapping[i].ext1_index;
1466     int sound   = property_mapping[i].artwork_index;
1467
1468     if (element >= MAX_NUM_ELEMENTS)
1469       continue;
1470
1471     if (action < 0)
1472       action = ACTION_DEFAULT;
1473
1474     element_info[element].sound[action] = sound;
1475   }
1476
1477   /* now set all '-1' values to element specific default values */
1478   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1479   {
1480     for (act = 0; act < NUM_ACTIONS; act++)
1481     {
1482       /* generic default action sound (defined by "[default]" directive) */
1483       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1484
1485       /* look for special default action sound (classic game specific) */
1486       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1487         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1488       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1489         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1490       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1491         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1492
1493       /* !!! there's no such thing as a "default action sound" !!! */
1494 #if 0
1495       /* look for element specific default sound (independent from action) */
1496       if (element_info[i].sound[ACTION_DEFAULT] != -1)
1497         default_action_sound = element_info[i].sound[ACTION_DEFAULT];
1498 #endif
1499
1500 #if 1
1501       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1502       /* !!! make this better !!! */
1503       if (i == EL_EMPTY_SPACE)
1504         default_action_sound = element_info[EL_DEFAULT].sound[act];
1505 #endif
1506
1507       /* no sound for this specific action -- use default action sound */
1508       if (element_info[i].sound[act] == -1)
1509         element_info[i].sound[act] = default_action_sound;
1510     }
1511   }
1512
1513   /* copy sound settings to some elements that are only stored in level file
1514      in native R'n'D levels, but are used by game engine in native EM levels */
1515   for (i = 0; copy_properties[i][0] != -1; i++)
1516     for (j = 1; j <= 4; j++)
1517       for (act = 0; act < NUM_ACTIONS; act++)
1518         element_info[copy_properties[i][j]].sound[act] =
1519           element_info[copy_properties[i][0]].sound[act];
1520 }
1521
1522 static void InitGameModeSoundInfo()
1523 {
1524   int i;
1525
1526   /* set values to -1 to identify later as "uninitialized" values */
1527   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1528     menu.sound[i] = -1;
1529
1530   /* initialize gamemode/sound mapping from static configuration */
1531   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1532   {
1533     int gamemode = gamemode_to_sound[i].gamemode;
1534     int sound    = gamemode_to_sound[i].sound;
1535
1536     if (gamemode < 0)
1537       gamemode = GAME_MODE_DEFAULT;
1538
1539     menu.sound[gamemode] = sound;
1540   }
1541
1542   /* now set all '-1' values to levelset specific default values */
1543   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1544     if (menu.sound[i] == -1)
1545       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1546
1547 #if 0
1548   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1549     if (menu.sound[i] != -1)
1550       printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
1551 #endif
1552 }
1553
1554 static void set_sound_parameters(int sound, char **parameter_raw)
1555 {
1556   int parameter[NUM_SND_ARGS];
1557   int i;
1558
1559   /* get integer values from string parameters */
1560   for (i = 0; i < NUM_SND_ARGS; i++)
1561     parameter[i] =
1562       get_parameter_value(parameter_raw[i],
1563                           sound_config_suffix[i].token,
1564                           sound_config_suffix[i].type);
1565
1566   /* explicit loop mode setting in configuration overrides default value */
1567   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1568     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1569
1570   /* sound volume to change the original volume when loading the sound file */
1571   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1572
1573   /* sound priority to give certain sounds a higher or lower priority */
1574   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1575 }
1576
1577 static void InitSoundInfo()
1578 {
1579   int *sound_effect_properties;
1580   int num_sounds = getSoundListSize();
1581   int i, j;
1582
1583   checked_free(sound_info);
1584
1585   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1586   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1587
1588   /* initialize sound effect for all elements to "no sound" */
1589   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1590     for (j = 0; j < NUM_ACTIONS; j++)
1591       element_info[i].sound[j] = SND_UNDEFINED;
1592
1593   for (i = 0; i < num_sounds; i++)
1594   {
1595     struct FileInfo *sound = getSoundListEntry(i);
1596     int len_effect_text = strlen(sound->token);
1597
1598     sound_effect_properties[i] = ACTION_OTHER;
1599     sound_info[i].loop = FALSE;         /* default: play sound only once */
1600
1601 #if 0
1602     printf("::: sound %d: '%s'\n", i, sound->token);
1603 #endif
1604
1605     /* determine all loop sounds and identify certain sound classes */
1606
1607     for (j = 0; element_action_info[j].suffix; j++)
1608     {
1609       int len_action_text = strlen(element_action_info[j].suffix);
1610
1611       if (len_action_text < len_effect_text &&
1612           strEqual(&sound->token[len_effect_text - len_action_text],
1613                    element_action_info[j].suffix))
1614       {
1615         sound_effect_properties[i] = element_action_info[j].value;
1616         sound_info[i].loop = element_action_info[j].is_loop_sound;
1617
1618         break;
1619       }
1620     }
1621
1622     /* associate elements and some selected sound actions */
1623
1624     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1625     {
1626       if (element_info[j].class_name)
1627       {
1628         int len_class_text = strlen(element_info[j].class_name);
1629
1630         if (len_class_text + 1 < len_effect_text &&
1631             strncmp(sound->token,
1632                     element_info[j].class_name, len_class_text) == 0 &&
1633             sound->token[len_class_text] == '.')
1634         {
1635           int sound_action_value = sound_effect_properties[i];
1636
1637           element_info[j].sound[sound_action_value] = i;
1638         }
1639       }
1640     }
1641
1642     set_sound_parameters(i, sound->parameter);
1643   }
1644
1645   free(sound_effect_properties);
1646 }
1647
1648 static void InitGameModeMusicInfo()
1649 {
1650   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
1651   int num_property_mappings = getMusicListPropertyMappingSize();
1652   int default_levelset_music = -1;
1653   int i;
1654
1655   /* set values to -1 to identify later as "uninitialized" values */
1656   for (i = 0; i < MAX_LEVELS; i++)
1657     levelset.music[i] = -1;
1658   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1659     menu.music[i] = -1;
1660
1661   /* initialize gamemode/music mapping from static configuration */
1662   for (i = 0; gamemode_to_music[i].music > -1; i++)
1663   {
1664     int gamemode = gamemode_to_music[i].gamemode;
1665     int music    = gamemode_to_music[i].music;
1666
1667 #if 0
1668     printf("::: gamemode == %d, music == %d\n", gamemode, music);
1669 #endif
1670
1671     if (gamemode < 0)
1672       gamemode = GAME_MODE_DEFAULT;
1673
1674     menu.music[gamemode] = music;
1675   }
1676
1677   /* initialize gamemode/music mapping from dynamic configuration */
1678   for (i = 0; i < num_property_mappings; i++)
1679   {
1680     int prefix   = property_mapping[i].base_index;
1681     int gamemode = property_mapping[i].ext1_index;
1682     int level    = property_mapping[i].ext2_index;
1683     int music    = property_mapping[i].artwork_index;
1684
1685 #if 0
1686     printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
1687            prefix, gamemode, level, music);
1688 #endif
1689
1690     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
1691       continue;
1692
1693     if (gamemode < 0)
1694       gamemode = GAME_MODE_DEFAULT;
1695
1696     /* level specific music only allowed for in-game music */
1697     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
1698       gamemode = GAME_MODE_PLAYING;
1699
1700     if (level == -1)
1701     {
1702       level = 0;
1703       default_levelset_music = music;
1704     }
1705
1706     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
1707       levelset.music[level] = music;
1708     if (gamemode != GAME_MODE_PLAYING)
1709       menu.music[gamemode] = music;
1710   }
1711
1712   /* now set all '-1' values to menu specific default values */
1713   /* (undefined values of "levelset.music[]" might stay at "-1" to
1714      allow dynamic selection of music files from music directory!) */
1715   for (i = 0; i < MAX_LEVELS; i++)
1716     if (levelset.music[i] == -1)
1717       levelset.music[i] = default_levelset_music;
1718   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1719     if (menu.music[i] == -1)
1720       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
1721
1722 #if 0
1723   for (i = 0; i < MAX_LEVELS; i++)
1724     if (levelset.music[i] != -1)
1725       printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
1726   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1727     if (menu.music[i] != -1)
1728       printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
1729 #endif
1730 }
1731
1732 static void set_music_parameters(int music, char **parameter_raw)
1733 {
1734   int parameter[NUM_MUS_ARGS];
1735   int i;
1736
1737   /* get integer values from string parameters */
1738   for (i = 0; i < NUM_MUS_ARGS; i++)
1739     parameter[i] =
1740       get_parameter_value(parameter_raw[i],
1741                           music_config_suffix[i].token,
1742                           music_config_suffix[i].type);
1743
1744   /* explicit loop mode setting in configuration overrides default value */
1745   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1746     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
1747 }
1748
1749 static void InitMusicInfo()
1750 {
1751   int num_music = getMusicListSize();
1752   int i, j;
1753
1754   checked_free(music_info);
1755
1756   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
1757
1758   for (i = 0; i < num_music; i++)
1759   {
1760     struct FileInfo *music = getMusicListEntry(i);
1761     int len_music_text = strlen(music->token);
1762
1763     music_info[i].loop = TRUE;          /* default: play music in loop mode */
1764
1765     /* determine all loop music */
1766
1767     for (j = 0; music_prefix_info[j].prefix; j++)
1768     {
1769       int len_prefix_text = strlen(music_prefix_info[j].prefix);
1770
1771       if (len_prefix_text < len_music_text &&
1772           strncmp(music->token,
1773                   music_prefix_info[j].prefix, len_prefix_text) == 0)
1774       {
1775         music_info[i].loop = music_prefix_info[j].is_loop_music;
1776
1777         break;
1778       }
1779     }
1780
1781     set_music_parameters(i, music->parameter);
1782   }
1783 }
1784
1785 static void ReinitializeGraphics()
1786 {
1787   InitGraphicInfo();                    /* graphic properties mapping */
1788   InitElementGraphicInfo();             /* element game graphic mapping */
1789   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
1790
1791   InitElementSmallImages();             /* scale elements to all needed sizes */
1792   InitScaledImages();                   /* scale all other images, if needed */
1793   InitFontGraphicInfo();                /* initialize text drawing functions */
1794
1795   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
1796
1797   SetMainBackgroundImage(IMG_BACKGROUND);
1798   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
1799
1800   InitGadgets();
1801   InitToons();
1802 }
1803
1804 static void ReinitializeSounds()
1805 {
1806   InitSoundInfo();              /* sound properties mapping */
1807   InitElementSoundInfo();       /* element game sound mapping */
1808   InitGameModeSoundInfo();      /* game mode sound mapping */
1809
1810   InitPlayLevelSound();         /* internal game sound settings */
1811 }
1812
1813 static void ReinitializeMusic()
1814 {
1815   InitMusicInfo();              /* music properties mapping */
1816   InitGameModeMusicInfo();      /* game mode music mapping */
1817 }
1818
1819 static int get_special_property_bit(int element, int property_bit_nr)
1820 {
1821   struct PropertyBitInfo
1822   {
1823     int element;
1824     int bit_nr;
1825   };
1826
1827   static struct PropertyBitInfo pb_can_move_into_acid[] =
1828   {
1829     /* the player may be able fall into acid when gravity is activated */
1830     { EL_PLAYER_1,              0       },
1831     { EL_PLAYER_2,              0       },
1832     { EL_PLAYER_3,              0       },
1833     { EL_PLAYER_4,              0       },
1834     { EL_SP_MURPHY,             0       },
1835     { EL_SOKOBAN_FIELD_PLAYER,  0       },
1836
1837     /* all elements that can move may be able to also move into acid */
1838     { EL_BUG,                   1       },
1839     { EL_BUG_LEFT,              1       },
1840     { EL_BUG_RIGHT,             1       },
1841     { EL_BUG_UP,                1       },
1842     { EL_BUG_DOWN,              1       },
1843     { EL_SPACESHIP,             2       },
1844     { EL_SPACESHIP_LEFT,        2       },
1845     { EL_SPACESHIP_RIGHT,       2       },
1846     { EL_SPACESHIP_UP,          2       },
1847     { EL_SPACESHIP_DOWN,        2       },
1848     { EL_BD_BUTTERFLY,          3       },
1849     { EL_BD_BUTTERFLY_LEFT,     3       },
1850     { EL_BD_BUTTERFLY_RIGHT,    3       },
1851     { EL_BD_BUTTERFLY_UP,       3       },
1852     { EL_BD_BUTTERFLY_DOWN,     3       },
1853     { EL_BD_FIREFLY,            4       },
1854     { EL_BD_FIREFLY_LEFT,       4       },
1855     { EL_BD_FIREFLY_RIGHT,      4       },
1856     { EL_BD_FIREFLY_UP,         4       },
1857     { EL_BD_FIREFLY_DOWN,       4       },
1858     { EL_YAMYAM,                5       },
1859     { EL_YAMYAM_LEFT,           5       },
1860     { EL_YAMYAM_RIGHT,          5       },
1861     { EL_YAMYAM_UP,             5       },
1862     { EL_YAMYAM_DOWN,           5       },
1863     { EL_DARK_YAMYAM,           6       },
1864     { EL_ROBOT,                 7       },
1865     { EL_PACMAN,                8       },
1866     { EL_PACMAN_LEFT,           8       },
1867     { EL_PACMAN_RIGHT,          8       },
1868     { EL_PACMAN_UP,             8       },
1869     { EL_PACMAN_DOWN,           8       },
1870     { EL_MOLE,                  9       },
1871     { EL_MOLE_LEFT,             9       },
1872     { EL_MOLE_RIGHT,            9       },
1873     { EL_MOLE_UP,               9       },
1874     { EL_MOLE_DOWN,             9       },
1875     { EL_PENGUIN,               10      },
1876     { EL_PIG,                   11      },
1877     { EL_DRAGON,                12      },
1878     { EL_SATELLITE,             13      },
1879     { EL_SP_SNIKSNAK,           14      },
1880     { EL_SP_ELECTRON,           15      },
1881     { EL_BALLOON,               16      },
1882     { EL_SPRING,                17      },
1883     { EL_EMC_ANDROID,           18      },
1884
1885     { -1,                       -1      },
1886   };
1887
1888   static struct PropertyBitInfo pb_dont_collide_with[] =
1889   {
1890     { EL_SP_SNIKSNAK,           0       },
1891     { EL_SP_ELECTRON,           1       },
1892
1893     { -1,                       -1      },
1894   };
1895
1896   static struct
1897   {
1898     int bit_nr;
1899     struct PropertyBitInfo *pb_info;
1900   } pb_definition[] =
1901   {
1902     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
1903     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
1904
1905     { -1,                       NULL                    },
1906   };
1907
1908   struct PropertyBitInfo *pb_info = NULL;
1909   int i;
1910
1911   for (i = 0; pb_definition[i].bit_nr != -1; i++)
1912     if (pb_definition[i].bit_nr == property_bit_nr)
1913       pb_info = pb_definition[i].pb_info;
1914
1915   if (pb_info == NULL)
1916     return -1;
1917
1918   for (i = 0; pb_info[i].element != -1; i++)
1919     if (pb_info[i].element == element)
1920       return pb_info[i].bit_nr;
1921
1922   return -1;
1923 }
1924
1925 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
1926                          boolean property_value)
1927 {
1928   int bit_nr = get_special_property_bit(element, property_bit_nr);
1929
1930   if (bit_nr > -1)
1931   {
1932     if (property_value)
1933       *bitfield |=  (1 << bit_nr);
1934     else
1935       *bitfield &= ~(1 << bit_nr);
1936   }
1937 }
1938
1939 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
1940 {
1941   int bit_nr = get_special_property_bit(element, property_bit_nr);
1942
1943   if (bit_nr > -1)
1944     return ((*bitfield & (1 << bit_nr)) != 0);
1945
1946   return FALSE;
1947 }
1948
1949 static void resolve_group_element(int group_element, int recursion_depth)
1950 {
1951   static int group_nr;
1952   static struct ElementGroupInfo *group;
1953   struct ElementGroupInfo *actual_group = element_info[group_element].group;
1954   int i;
1955
1956   if (actual_group == NULL)                     /* not yet initialized */
1957     return;
1958
1959   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
1960   {
1961     Error(ERR_WARN, "recursion too deep when resolving group element %d",
1962           group_element - EL_GROUP_START + 1);
1963
1964     /* replace element which caused too deep recursion by question mark */
1965     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1966
1967     return;
1968   }
1969
1970   if (recursion_depth == 0)                     /* initialization */
1971   {
1972     group = actual_group;
1973     group_nr = group_element - EL_GROUP_START;
1974
1975     group->num_elements_resolved = 0;
1976     group->choice_pos = 0;
1977   }
1978
1979   for (i = 0; i < actual_group->num_elements; i++)
1980   {
1981     int element = actual_group->element[i];
1982
1983     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1984       break;
1985
1986     if (IS_GROUP_ELEMENT(element))
1987       resolve_group_element(element, recursion_depth + 1);
1988     else
1989     {
1990       group->element_resolved[group->num_elements_resolved++] = element;
1991       element_info[element].in_group[group_nr] = TRUE;
1992     }
1993   }
1994 }
1995
1996 void InitElementPropertiesStatic()
1997 {
1998   static int ep_diggable[] =
1999   {
2000     EL_SAND,
2001     EL_SP_BASE,
2002     EL_SP_BUGGY_BASE,
2003     EL_SP_BUGGY_BASE_ACTIVATING,
2004     EL_TRAP,
2005     EL_INVISIBLE_SAND,
2006     EL_INVISIBLE_SAND_ACTIVE,
2007     EL_EMC_GRASS,
2008
2009     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2010     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2011 #if 0
2012     EL_LANDMINE,
2013     EL_TRAP_ACTIVE,
2014     EL_SP_BUGGY_BASE_ACTIVE,
2015     EL_EMC_PLANT,
2016 #endif
2017
2018     -1
2019   };
2020
2021   static int ep_collectible_only[] =
2022   {
2023     EL_BD_DIAMOND,
2024     EL_EMERALD,
2025     EL_DIAMOND,
2026     EL_EMERALD_YELLOW,
2027     EL_EMERALD_RED,
2028     EL_EMERALD_PURPLE,
2029     EL_KEY_1,
2030     EL_KEY_2,
2031     EL_KEY_3,
2032     EL_KEY_4,
2033     EL_EM_KEY_1,
2034     EL_EM_KEY_2,
2035     EL_EM_KEY_3,
2036     EL_EM_KEY_4,
2037     EL_EMC_KEY_5,
2038     EL_EMC_KEY_6,
2039     EL_EMC_KEY_7,
2040     EL_EMC_KEY_8,
2041     EL_DYNAMITE,
2042     EL_EM_DYNAMITE,
2043     EL_DYNABOMB_INCREASE_NUMBER,
2044     EL_DYNABOMB_INCREASE_SIZE,
2045     EL_DYNABOMB_INCREASE_POWER,
2046     EL_SP_INFOTRON,
2047     EL_SP_DISK_RED,
2048     EL_PEARL,
2049     EL_CRYSTAL,
2050     EL_KEY_WHITE,
2051     EL_SHIELD_NORMAL,
2052     EL_SHIELD_DEADLY,
2053     EL_EXTRA_TIME,
2054     EL_ENVELOPE_1,
2055     EL_ENVELOPE_2,
2056     EL_ENVELOPE_3,
2057     EL_ENVELOPE_4,
2058     EL_SPEED_PILL,
2059     EL_EMC_LENSES,
2060     EL_EMC_MAGNIFIER,
2061
2062     -1
2063   };
2064
2065   static int ep_dont_run_into[] =
2066   {
2067     /* same elements as in 'ep_dont_touch' */
2068     EL_BUG,
2069     EL_SPACESHIP,
2070     EL_BD_BUTTERFLY,
2071     EL_BD_FIREFLY,
2072
2073     /* same elements as in 'ep_dont_collide_with' */
2074     EL_YAMYAM,
2075     EL_DARK_YAMYAM,
2076     EL_ROBOT,
2077     EL_PACMAN,
2078     EL_SP_SNIKSNAK,
2079     EL_SP_ELECTRON,
2080
2081     /* new elements */
2082     EL_AMOEBA_DROP,
2083     EL_ACID,
2084
2085     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2086 #if 1
2087     EL_LANDMINE,
2088     EL_TRAP_ACTIVE,
2089     EL_SP_BUGGY_BASE_ACTIVE,
2090     EL_EMC_PLANT,
2091 #endif
2092
2093     -1
2094   };
2095
2096   static int ep_dont_collide_with[] =
2097   {
2098     /* same elements as in 'ep_dont_touch' */
2099     EL_BUG,
2100     EL_SPACESHIP,
2101     EL_BD_BUTTERFLY,
2102     EL_BD_FIREFLY,
2103
2104     /* new elements */
2105     EL_YAMYAM,
2106     EL_DARK_YAMYAM,
2107     EL_ROBOT,
2108     EL_PACMAN,
2109     EL_SP_SNIKSNAK,
2110     EL_SP_ELECTRON,
2111
2112     -1
2113   };
2114
2115   static int ep_dont_touch[] =
2116   {
2117     EL_BUG,
2118     EL_SPACESHIP,
2119     EL_BD_BUTTERFLY,
2120     EL_BD_FIREFLY,
2121
2122     -1
2123   };
2124
2125   static int ep_indestructible[] =
2126   {
2127     EL_STEELWALL,
2128     EL_ACID,
2129     EL_ACID_POOL_TOPLEFT,
2130     EL_ACID_POOL_TOPRIGHT,
2131     EL_ACID_POOL_BOTTOMLEFT,
2132     EL_ACID_POOL_BOTTOM,
2133     EL_ACID_POOL_BOTTOMRIGHT,
2134     EL_SP_HARDWARE_GRAY,
2135     EL_SP_HARDWARE_GREEN,
2136     EL_SP_HARDWARE_BLUE,
2137     EL_SP_HARDWARE_RED,
2138     EL_SP_HARDWARE_YELLOW,
2139     EL_SP_HARDWARE_BASE_1,
2140     EL_SP_HARDWARE_BASE_2,
2141     EL_SP_HARDWARE_BASE_3,
2142     EL_SP_HARDWARE_BASE_4,
2143     EL_SP_HARDWARE_BASE_5,
2144     EL_SP_HARDWARE_BASE_6,
2145     EL_INVISIBLE_STEELWALL,
2146     EL_INVISIBLE_STEELWALL_ACTIVE,
2147     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2148     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2149     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2150     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2151     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2152     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2153     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2154     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2155     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2156     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2157     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2158     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2159     EL_LIGHT_SWITCH,
2160     EL_LIGHT_SWITCH_ACTIVE,
2161     EL_SIGN_EXCLAMATION,
2162     EL_SIGN_RADIOACTIVITY,
2163     EL_SIGN_STOP,
2164     EL_SIGN_WHEELCHAIR,
2165     EL_SIGN_PARKING,
2166     EL_SIGN_ONEWAY,
2167     EL_SIGN_HEART,
2168     EL_SIGN_TRIANGLE,
2169     EL_SIGN_ROUND,
2170     EL_SIGN_EXIT,
2171     EL_SIGN_YINYANG,
2172     EL_SIGN_OTHER,
2173     EL_STEELWALL_SLIPPERY,
2174     EL_EMC_STEELWALL_1,
2175     EL_EMC_STEELWALL_2,
2176     EL_EMC_STEELWALL_3,
2177     EL_EMC_STEELWALL_4,
2178     EL_CRYSTAL,
2179     EL_GATE_1,
2180     EL_GATE_2,
2181     EL_GATE_3,
2182     EL_GATE_4,
2183     EL_GATE_1_GRAY,
2184     EL_GATE_2_GRAY,
2185     EL_GATE_3_GRAY,
2186     EL_GATE_4_GRAY,
2187     EL_GATE_1_GRAY_ACTIVE,
2188     EL_GATE_2_GRAY_ACTIVE,
2189     EL_GATE_3_GRAY_ACTIVE,
2190     EL_GATE_4_GRAY_ACTIVE,
2191     EL_EM_GATE_1,
2192     EL_EM_GATE_2,
2193     EL_EM_GATE_3,
2194     EL_EM_GATE_4,
2195     EL_EM_GATE_1_GRAY,
2196     EL_EM_GATE_2_GRAY,
2197     EL_EM_GATE_3_GRAY,
2198     EL_EM_GATE_4_GRAY,
2199     EL_EM_GATE_1_GRAY_ACTIVE,
2200     EL_EM_GATE_2_GRAY_ACTIVE,
2201     EL_EM_GATE_3_GRAY_ACTIVE,
2202     EL_EM_GATE_4_GRAY_ACTIVE,
2203     EL_EMC_GATE_5,
2204     EL_EMC_GATE_6,
2205     EL_EMC_GATE_7,
2206     EL_EMC_GATE_8,
2207     EL_EMC_GATE_5_GRAY,
2208     EL_EMC_GATE_6_GRAY,
2209     EL_EMC_GATE_7_GRAY,
2210     EL_EMC_GATE_8_GRAY,
2211     EL_EMC_GATE_5_GRAY_ACTIVE,
2212     EL_EMC_GATE_6_GRAY_ACTIVE,
2213     EL_EMC_GATE_7_GRAY_ACTIVE,
2214     EL_EMC_GATE_8_GRAY_ACTIVE,
2215     EL_SWITCHGATE_OPEN,
2216     EL_SWITCHGATE_OPENING,
2217     EL_SWITCHGATE_CLOSED,
2218     EL_SWITCHGATE_CLOSING,
2219 #if 0
2220     EL_SWITCHGATE_SWITCH_UP,
2221     EL_SWITCHGATE_SWITCH_DOWN,
2222 #endif
2223     EL_TIMEGATE_OPEN,
2224     EL_TIMEGATE_OPENING,
2225     EL_TIMEGATE_CLOSED,
2226     EL_TIMEGATE_CLOSING,
2227 #if 0
2228     EL_TIMEGATE_SWITCH,
2229     EL_TIMEGATE_SWITCH_ACTIVE,
2230 #endif
2231     EL_TUBE_ANY,
2232     EL_TUBE_VERTICAL,
2233     EL_TUBE_HORIZONTAL,
2234     EL_TUBE_VERTICAL_LEFT,
2235     EL_TUBE_VERTICAL_RIGHT,
2236     EL_TUBE_HORIZONTAL_UP,
2237     EL_TUBE_HORIZONTAL_DOWN,
2238     EL_TUBE_LEFT_UP,
2239     EL_TUBE_LEFT_DOWN,
2240     EL_TUBE_RIGHT_UP,
2241     EL_TUBE_RIGHT_DOWN,
2242
2243     -1
2244   };
2245
2246   static int ep_slippery[] =
2247   {
2248     EL_WALL_SLIPPERY,
2249     EL_BD_WALL,
2250     EL_ROCK,
2251     EL_BD_ROCK,
2252     EL_EMERALD,
2253     EL_BD_DIAMOND,
2254     EL_EMERALD_YELLOW,
2255     EL_EMERALD_RED,
2256     EL_EMERALD_PURPLE,
2257     EL_DIAMOND,
2258     EL_BOMB,
2259     EL_NUT,
2260     EL_ROBOT_WHEEL_ACTIVE,
2261     EL_ROBOT_WHEEL,
2262     EL_TIME_ORB_FULL,
2263     EL_TIME_ORB_EMPTY,
2264     EL_LAMP_ACTIVE,
2265     EL_LAMP,
2266     EL_ACID_POOL_TOPLEFT,
2267     EL_ACID_POOL_TOPRIGHT,
2268     EL_SATELLITE,
2269     EL_SP_ZONK,
2270     EL_SP_INFOTRON,
2271     EL_SP_CHIP_SINGLE,
2272     EL_SP_CHIP_LEFT,
2273     EL_SP_CHIP_RIGHT,
2274     EL_SP_CHIP_TOP,
2275     EL_SP_CHIP_BOTTOM,
2276     EL_SPEED_PILL,
2277     EL_STEELWALL_SLIPPERY,
2278     EL_PEARL,
2279     EL_CRYSTAL,
2280     EL_EMC_WALL_SLIPPERY_1,
2281     EL_EMC_WALL_SLIPPERY_2,
2282     EL_EMC_WALL_SLIPPERY_3,
2283     EL_EMC_WALL_SLIPPERY_4,
2284     EL_EMC_MAGIC_BALL,
2285     EL_EMC_MAGIC_BALL_ACTIVE,
2286
2287     -1
2288   };
2289
2290   static int ep_can_change[] =
2291   {
2292     -1
2293   };
2294
2295   static int ep_can_move[] =
2296   {
2297     /* same elements as in 'pb_can_move_into_acid' */
2298     EL_BUG,
2299     EL_SPACESHIP,
2300     EL_BD_BUTTERFLY,
2301     EL_BD_FIREFLY,
2302     EL_YAMYAM,
2303     EL_DARK_YAMYAM,
2304     EL_ROBOT,
2305     EL_PACMAN,
2306     EL_MOLE,
2307     EL_PENGUIN,
2308     EL_PIG,
2309     EL_DRAGON,
2310     EL_SATELLITE,
2311     EL_SP_SNIKSNAK,
2312     EL_SP_ELECTRON,
2313     EL_BALLOON,
2314     EL_SPRING,
2315     EL_EMC_ANDROID,
2316
2317     -1
2318   };
2319
2320   static int ep_can_fall[] =
2321   {
2322     EL_ROCK,
2323     EL_BD_ROCK,
2324     EL_EMERALD,
2325     EL_BD_DIAMOND,
2326     EL_EMERALD_YELLOW,
2327     EL_EMERALD_RED,
2328     EL_EMERALD_PURPLE,
2329     EL_DIAMOND,
2330     EL_BOMB,
2331     EL_NUT,
2332     EL_AMOEBA_DROP,
2333     EL_QUICKSAND_FULL,
2334     EL_MAGIC_WALL_FULL,
2335     EL_BD_MAGIC_WALL_FULL,
2336     EL_TIME_ORB_FULL,
2337     EL_TIME_ORB_EMPTY,
2338     EL_SP_ZONK,
2339     EL_SP_INFOTRON,
2340     EL_SP_DISK_ORANGE,
2341     EL_PEARL,
2342     EL_CRYSTAL,
2343     EL_SPRING,
2344     EL_DX_SUPABOMB,
2345
2346     -1
2347   };
2348
2349   static int ep_can_smash_player[] =
2350   {
2351     EL_ROCK,
2352     EL_BD_ROCK,
2353     EL_EMERALD,
2354     EL_BD_DIAMOND,
2355     EL_EMERALD_YELLOW,
2356     EL_EMERALD_RED,
2357     EL_EMERALD_PURPLE,
2358     EL_DIAMOND,
2359     EL_BOMB,
2360     EL_NUT,
2361     EL_AMOEBA_DROP,
2362     EL_TIME_ORB_FULL,
2363     EL_TIME_ORB_EMPTY,
2364     EL_SP_ZONK,
2365     EL_SP_INFOTRON,
2366     EL_SP_DISK_ORANGE,
2367     EL_PEARL,
2368     EL_CRYSTAL,
2369     EL_SPRING,
2370     EL_DX_SUPABOMB,
2371
2372     -1
2373   };
2374
2375   static int ep_can_smash_enemies[] =
2376   {
2377     EL_ROCK,
2378     EL_BD_ROCK,
2379     EL_SP_ZONK,
2380
2381     -1
2382   };
2383
2384   static int ep_can_smash_everything[] =
2385   {
2386     EL_ROCK,
2387     EL_BD_ROCK,
2388     EL_SP_ZONK,
2389
2390     -1
2391   };
2392
2393   static int ep_explodes_by_fire[] =
2394   {
2395     /* same elements as in 'ep_explodes_impact' */
2396     EL_BOMB,
2397     EL_SP_DISK_ORANGE,
2398     EL_DX_SUPABOMB,
2399
2400     /* same elements as in 'ep_explodes_smashed' */
2401     EL_SATELLITE,
2402     EL_PIG,
2403     EL_DRAGON,
2404     EL_MOLE,
2405
2406     /* new elements */
2407     EL_DYNAMITE,
2408     EL_DYNAMITE_ACTIVE,
2409     EL_EM_DYNAMITE,
2410     EL_EM_DYNAMITE_ACTIVE,
2411     EL_DYNABOMB_PLAYER_1_ACTIVE,
2412     EL_DYNABOMB_PLAYER_2_ACTIVE,
2413     EL_DYNABOMB_PLAYER_3_ACTIVE,
2414     EL_DYNABOMB_PLAYER_4_ACTIVE,
2415     EL_DYNABOMB_INCREASE_NUMBER,
2416     EL_DYNABOMB_INCREASE_SIZE,
2417     EL_DYNABOMB_INCREASE_POWER,
2418     EL_SP_DISK_RED_ACTIVE,
2419     EL_BUG,
2420     EL_PENGUIN,
2421     EL_SP_DISK_RED,
2422     EL_SP_DISK_YELLOW,
2423     EL_SP_SNIKSNAK,
2424     EL_SP_ELECTRON,
2425 #if 0
2426     EL_BLACK_ORB,
2427 #endif
2428
2429     -1
2430   };
2431
2432   static int ep_explodes_smashed[] =
2433   {
2434     /* same elements as in 'ep_explodes_impact' */
2435     EL_BOMB,
2436     EL_SP_DISK_ORANGE,
2437     EL_DX_SUPABOMB,
2438
2439     /* new elements */
2440     EL_SATELLITE,
2441     EL_PIG,
2442     EL_DRAGON,
2443     EL_MOLE,
2444
2445     -1
2446   };
2447
2448   static int ep_explodes_impact[] =
2449   {
2450     EL_BOMB,
2451     EL_SP_DISK_ORANGE,
2452     EL_DX_SUPABOMB,
2453
2454     -1
2455   };
2456
2457   static int ep_walkable_over[] =
2458   {
2459     EL_EMPTY_SPACE,
2460     EL_SP_EMPTY_SPACE,
2461     EL_SOKOBAN_FIELD_EMPTY,
2462     EL_EXIT_OPEN,
2463     EL_SP_EXIT_OPEN,
2464     EL_SP_EXIT_OPENING,
2465     EL_GATE_1,
2466     EL_GATE_2,
2467     EL_GATE_3,
2468     EL_GATE_4,
2469     EL_GATE_1_GRAY,
2470     EL_GATE_2_GRAY,
2471     EL_GATE_3_GRAY,
2472     EL_GATE_4_GRAY,
2473     EL_GATE_1_GRAY_ACTIVE,
2474     EL_GATE_2_GRAY_ACTIVE,
2475     EL_GATE_3_GRAY_ACTIVE,
2476     EL_GATE_4_GRAY_ACTIVE,
2477     EL_PENGUIN,
2478     EL_PIG,
2479     EL_DRAGON,
2480
2481     -1
2482   };
2483
2484   static int ep_walkable_inside[] =
2485   {
2486     EL_TUBE_ANY,
2487     EL_TUBE_VERTICAL,
2488     EL_TUBE_HORIZONTAL,
2489     EL_TUBE_VERTICAL_LEFT,
2490     EL_TUBE_VERTICAL_RIGHT,
2491     EL_TUBE_HORIZONTAL_UP,
2492     EL_TUBE_HORIZONTAL_DOWN,
2493     EL_TUBE_LEFT_UP,
2494     EL_TUBE_LEFT_DOWN,
2495     EL_TUBE_RIGHT_UP,
2496     EL_TUBE_RIGHT_DOWN,
2497
2498     -1
2499   };
2500
2501   static int ep_walkable_under[] =
2502   {
2503     -1
2504   };
2505
2506   static int ep_passable_over[] =
2507   {
2508     EL_EM_GATE_1,
2509     EL_EM_GATE_2,
2510     EL_EM_GATE_3,
2511     EL_EM_GATE_4,
2512     EL_EM_GATE_1_GRAY,
2513     EL_EM_GATE_2_GRAY,
2514     EL_EM_GATE_3_GRAY,
2515     EL_EM_GATE_4_GRAY,
2516     EL_EM_GATE_1_GRAY_ACTIVE,
2517     EL_EM_GATE_2_GRAY_ACTIVE,
2518     EL_EM_GATE_3_GRAY_ACTIVE,
2519     EL_EM_GATE_4_GRAY_ACTIVE,
2520     EL_EMC_GATE_5,
2521     EL_EMC_GATE_6,
2522     EL_EMC_GATE_7,
2523     EL_EMC_GATE_8,
2524     EL_EMC_GATE_5_GRAY,
2525     EL_EMC_GATE_6_GRAY,
2526     EL_EMC_GATE_7_GRAY,
2527     EL_EMC_GATE_8_GRAY,
2528     EL_EMC_GATE_5_GRAY_ACTIVE,
2529     EL_EMC_GATE_6_GRAY_ACTIVE,
2530     EL_EMC_GATE_7_GRAY_ACTIVE,
2531     EL_EMC_GATE_8_GRAY_ACTIVE,
2532     EL_SWITCHGATE_OPEN,
2533     EL_TIMEGATE_OPEN,
2534
2535     -1
2536   };
2537
2538   static int ep_passable_inside[] =
2539   {
2540     EL_SP_PORT_LEFT,
2541     EL_SP_PORT_RIGHT,
2542     EL_SP_PORT_UP,
2543     EL_SP_PORT_DOWN,
2544     EL_SP_PORT_HORIZONTAL,
2545     EL_SP_PORT_VERTICAL,
2546     EL_SP_PORT_ANY,
2547     EL_SP_GRAVITY_PORT_LEFT,
2548     EL_SP_GRAVITY_PORT_RIGHT,
2549     EL_SP_GRAVITY_PORT_UP,
2550     EL_SP_GRAVITY_PORT_DOWN,
2551     EL_SP_GRAVITY_ON_PORT_LEFT,
2552     EL_SP_GRAVITY_ON_PORT_RIGHT,
2553     EL_SP_GRAVITY_ON_PORT_UP,
2554     EL_SP_GRAVITY_ON_PORT_DOWN,
2555     EL_SP_GRAVITY_OFF_PORT_LEFT,
2556     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2557     EL_SP_GRAVITY_OFF_PORT_UP,
2558     EL_SP_GRAVITY_OFF_PORT_DOWN,
2559
2560     -1
2561   };
2562
2563   static int ep_passable_under[] =
2564   {
2565     -1
2566   };
2567
2568   static int ep_droppable[] =
2569   {
2570     -1
2571   };
2572
2573   static int ep_explodes_1x1_old[] =
2574   {
2575     -1
2576   };
2577
2578   static int ep_pushable[] =
2579   {
2580     EL_ROCK,
2581     EL_BOMB,
2582     EL_DX_SUPABOMB,
2583     EL_NUT,
2584     EL_TIME_ORB_EMPTY,
2585     EL_SP_ZONK,
2586     EL_SP_DISK_ORANGE,
2587     EL_SPRING,
2588     EL_BD_ROCK,
2589     EL_SOKOBAN_OBJECT,
2590     EL_SOKOBAN_FIELD_FULL,
2591     EL_SATELLITE,
2592     EL_SP_DISK_YELLOW,
2593     EL_BALLOON,
2594     EL_EMC_ANDROID,
2595
2596     -1
2597   };
2598
2599   static int ep_explodes_cross_old[] =
2600   {
2601     -1
2602   };
2603
2604   static int ep_protected[] =
2605   {
2606     /* same elements as in 'ep_walkable_inside' */
2607     EL_TUBE_ANY,
2608     EL_TUBE_VERTICAL,
2609     EL_TUBE_HORIZONTAL,
2610     EL_TUBE_VERTICAL_LEFT,
2611     EL_TUBE_VERTICAL_RIGHT,
2612     EL_TUBE_HORIZONTAL_UP,
2613     EL_TUBE_HORIZONTAL_DOWN,
2614     EL_TUBE_LEFT_UP,
2615     EL_TUBE_LEFT_DOWN,
2616     EL_TUBE_RIGHT_UP,
2617     EL_TUBE_RIGHT_DOWN,
2618
2619     /* same elements as in 'ep_passable_over' */
2620     EL_EM_GATE_1,
2621     EL_EM_GATE_2,
2622     EL_EM_GATE_3,
2623     EL_EM_GATE_4,
2624     EL_EM_GATE_1_GRAY,
2625     EL_EM_GATE_2_GRAY,
2626     EL_EM_GATE_3_GRAY,
2627     EL_EM_GATE_4_GRAY,
2628     EL_EM_GATE_1_GRAY_ACTIVE,
2629     EL_EM_GATE_2_GRAY_ACTIVE,
2630     EL_EM_GATE_3_GRAY_ACTIVE,
2631     EL_EM_GATE_4_GRAY_ACTIVE,
2632     EL_EMC_GATE_5,
2633     EL_EMC_GATE_6,
2634     EL_EMC_GATE_7,
2635     EL_EMC_GATE_8,
2636     EL_EMC_GATE_5_GRAY,
2637     EL_EMC_GATE_6_GRAY,
2638     EL_EMC_GATE_7_GRAY,
2639     EL_EMC_GATE_8_GRAY,
2640     EL_EMC_GATE_5_GRAY_ACTIVE,
2641     EL_EMC_GATE_6_GRAY_ACTIVE,
2642     EL_EMC_GATE_7_GRAY_ACTIVE,
2643     EL_EMC_GATE_8_GRAY_ACTIVE,
2644     EL_SWITCHGATE_OPEN,
2645     EL_TIMEGATE_OPEN,
2646
2647     /* same elements as in 'ep_passable_inside' */
2648     EL_SP_PORT_LEFT,
2649     EL_SP_PORT_RIGHT,
2650     EL_SP_PORT_UP,
2651     EL_SP_PORT_DOWN,
2652     EL_SP_PORT_HORIZONTAL,
2653     EL_SP_PORT_VERTICAL,
2654     EL_SP_PORT_ANY,
2655     EL_SP_GRAVITY_PORT_LEFT,
2656     EL_SP_GRAVITY_PORT_RIGHT,
2657     EL_SP_GRAVITY_PORT_UP,
2658     EL_SP_GRAVITY_PORT_DOWN,
2659     EL_SP_GRAVITY_ON_PORT_LEFT,
2660     EL_SP_GRAVITY_ON_PORT_RIGHT,
2661     EL_SP_GRAVITY_ON_PORT_UP,
2662     EL_SP_GRAVITY_ON_PORT_DOWN,
2663     EL_SP_GRAVITY_OFF_PORT_LEFT,
2664     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2665     EL_SP_GRAVITY_OFF_PORT_UP,
2666     EL_SP_GRAVITY_OFF_PORT_DOWN,
2667
2668     -1
2669   };
2670
2671   static int ep_throwable[] =
2672   {
2673     -1
2674   };
2675
2676   static int ep_can_explode[] =
2677   {
2678     /* same elements as in 'ep_explodes_impact' */
2679     EL_BOMB,
2680     EL_SP_DISK_ORANGE,
2681     EL_DX_SUPABOMB,
2682
2683     /* same elements as in 'ep_explodes_smashed' */
2684     EL_SATELLITE,
2685     EL_PIG,
2686     EL_DRAGON,
2687     EL_MOLE,
2688
2689     /* elements that can explode by explosion or by dragonfire */
2690     EL_DYNAMITE,
2691     EL_DYNAMITE_ACTIVE,
2692     EL_EM_DYNAMITE,
2693     EL_EM_DYNAMITE_ACTIVE,
2694     EL_DYNABOMB_PLAYER_1_ACTIVE,
2695     EL_DYNABOMB_PLAYER_2_ACTIVE,
2696     EL_DYNABOMB_PLAYER_3_ACTIVE,
2697     EL_DYNABOMB_PLAYER_4_ACTIVE,
2698     EL_DYNABOMB_INCREASE_NUMBER,
2699     EL_DYNABOMB_INCREASE_SIZE,
2700     EL_DYNABOMB_INCREASE_POWER,
2701     EL_SP_DISK_RED_ACTIVE,
2702     EL_BUG,
2703     EL_PENGUIN,
2704     EL_SP_DISK_RED,
2705     EL_SP_DISK_YELLOW,
2706     EL_SP_SNIKSNAK,
2707     EL_SP_ELECTRON,
2708
2709     /* elements that can explode only by explosion */
2710     EL_BLACK_ORB,
2711
2712     -1
2713   };
2714
2715   static int ep_gravity_reachable[] =
2716   {
2717     EL_SAND,
2718     EL_SP_BASE,
2719     EL_TRAP,
2720     EL_INVISIBLE_SAND,
2721     EL_INVISIBLE_SAND_ACTIVE,
2722     EL_SP_PORT_LEFT,
2723     EL_SP_PORT_RIGHT,
2724     EL_SP_PORT_UP,
2725     EL_SP_PORT_DOWN,
2726     EL_SP_PORT_HORIZONTAL,
2727     EL_SP_PORT_VERTICAL,
2728     EL_SP_PORT_ANY,
2729     EL_SP_GRAVITY_PORT_LEFT,
2730     EL_SP_GRAVITY_PORT_RIGHT,
2731     EL_SP_GRAVITY_PORT_UP,
2732     EL_SP_GRAVITY_PORT_DOWN,
2733     EL_SP_GRAVITY_ON_PORT_LEFT,
2734     EL_SP_GRAVITY_ON_PORT_RIGHT,
2735     EL_SP_GRAVITY_ON_PORT_UP,
2736     EL_SP_GRAVITY_ON_PORT_DOWN,
2737     EL_SP_GRAVITY_OFF_PORT_LEFT,
2738     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2739     EL_SP_GRAVITY_OFF_PORT_UP,
2740     EL_SP_GRAVITY_OFF_PORT_DOWN,
2741     EL_EMC_GRASS,
2742
2743     -1
2744   };
2745
2746   static int ep_player[] =
2747   {
2748     EL_PLAYER_1,
2749     EL_PLAYER_2,
2750     EL_PLAYER_3,
2751     EL_PLAYER_4,
2752     EL_SP_MURPHY,
2753     EL_SOKOBAN_FIELD_PLAYER,
2754     EL_TRIGGER_PLAYER,
2755
2756     -1
2757   };
2758
2759   static int ep_can_pass_magic_wall[] =
2760   {
2761     EL_ROCK,
2762     EL_BD_ROCK,
2763     EL_EMERALD,
2764     EL_BD_DIAMOND,
2765     EL_EMERALD_YELLOW,
2766     EL_EMERALD_RED,
2767     EL_EMERALD_PURPLE,
2768     EL_DIAMOND,
2769
2770     -1
2771   };
2772
2773   static int ep_switchable[] =
2774   {
2775     EL_ROBOT_WHEEL,
2776     EL_SP_TERMINAL,
2777     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2778     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2779     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2780     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2781     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2782     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2783     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2784     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2785     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2786     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2787     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2788     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2789     EL_SWITCHGATE_SWITCH_UP,
2790     EL_SWITCHGATE_SWITCH_DOWN,
2791     EL_LIGHT_SWITCH,
2792     EL_LIGHT_SWITCH_ACTIVE,
2793     EL_TIMEGATE_SWITCH,
2794     EL_BALLOON_SWITCH_LEFT,
2795     EL_BALLOON_SWITCH_RIGHT,
2796     EL_BALLOON_SWITCH_UP,
2797     EL_BALLOON_SWITCH_DOWN,
2798     EL_BALLOON_SWITCH_ANY,
2799     EL_BALLOON_SWITCH_NONE,
2800     EL_LAMP,
2801     EL_TIME_ORB_FULL,
2802     EL_EMC_MAGIC_BALL_SWITCH,
2803     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2804
2805     -1
2806   };
2807
2808   static int ep_bd_element[] =
2809   {
2810     EL_EMPTY,
2811     EL_SAND,
2812     EL_WALL_SLIPPERY,
2813     EL_BD_WALL,
2814     EL_ROCK,
2815     EL_BD_ROCK,
2816     EL_BD_DIAMOND,
2817     EL_BD_MAGIC_WALL,
2818     EL_EXIT_CLOSED,
2819     EL_EXIT_OPEN,
2820     EL_STEELWALL,
2821     EL_PLAYER_1,
2822     EL_PLAYER_2,
2823     EL_PLAYER_3,
2824     EL_PLAYER_4,
2825     EL_BD_FIREFLY,
2826     EL_BD_FIREFLY_1,
2827     EL_BD_FIREFLY_2,
2828     EL_BD_FIREFLY_3,
2829     EL_BD_FIREFLY_4,
2830     EL_BD_BUTTERFLY,
2831     EL_BD_BUTTERFLY_1,
2832     EL_BD_BUTTERFLY_2,
2833     EL_BD_BUTTERFLY_3,
2834     EL_BD_BUTTERFLY_4,
2835     EL_BD_AMOEBA,
2836     EL_CHAR_QUESTION,
2837     EL_UNKNOWN,
2838
2839     -1
2840   };
2841
2842   static int ep_sp_element[] =
2843   {
2844     /* should always be valid */
2845     EL_EMPTY,
2846
2847     /* standard classic Supaplex elements */
2848     EL_SP_EMPTY,
2849     EL_SP_ZONK,
2850     EL_SP_BASE,
2851     EL_SP_MURPHY,
2852     EL_SP_INFOTRON,
2853     EL_SP_CHIP_SINGLE,
2854     EL_SP_HARDWARE_GRAY,
2855     EL_SP_EXIT_CLOSED,
2856     EL_SP_EXIT_OPEN,
2857     EL_SP_DISK_ORANGE,
2858     EL_SP_PORT_RIGHT,
2859     EL_SP_PORT_DOWN,
2860     EL_SP_PORT_LEFT,
2861     EL_SP_PORT_UP,
2862     EL_SP_GRAVITY_PORT_RIGHT,
2863     EL_SP_GRAVITY_PORT_DOWN,
2864     EL_SP_GRAVITY_PORT_LEFT,
2865     EL_SP_GRAVITY_PORT_UP,
2866     EL_SP_SNIKSNAK,
2867     EL_SP_DISK_YELLOW,
2868     EL_SP_TERMINAL,
2869     EL_SP_DISK_RED,
2870     EL_SP_PORT_VERTICAL,
2871     EL_SP_PORT_HORIZONTAL,
2872     EL_SP_PORT_ANY,
2873     EL_SP_ELECTRON,
2874     EL_SP_BUGGY_BASE,
2875     EL_SP_CHIP_LEFT,
2876     EL_SP_CHIP_RIGHT,
2877     EL_SP_HARDWARE_BASE_1,
2878     EL_SP_HARDWARE_GREEN,
2879     EL_SP_HARDWARE_BLUE,
2880     EL_SP_HARDWARE_RED,
2881     EL_SP_HARDWARE_YELLOW,
2882     EL_SP_HARDWARE_BASE_2,
2883     EL_SP_HARDWARE_BASE_3,
2884     EL_SP_HARDWARE_BASE_4,
2885     EL_SP_HARDWARE_BASE_5,
2886     EL_SP_HARDWARE_BASE_6,
2887     EL_SP_CHIP_TOP,
2888     EL_SP_CHIP_BOTTOM,
2889
2890     /* additional elements that appeared in newer Supaplex levels */
2891     EL_INVISIBLE_WALL,
2892
2893     /* additional gravity port elements (not switching, but setting gravity) */
2894     EL_SP_GRAVITY_ON_PORT_LEFT,
2895     EL_SP_GRAVITY_ON_PORT_RIGHT,
2896     EL_SP_GRAVITY_ON_PORT_UP,
2897     EL_SP_GRAVITY_ON_PORT_DOWN,
2898     EL_SP_GRAVITY_OFF_PORT_LEFT,
2899     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2900     EL_SP_GRAVITY_OFF_PORT_UP,
2901     EL_SP_GRAVITY_OFF_PORT_DOWN,
2902
2903     /* more than one Murphy in a level results in an inactive clone */
2904     EL_SP_MURPHY_CLONE,
2905
2906     /* runtime Supaplex elements */
2907     EL_SP_DISK_RED_ACTIVE,
2908     EL_SP_TERMINAL_ACTIVE,
2909     EL_SP_BUGGY_BASE_ACTIVATING,
2910     EL_SP_BUGGY_BASE_ACTIVE,
2911     EL_SP_EXIT_OPENING,
2912     EL_SP_EXIT_CLOSING,
2913
2914     -1
2915   };
2916
2917   static int ep_sb_element[] =
2918   {
2919     EL_EMPTY,
2920     EL_STEELWALL,
2921     EL_SOKOBAN_OBJECT,
2922     EL_SOKOBAN_FIELD_EMPTY,
2923     EL_SOKOBAN_FIELD_FULL,
2924     EL_SOKOBAN_FIELD_PLAYER,
2925     EL_PLAYER_1,
2926     EL_PLAYER_2,
2927     EL_PLAYER_3,
2928     EL_PLAYER_4,
2929     EL_INVISIBLE_STEELWALL,
2930
2931     -1
2932   };
2933
2934   static int ep_gem[] =
2935   {
2936     EL_BD_DIAMOND,
2937     EL_EMERALD,
2938     EL_EMERALD_YELLOW,
2939     EL_EMERALD_RED,
2940     EL_EMERALD_PURPLE,
2941     EL_DIAMOND,
2942
2943     -1
2944   };
2945
2946   static int ep_food_dark_yamyam[] =
2947   {
2948     EL_SAND,
2949     EL_BUG,
2950     EL_SPACESHIP,
2951     EL_BD_BUTTERFLY,
2952     EL_BD_FIREFLY,
2953     EL_YAMYAM,
2954     EL_ROBOT,
2955     EL_PACMAN,
2956     EL_AMOEBA_DROP,
2957     EL_AMOEBA_DEAD,
2958     EL_AMOEBA_WET,
2959     EL_AMOEBA_DRY,
2960     EL_AMOEBA_FULL,
2961     EL_BD_AMOEBA,
2962     EL_EMERALD,
2963     EL_BD_DIAMOND,
2964     EL_EMERALD_YELLOW,
2965     EL_EMERALD_RED,
2966     EL_EMERALD_PURPLE,
2967     EL_DIAMOND,
2968     EL_PEARL,
2969     EL_CRYSTAL,
2970
2971     -1
2972   };
2973
2974   static int ep_food_penguin[] =
2975   {
2976     EL_EMERALD,
2977     EL_BD_DIAMOND,
2978     EL_EMERALD_YELLOW,
2979     EL_EMERALD_RED,
2980     EL_EMERALD_PURPLE,
2981     EL_DIAMOND,
2982     EL_PEARL,
2983     EL_CRYSTAL,
2984
2985     -1
2986   };
2987
2988   static int ep_food_pig[] =
2989   {
2990     EL_EMERALD,
2991     EL_BD_DIAMOND,
2992     EL_EMERALD_YELLOW,
2993     EL_EMERALD_RED,
2994     EL_EMERALD_PURPLE,
2995     EL_DIAMOND,
2996
2997     -1
2998   };
2999
3000   static int ep_historic_wall[] =
3001   {
3002     EL_STEELWALL,
3003     EL_GATE_1,
3004     EL_GATE_2,
3005     EL_GATE_3,
3006     EL_GATE_4,
3007     EL_GATE_1_GRAY,
3008     EL_GATE_2_GRAY,
3009     EL_GATE_3_GRAY,
3010     EL_GATE_4_GRAY,
3011     EL_GATE_1_GRAY_ACTIVE,
3012     EL_GATE_2_GRAY_ACTIVE,
3013     EL_GATE_3_GRAY_ACTIVE,
3014     EL_GATE_4_GRAY_ACTIVE,
3015     EL_EM_GATE_1,
3016     EL_EM_GATE_2,
3017     EL_EM_GATE_3,
3018     EL_EM_GATE_4,
3019     EL_EM_GATE_1_GRAY,
3020     EL_EM_GATE_2_GRAY,
3021     EL_EM_GATE_3_GRAY,
3022     EL_EM_GATE_4_GRAY,
3023     EL_EM_GATE_1_GRAY_ACTIVE,
3024     EL_EM_GATE_2_GRAY_ACTIVE,
3025     EL_EM_GATE_3_GRAY_ACTIVE,
3026     EL_EM_GATE_4_GRAY_ACTIVE,
3027     EL_EXIT_CLOSED,
3028     EL_EXIT_OPENING,
3029     EL_EXIT_OPEN,
3030     EL_WALL,
3031     EL_WALL_SLIPPERY,
3032     EL_EXPANDABLE_WALL,
3033     EL_EXPANDABLE_WALL_HORIZONTAL,
3034     EL_EXPANDABLE_WALL_VERTICAL,
3035     EL_EXPANDABLE_WALL_ANY,
3036     EL_EXPANDABLE_WALL_GROWING,
3037     EL_BD_EXPANDABLE_WALL,
3038     EL_BD_WALL,
3039     EL_SP_CHIP_SINGLE,
3040     EL_SP_CHIP_LEFT,
3041     EL_SP_CHIP_RIGHT,
3042     EL_SP_CHIP_TOP,
3043     EL_SP_CHIP_BOTTOM,
3044     EL_SP_HARDWARE_GRAY,
3045     EL_SP_HARDWARE_GREEN,
3046     EL_SP_HARDWARE_BLUE,
3047     EL_SP_HARDWARE_RED,
3048     EL_SP_HARDWARE_YELLOW,
3049     EL_SP_HARDWARE_BASE_1,
3050     EL_SP_HARDWARE_BASE_2,
3051     EL_SP_HARDWARE_BASE_3,
3052     EL_SP_HARDWARE_BASE_4,
3053     EL_SP_HARDWARE_BASE_5,
3054     EL_SP_HARDWARE_BASE_6,
3055     EL_SP_TERMINAL,
3056     EL_SP_TERMINAL_ACTIVE,
3057     EL_SP_EXIT_CLOSED,
3058     EL_SP_EXIT_OPEN,
3059     EL_INVISIBLE_STEELWALL,
3060     EL_INVISIBLE_STEELWALL_ACTIVE,
3061     EL_INVISIBLE_WALL,
3062     EL_INVISIBLE_WALL_ACTIVE,
3063     EL_STEELWALL_SLIPPERY,
3064     EL_EMC_STEELWALL_1,
3065     EL_EMC_STEELWALL_2,
3066     EL_EMC_STEELWALL_3,
3067     EL_EMC_STEELWALL_4,
3068     EL_EMC_WALL_1,
3069     EL_EMC_WALL_2,
3070     EL_EMC_WALL_3,
3071     EL_EMC_WALL_4,
3072     EL_EMC_WALL_5,
3073     EL_EMC_WALL_6,
3074     EL_EMC_WALL_7,
3075     EL_EMC_WALL_8,
3076
3077     -1
3078   };
3079
3080   static int ep_historic_solid[] =
3081   {
3082     EL_WALL,
3083     EL_EXPANDABLE_WALL,
3084     EL_EXPANDABLE_WALL_HORIZONTAL,
3085     EL_EXPANDABLE_WALL_VERTICAL,
3086     EL_EXPANDABLE_WALL_ANY,
3087     EL_BD_EXPANDABLE_WALL,
3088     EL_BD_WALL,
3089     EL_WALL_SLIPPERY,
3090     EL_EXIT_CLOSED,
3091     EL_EXIT_OPENING,
3092     EL_EXIT_OPEN,
3093     EL_AMOEBA_DEAD,
3094     EL_AMOEBA_WET,
3095     EL_AMOEBA_DRY,
3096     EL_AMOEBA_FULL,
3097     EL_BD_AMOEBA,
3098     EL_QUICKSAND_EMPTY,
3099     EL_QUICKSAND_FULL,
3100     EL_QUICKSAND_FILLING,
3101     EL_QUICKSAND_EMPTYING,
3102     EL_MAGIC_WALL,
3103     EL_MAGIC_WALL_ACTIVE,
3104     EL_MAGIC_WALL_EMPTYING,
3105     EL_MAGIC_WALL_FILLING,
3106     EL_MAGIC_WALL_FULL,
3107     EL_MAGIC_WALL_DEAD,
3108     EL_BD_MAGIC_WALL,
3109     EL_BD_MAGIC_WALL_ACTIVE,
3110     EL_BD_MAGIC_WALL_EMPTYING,
3111     EL_BD_MAGIC_WALL_FULL,
3112     EL_BD_MAGIC_WALL_FILLING,
3113     EL_BD_MAGIC_WALL_DEAD,
3114     EL_GAME_OF_LIFE,
3115     EL_BIOMAZE,
3116     EL_SP_CHIP_SINGLE,
3117     EL_SP_CHIP_LEFT,
3118     EL_SP_CHIP_RIGHT,
3119     EL_SP_CHIP_TOP,
3120     EL_SP_CHIP_BOTTOM,
3121     EL_SP_TERMINAL,
3122     EL_SP_TERMINAL_ACTIVE,
3123     EL_SP_EXIT_CLOSED,
3124     EL_SP_EXIT_OPEN,
3125     EL_INVISIBLE_WALL,
3126     EL_INVISIBLE_WALL_ACTIVE,
3127     EL_SWITCHGATE_SWITCH_UP,
3128     EL_SWITCHGATE_SWITCH_DOWN,
3129     EL_TIMEGATE_SWITCH,
3130     EL_TIMEGATE_SWITCH_ACTIVE,
3131     EL_EMC_WALL_1,
3132     EL_EMC_WALL_2,
3133     EL_EMC_WALL_3,
3134     EL_EMC_WALL_4,
3135     EL_EMC_WALL_5,
3136     EL_EMC_WALL_6,
3137     EL_EMC_WALL_7,
3138     EL_EMC_WALL_8,
3139     EL_WALL_PEARL,
3140     EL_WALL_CRYSTAL,
3141
3142     /* the following elements are a direct copy of "indestructible" elements,
3143        except "EL_ACID", which is "indestructible", but not "solid"! */
3144 #if 0
3145     EL_ACID,
3146 #endif
3147     EL_STEELWALL,
3148     EL_ACID_POOL_TOPLEFT,
3149     EL_ACID_POOL_TOPRIGHT,
3150     EL_ACID_POOL_BOTTOMLEFT,
3151     EL_ACID_POOL_BOTTOM,
3152     EL_ACID_POOL_BOTTOMRIGHT,
3153     EL_SP_HARDWARE_GRAY,
3154     EL_SP_HARDWARE_GREEN,
3155     EL_SP_HARDWARE_BLUE,
3156     EL_SP_HARDWARE_RED,
3157     EL_SP_HARDWARE_YELLOW,
3158     EL_SP_HARDWARE_BASE_1,
3159     EL_SP_HARDWARE_BASE_2,
3160     EL_SP_HARDWARE_BASE_3,
3161     EL_SP_HARDWARE_BASE_4,
3162     EL_SP_HARDWARE_BASE_5,
3163     EL_SP_HARDWARE_BASE_6,
3164     EL_INVISIBLE_STEELWALL,
3165     EL_INVISIBLE_STEELWALL_ACTIVE,
3166     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3167     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3168     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3169     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3170     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3171     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3172     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3173     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3174     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3175     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3176     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3177     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3178     EL_LIGHT_SWITCH,
3179     EL_LIGHT_SWITCH_ACTIVE,
3180     EL_SIGN_EXCLAMATION,
3181     EL_SIGN_RADIOACTIVITY,
3182     EL_SIGN_STOP,
3183     EL_SIGN_WHEELCHAIR,
3184     EL_SIGN_PARKING,
3185     EL_SIGN_ONEWAY,
3186     EL_SIGN_HEART,
3187     EL_SIGN_TRIANGLE,
3188     EL_SIGN_ROUND,
3189     EL_SIGN_EXIT,
3190     EL_SIGN_YINYANG,
3191     EL_SIGN_OTHER,
3192     EL_STEELWALL_SLIPPERY,
3193     EL_EMC_STEELWALL_1,
3194     EL_EMC_STEELWALL_2,
3195     EL_EMC_STEELWALL_3,
3196     EL_EMC_STEELWALL_4,
3197     EL_CRYSTAL,
3198     EL_GATE_1,
3199     EL_GATE_2,
3200     EL_GATE_3,
3201     EL_GATE_4,
3202     EL_GATE_1_GRAY,
3203     EL_GATE_2_GRAY,
3204     EL_GATE_3_GRAY,
3205     EL_GATE_4_GRAY,
3206     EL_GATE_1_GRAY_ACTIVE,
3207     EL_GATE_2_GRAY_ACTIVE,
3208     EL_GATE_3_GRAY_ACTIVE,
3209     EL_GATE_4_GRAY_ACTIVE,
3210     EL_EM_GATE_1,
3211     EL_EM_GATE_2,
3212     EL_EM_GATE_3,
3213     EL_EM_GATE_4,
3214     EL_EM_GATE_1_GRAY,
3215     EL_EM_GATE_2_GRAY,
3216     EL_EM_GATE_3_GRAY,
3217     EL_EM_GATE_4_GRAY,
3218     EL_EM_GATE_1_GRAY_ACTIVE,
3219     EL_EM_GATE_2_GRAY_ACTIVE,
3220     EL_EM_GATE_3_GRAY_ACTIVE,
3221     EL_EM_GATE_4_GRAY_ACTIVE,
3222     EL_SWITCHGATE_OPEN,
3223     EL_SWITCHGATE_OPENING,
3224     EL_SWITCHGATE_CLOSED,
3225     EL_SWITCHGATE_CLOSING,
3226     EL_TIMEGATE_OPEN,
3227     EL_TIMEGATE_OPENING,
3228     EL_TIMEGATE_CLOSED,
3229     EL_TIMEGATE_CLOSING,
3230     EL_TUBE_ANY,
3231     EL_TUBE_VERTICAL,
3232     EL_TUBE_HORIZONTAL,
3233     EL_TUBE_VERTICAL_LEFT,
3234     EL_TUBE_VERTICAL_RIGHT,
3235     EL_TUBE_HORIZONTAL_UP,
3236     EL_TUBE_HORIZONTAL_DOWN,
3237     EL_TUBE_LEFT_UP,
3238     EL_TUBE_LEFT_DOWN,
3239     EL_TUBE_RIGHT_UP,
3240     EL_TUBE_RIGHT_DOWN,
3241
3242     -1
3243   };
3244
3245   static int ep_classic_enemy[] =
3246   {
3247     EL_BUG,
3248     EL_SPACESHIP,
3249     EL_BD_BUTTERFLY,
3250     EL_BD_FIREFLY,
3251
3252     EL_YAMYAM,
3253     EL_DARK_YAMYAM,
3254     EL_ROBOT,
3255     EL_PACMAN,
3256     EL_SP_SNIKSNAK,
3257     EL_SP_ELECTRON,
3258
3259     -1
3260   };
3261
3262   static int ep_belt[] =
3263   {
3264     EL_CONVEYOR_BELT_1_LEFT,
3265     EL_CONVEYOR_BELT_1_MIDDLE,
3266     EL_CONVEYOR_BELT_1_RIGHT,
3267     EL_CONVEYOR_BELT_2_LEFT,
3268     EL_CONVEYOR_BELT_2_MIDDLE,
3269     EL_CONVEYOR_BELT_2_RIGHT,
3270     EL_CONVEYOR_BELT_3_LEFT,
3271     EL_CONVEYOR_BELT_3_MIDDLE,
3272     EL_CONVEYOR_BELT_3_RIGHT,
3273     EL_CONVEYOR_BELT_4_LEFT,
3274     EL_CONVEYOR_BELT_4_MIDDLE,
3275     EL_CONVEYOR_BELT_4_RIGHT,
3276
3277     -1
3278   };
3279
3280   static int ep_belt_active[] =
3281   {
3282     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3283     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3284     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3285     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3286     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3287     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3288     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3289     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3290     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3291     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3292     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3293     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3294
3295     -1
3296   };
3297
3298   static int ep_belt_switch[] =
3299   {
3300     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3301     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3302     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3303     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3304     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3305     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3306     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3307     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3308     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3309     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3310     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3311     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3312
3313     -1
3314   };
3315
3316   static int ep_tube[] =
3317   {
3318     EL_TUBE_LEFT_UP,
3319     EL_TUBE_LEFT_DOWN,
3320     EL_TUBE_RIGHT_UP,
3321     EL_TUBE_RIGHT_DOWN,
3322     EL_TUBE_HORIZONTAL,
3323     EL_TUBE_HORIZONTAL_UP,
3324     EL_TUBE_HORIZONTAL_DOWN,
3325     EL_TUBE_VERTICAL,
3326     EL_TUBE_VERTICAL_LEFT,
3327     EL_TUBE_VERTICAL_RIGHT,
3328     EL_TUBE_ANY,
3329
3330     -1
3331   };
3332
3333   static int ep_keygate[] =
3334   {
3335     EL_GATE_1,
3336     EL_GATE_2,
3337     EL_GATE_3,
3338     EL_GATE_4,
3339     EL_GATE_1_GRAY,
3340     EL_GATE_2_GRAY,
3341     EL_GATE_3_GRAY,
3342     EL_GATE_4_GRAY,
3343     EL_GATE_1_GRAY_ACTIVE,
3344     EL_GATE_2_GRAY_ACTIVE,
3345     EL_GATE_3_GRAY_ACTIVE,
3346     EL_GATE_4_GRAY_ACTIVE,
3347     EL_EM_GATE_1,
3348     EL_EM_GATE_2,
3349     EL_EM_GATE_3,
3350     EL_EM_GATE_4,
3351     EL_EM_GATE_1_GRAY,
3352     EL_EM_GATE_2_GRAY,
3353     EL_EM_GATE_3_GRAY,
3354     EL_EM_GATE_4_GRAY,
3355     EL_EM_GATE_1_GRAY_ACTIVE,
3356     EL_EM_GATE_2_GRAY_ACTIVE,
3357     EL_EM_GATE_3_GRAY_ACTIVE,
3358     EL_EM_GATE_4_GRAY_ACTIVE,
3359     EL_EMC_GATE_5,
3360     EL_EMC_GATE_6,
3361     EL_EMC_GATE_7,
3362     EL_EMC_GATE_8,
3363     EL_EMC_GATE_5_GRAY,
3364     EL_EMC_GATE_6_GRAY,
3365     EL_EMC_GATE_7_GRAY,
3366     EL_EMC_GATE_8_GRAY,
3367     EL_EMC_GATE_5_GRAY_ACTIVE,
3368     EL_EMC_GATE_6_GRAY_ACTIVE,
3369     EL_EMC_GATE_7_GRAY_ACTIVE,
3370     EL_EMC_GATE_8_GRAY_ACTIVE,
3371
3372     -1
3373   };
3374
3375   static int ep_amoeboid[] =
3376   {
3377     EL_AMOEBA_DEAD,
3378     EL_AMOEBA_WET,
3379     EL_AMOEBA_DRY,
3380     EL_AMOEBA_FULL,
3381     EL_BD_AMOEBA,
3382     EL_EMC_DRIPPER,
3383
3384     -1
3385   };
3386
3387   static int ep_amoebalive[] =
3388   {
3389     EL_AMOEBA_WET,
3390     EL_AMOEBA_DRY,
3391     EL_AMOEBA_FULL,
3392     EL_BD_AMOEBA,
3393     EL_EMC_DRIPPER,
3394
3395     -1
3396   };
3397
3398   static int ep_has_editor_content[] =
3399   {
3400     EL_PLAYER_1,
3401     EL_PLAYER_2,
3402     EL_PLAYER_3,
3403     EL_PLAYER_4,
3404     EL_SP_MURPHY,
3405     EL_YAMYAM,
3406     EL_YAMYAM_LEFT,
3407     EL_YAMYAM_RIGHT,
3408     EL_YAMYAM_UP,
3409     EL_YAMYAM_DOWN,
3410     EL_AMOEBA_WET,
3411     EL_AMOEBA_DRY,
3412     EL_AMOEBA_FULL,
3413     EL_BD_AMOEBA,
3414     EL_EMC_MAGIC_BALL,
3415     EL_EMC_ANDROID,
3416
3417     -1
3418   };
3419
3420   static int ep_can_turn_each_move[] =
3421   {
3422     /* !!! do something with this one !!! */
3423     -1
3424   };
3425
3426   static int ep_can_grow[] =
3427   {
3428     EL_BD_AMOEBA,
3429     EL_AMOEBA_DROP,
3430     EL_AMOEBA_WET,
3431     EL_AMOEBA_DRY,
3432     EL_AMOEBA_FULL,
3433     EL_GAME_OF_LIFE,
3434     EL_BIOMAZE,
3435     EL_EMC_DRIPPER,
3436
3437     -1
3438   };
3439
3440   static int ep_active_bomb[] =
3441   {
3442     EL_DYNAMITE_ACTIVE,
3443     EL_EM_DYNAMITE_ACTIVE,
3444     EL_DYNABOMB_PLAYER_1_ACTIVE,
3445     EL_DYNABOMB_PLAYER_2_ACTIVE,
3446     EL_DYNABOMB_PLAYER_3_ACTIVE,
3447     EL_DYNABOMB_PLAYER_4_ACTIVE,
3448     EL_SP_DISK_RED_ACTIVE,
3449
3450     -1
3451   };
3452
3453   static int ep_inactive[] =
3454   {
3455     EL_EMPTY,
3456     EL_SAND,
3457     EL_WALL,
3458     EL_BD_WALL,
3459     EL_WALL_SLIPPERY,
3460     EL_STEELWALL,
3461     EL_AMOEBA_DEAD,
3462     EL_QUICKSAND_EMPTY,
3463     EL_STONEBLOCK,
3464     EL_ROBOT_WHEEL,
3465     EL_KEY_1,
3466     EL_KEY_2,
3467     EL_KEY_3,
3468     EL_KEY_4,
3469     EL_EM_KEY_1,
3470     EL_EM_KEY_2,
3471     EL_EM_KEY_3,
3472     EL_EM_KEY_4,
3473     EL_EMC_KEY_5,
3474     EL_EMC_KEY_6,
3475     EL_EMC_KEY_7,
3476     EL_EMC_KEY_8,
3477     EL_GATE_1,
3478     EL_GATE_2,
3479     EL_GATE_3,
3480     EL_GATE_4,
3481     EL_GATE_1_GRAY,
3482     EL_GATE_2_GRAY,
3483     EL_GATE_3_GRAY,
3484     EL_GATE_4_GRAY,
3485     EL_GATE_1_GRAY_ACTIVE,
3486     EL_GATE_2_GRAY_ACTIVE,
3487     EL_GATE_3_GRAY_ACTIVE,
3488     EL_GATE_4_GRAY_ACTIVE,
3489     EL_EM_GATE_1,
3490     EL_EM_GATE_2,
3491     EL_EM_GATE_3,
3492     EL_EM_GATE_4,
3493     EL_EM_GATE_1_GRAY,
3494     EL_EM_GATE_2_GRAY,
3495     EL_EM_GATE_3_GRAY,
3496     EL_EM_GATE_4_GRAY,
3497     EL_EM_GATE_1_GRAY_ACTIVE,
3498     EL_EM_GATE_2_GRAY_ACTIVE,
3499     EL_EM_GATE_3_GRAY_ACTIVE,
3500     EL_EM_GATE_4_GRAY_ACTIVE,
3501     EL_EMC_GATE_5,
3502     EL_EMC_GATE_6,
3503     EL_EMC_GATE_7,
3504     EL_EMC_GATE_8,
3505     EL_EMC_GATE_5_GRAY,
3506     EL_EMC_GATE_6_GRAY,
3507     EL_EMC_GATE_7_GRAY,
3508     EL_EMC_GATE_8_GRAY,
3509     EL_EMC_GATE_5_GRAY_ACTIVE,
3510     EL_EMC_GATE_6_GRAY_ACTIVE,
3511     EL_EMC_GATE_7_GRAY_ACTIVE,
3512     EL_EMC_GATE_8_GRAY_ACTIVE,
3513     EL_DYNAMITE,
3514     EL_EM_DYNAMITE,
3515     EL_INVISIBLE_STEELWALL,
3516     EL_INVISIBLE_WALL,
3517     EL_INVISIBLE_SAND,
3518     EL_LAMP,
3519     EL_LAMP_ACTIVE,
3520     EL_WALL_EMERALD,
3521     EL_WALL_DIAMOND,
3522     EL_WALL_BD_DIAMOND,
3523     EL_WALL_EMERALD_YELLOW,
3524     EL_DYNABOMB_INCREASE_NUMBER,
3525     EL_DYNABOMB_INCREASE_SIZE,
3526     EL_DYNABOMB_INCREASE_POWER,
3527 #if 0
3528     EL_SOKOBAN_OBJECT,
3529 #endif
3530     EL_SOKOBAN_FIELD_EMPTY,
3531     EL_SOKOBAN_FIELD_FULL,
3532     EL_WALL_EMERALD_RED,
3533     EL_WALL_EMERALD_PURPLE,
3534     EL_ACID_POOL_TOPLEFT,
3535     EL_ACID_POOL_TOPRIGHT,
3536     EL_ACID_POOL_BOTTOMLEFT,
3537     EL_ACID_POOL_BOTTOM,
3538     EL_ACID_POOL_BOTTOMRIGHT,
3539     EL_MAGIC_WALL,
3540     EL_MAGIC_WALL_DEAD,
3541     EL_BD_MAGIC_WALL,
3542     EL_BD_MAGIC_WALL_DEAD,
3543     EL_AMOEBA_TO_DIAMOND,
3544     EL_BLOCKED,
3545     EL_SP_EMPTY,
3546     EL_SP_BASE,
3547     EL_SP_PORT_RIGHT,
3548     EL_SP_PORT_DOWN,
3549     EL_SP_PORT_LEFT,
3550     EL_SP_PORT_UP,
3551     EL_SP_GRAVITY_PORT_RIGHT,
3552     EL_SP_GRAVITY_PORT_DOWN,
3553     EL_SP_GRAVITY_PORT_LEFT,
3554     EL_SP_GRAVITY_PORT_UP,
3555     EL_SP_PORT_HORIZONTAL,
3556     EL_SP_PORT_VERTICAL,
3557     EL_SP_PORT_ANY,
3558     EL_SP_DISK_RED,
3559 #if 0
3560     EL_SP_DISK_YELLOW,
3561 #endif
3562     EL_SP_CHIP_SINGLE,
3563     EL_SP_CHIP_LEFT,
3564     EL_SP_CHIP_RIGHT,
3565     EL_SP_CHIP_TOP,
3566     EL_SP_CHIP_BOTTOM,
3567     EL_SP_HARDWARE_GRAY,
3568     EL_SP_HARDWARE_GREEN,
3569     EL_SP_HARDWARE_BLUE,
3570     EL_SP_HARDWARE_RED,
3571     EL_SP_HARDWARE_YELLOW,
3572     EL_SP_HARDWARE_BASE_1,
3573     EL_SP_HARDWARE_BASE_2,
3574     EL_SP_HARDWARE_BASE_3,
3575     EL_SP_HARDWARE_BASE_4,
3576     EL_SP_HARDWARE_BASE_5,
3577     EL_SP_HARDWARE_BASE_6,
3578     EL_SP_GRAVITY_ON_PORT_LEFT,
3579     EL_SP_GRAVITY_ON_PORT_RIGHT,
3580     EL_SP_GRAVITY_ON_PORT_UP,
3581     EL_SP_GRAVITY_ON_PORT_DOWN,
3582     EL_SP_GRAVITY_OFF_PORT_LEFT,
3583     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3584     EL_SP_GRAVITY_OFF_PORT_UP,
3585     EL_SP_GRAVITY_OFF_PORT_DOWN,
3586     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3587     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3588     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3589     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3590     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3591     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3592     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3593     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3594     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3595     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3596     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3597     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3598     EL_SIGN_EXCLAMATION,
3599     EL_SIGN_RADIOACTIVITY,
3600     EL_SIGN_STOP,
3601     EL_SIGN_WHEELCHAIR,
3602     EL_SIGN_PARKING,
3603     EL_SIGN_ONEWAY,
3604     EL_SIGN_HEART,
3605     EL_SIGN_TRIANGLE,
3606     EL_SIGN_ROUND,
3607     EL_SIGN_EXIT,
3608     EL_SIGN_YINYANG,
3609     EL_SIGN_OTHER,
3610     EL_STEELWALL_SLIPPERY,
3611     EL_EMC_STEELWALL_1,
3612     EL_EMC_STEELWALL_2,
3613     EL_EMC_STEELWALL_3,
3614     EL_EMC_STEELWALL_4,
3615     EL_EMC_WALL_SLIPPERY_1,
3616     EL_EMC_WALL_SLIPPERY_2,
3617     EL_EMC_WALL_SLIPPERY_3,
3618     EL_EMC_WALL_SLIPPERY_4,
3619     EL_EMC_WALL_1,
3620     EL_EMC_WALL_2,
3621     EL_EMC_WALL_3,
3622     EL_EMC_WALL_4,
3623     EL_EMC_WALL_5,
3624     EL_EMC_WALL_6,
3625     EL_EMC_WALL_7,
3626     EL_EMC_WALL_8,
3627     EL_EMC_WALL_9,
3628     EL_EMC_WALL_10,
3629     EL_EMC_WALL_11,
3630     EL_EMC_WALL_12,
3631     EL_EMC_WALL_13,
3632     EL_EMC_WALL_14,
3633     EL_EMC_WALL_15,
3634     EL_EMC_WALL_16,
3635
3636     -1
3637   };
3638
3639   static int ep_em_slippery_wall[] =
3640   {
3641     -1
3642   };
3643
3644   static int ep_gfx_crumbled[] =
3645   {
3646     EL_SAND,
3647     EL_LANDMINE,
3648     EL_TRAP,
3649     EL_TRAP_ACTIVE,
3650
3651     -1
3652   };
3653
3654   static int ep_editor_cascade_active[] =
3655   {
3656     EL_INTERNAL_CASCADE_BD_ACTIVE,
3657     EL_INTERNAL_CASCADE_EM_ACTIVE,
3658     EL_INTERNAL_CASCADE_EMC_ACTIVE,
3659     EL_INTERNAL_CASCADE_RND_ACTIVE,
3660     EL_INTERNAL_CASCADE_SB_ACTIVE,
3661     EL_INTERNAL_CASCADE_SP_ACTIVE,
3662     EL_INTERNAL_CASCADE_DC_ACTIVE,
3663     EL_INTERNAL_CASCADE_DX_ACTIVE,
3664     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3665     EL_INTERNAL_CASCADE_CE_ACTIVE,
3666     EL_INTERNAL_CASCADE_GE_ACTIVE,
3667     EL_INTERNAL_CASCADE_REF_ACTIVE,
3668     EL_INTERNAL_CASCADE_USER_ACTIVE,
3669     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3670
3671     -1
3672   };
3673
3674   static int ep_editor_cascade_inactive[] =
3675   {
3676     EL_INTERNAL_CASCADE_BD,
3677     EL_INTERNAL_CASCADE_EM,
3678     EL_INTERNAL_CASCADE_EMC,
3679     EL_INTERNAL_CASCADE_RND,
3680     EL_INTERNAL_CASCADE_SB,
3681     EL_INTERNAL_CASCADE_SP,
3682     EL_INTERNAL_CASCADE_DC,
3683     EL_INTERNAL_CASCADE_DX,
3684     EL_INTERNAL_CASCADE_CHARS,
3685     EL_INTERNAL_CASCADE_CE,
3686     EL_INTERNAL_CASCADE_GE,
3687     EL_INTERNAL_CASCADE_REF,
3688     EL_INTERNAL_CASCADE_USER,
3689     EL_INTERNAL_CASCADE_DYNAMIC,
3690
3691     -1
3692   };
3693
3694   static int ep_obsolete[] =
3695   {
3696     EL_PLAYER_OBSOLETE,
3697     EL_KEY_OBSOLETE,
3698     EL_EM_KEY_1_FILE_OBSOLETE,
3699     EL_EM_KEY_2_FILE_OBSOLETE,
3700     EL_EM_KEY_3_FILE_OBSOLETE,
3701     EL_EM_KEY_4_FILE_OBSOLETE,
3702     EL_ENVELOPE_OBSOLETE,
3703
3704     -1
3705   };
3706
3707   static struct
3708   {
3709     int *elements;
3710     int property;
3711   } element_properties[] =
3712   {
3713     { ep_diggable,                      EP_DIGGABLE                     },
3714     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
3715     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
3716     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
3717     { ep_dont_touch,                    EP_DONT_TOUCH                   },
3718     { ep_indestructible,                EP_INDESTRUCTIBLE               },
3719     { ep_slippery,                      EP_SLIPPERY                     },
3720     { ep_can_change,                    EP_CAN_CHANGE                   },
3721     { ep_can_move,                      EP_CAN_MOVE                     },
3722     { ep_can_fall,                      EP_CAN_FALL                     },
3723     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
3724     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
3725     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
3726     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
3727     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
3728     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
3729     { ep_walkable_over,                 EP_WALKABLE_OVER                },
3730     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
3731     { ep_walkable_under,                EP_WALKABLE_UNDER               },
3732     { ep_passable_over,                 EP_PASSABLE_OVER                },
3733     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
3734     { ep_passable_under,                EP_PASSABLE_UNDER               },
3735     { ep_droppable,                     EP_DROPPABLE                    },
3736     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
3737     { ep_pushable,                      EP_PUSHABLE                     },
3738     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
3739     { ep_protected,                     EP_PROTECTED                    },
3740     { ep_throwable,                     EP_THROWABLE                    },
3741     { ep_can_explode,                   EP_CAN_EXPLODE                  },
3742     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
3743
3744     { ep_player,                        EP_PLAYER                       },
3745     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
3746     { ep_switchable,                    EP_SWITCHABLE                   },
3747     { ep_bd_element,                    EP_BD_ELEMENT                   },
3748     { ep_sp_element,                    EP_SP_ELEMENT                   },
3749     { ep_sb_element,                    EP_SB_ELEMENT                   },
3750     { ep_gem,                           EP_GEM                          },
3751     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
3752     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
3753     { ep_food_pig,                      EP_FOOD_PIG                     },
3754     { ep_historic_wall,                 EP_HISTORIC_WALL                },
3755     { ep_historic_solid,                EP_HISTORIC_SOLID               },
3756     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
3757     { ep_belt,                          EP_BELT                         },
3758     { ep_belt_active,                   EP_BELT_ACTIVE                  },
3759     { ep_belt_switch,                   EP_BELT_SWITCH                  },
3760     { ep_tube,                          EP_TUBE                         },
3761     { ep_keygate,                       EP_KEYGATE                      },
3762     { ep_amoeboid,                      EP_AMOEBOID                     },
3763     { ep_amoebalive,                    EP_AMOEBALIVE                   },
3764     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
3765     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
3766     { ep_can_grow,                      EP_CAN_GROW                     },
3767     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
3768     { ep_inactive,                      EP_INACTIVE                     },
3769
3770     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
3771
3772     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
3773
3774     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
3775     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
3776
3777     { ep_obsolete,                      EP_OBSOLETE                     },
3778
3779     { NULL,                             -1                              }
3780   };
3781
3782   int i, j, k;
3783
3784   /* always start with reliable default values (element has no properties) */
3785   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3786     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3787       SET_PROPERTY(i, j, FALSE);
3788
3789   /* set all base element properties from above array definitions */
3790   for (i = 0; element_properties[i].elements != NULL; i++)
3791     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3792       SET_PROPERTY((element_properties[i].elements)[j],
3793                    element_properties[i].property, TRUE);
3794
3795   /* copy properties to some elements that are only stored in level file */
3796   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3797     for (j = 0; copy_properties[j][0] != -1; j++)
3798       if (HAS_PROPERTY(copy_properties[j][0], i))
3799         for (k = 1; k <= 4; k++)
3800           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3801 }
3802
3803 void InitElementPropertiesEngine(int engine_version)
3804 {
3805   static int no_wall_properties[] =
3806   {
3807     EP_DIGGABLE,
3808     EP_COLLECTIBLE_ONLY,
3809     EP_DONT_RUN_INTO,
3810     EP_DONT_COLLIDE_WITH,
3811     EP_CAN_MOVE,
3812     EP_CAN_FALL,
3813     EP_CAN_SMASH_PLAYER,
3814     EP_CAN_SMASH_ENEMIES,
3815     EP_CAN_SMASH_EVERYTHING,
3816     EP_PUSHABLE,
3817
3818     EP_PLAYER,
3819     EP_GEM,
3820     EP_FOOD_DARK_YAMYAM,
3821     EP_FOOD_PENGUIN,
3822     EP_BELT,
3823     EP_BELT_ACTIVE,
3824     EP_TUBE,
3825     EP_AMOEBOID,
3826     EP_AMOEBALIVE,
3827     EP_ACTIVE_BOMB,
3828
3829     EP_ACCESSIBLE,
3830
3831     -1
3832   };
3833
3834   int i, j;
3835
3836   /* important: after initialization in InitElementPropertiesStatic(), the
3837      elements are not again initialized to a default value; therefore all
3838      changes have to make sure that they leave the element with a defined
3839      property (which means that conditional property changes must be set to
3840      a reliable default value before) */
3841
3842   /* ---------- recursively resolve group elements ------------------------- */
3843
3844   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3845     for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3846       element_info[i].in_group[j] = FALSE;
3847
3848   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3849     resolve_group_element(EL_GROUP_START + i, 0);
3850
3851   /* set all special, combined or engine dependent element properties */
3852   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3853   {
3854     /* ---------- INACTIVE ------------------------------------------------- */
3855     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3856
3857     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3858     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3859                                   IS_WALKABLE_INSIDE(i) ||
3860                                   IS_WALKABLE_UNDER(i)));
3861
3862     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3863                                   IS_PASSABLE_INSIDE(i) ||
3864                                   IS_PASSABLE_UNDER(i)));
3865
3866     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3867                                          IS_PASSABLE_OVER(i)));
3868
3869     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3870                                            IS_PASSABLE_INSIDE(i)));
3871
3872     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3873                                           IS_PASSABLE_UNDER(i)));
3874
3875     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3876                                     IS_PASSABLE(i)));
3877
3878     /* ---------- COLLECTIBLE ---------------------------------------------- */
3879     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3880                                      IS_DROPPABLE(i) ||
3881                                      IS_THROWABLE(i)));
3882
3883     /* ---------- SNAPPABLE ------------------------------------------------ */
3884     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3885                                    IS_COLLECTIBLE(i) ||
3886                                    IS_SWITCHABLE(i) ||
3887                                    i == EL_BD_ROCK));
3888
3889     /* ---------- WALL ----------------------------------------------------- */
3890     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3891
3892     for (j = 0; no_wall_properties[j] != -1; j++)
3893       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3894           i >= EL_FIRST_RUNTIME_UNREAL)
3895         SET_PROPERTY(i, EP_WALL, FALSE);
3896
3897     if (IS_HISTORIC_WALL(i))
3898       SET_PROPERTY(i, EP_WALL, TRUE);
3899
3900     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3901     if (engine_version < VERSION_IDENT(2,2,0,0))
3902       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3903     else
3904       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3905                                              !IS_DIGGABLE(i) &&
3906                                              !IS_COLLECTIBLE(i)));
3907
3908     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3909
3910     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3911       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3912     else
3913       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3914                                             IS_INDESTRUCTIBLE(i)));
3915
3916     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3917     if (i == EL_FLAMES)
3918       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3919     else if (engine_version < VERSION_IDENT(2,2,0,0))
3920       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3921     else
3922       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3923                                            (!IS_WALKABLE(i) ||
3924                                             IS_PROTECTED(i))));
3925
3926     if (IS_CUSTOM_ELEMENT(i))
3927     {
3928       /* these are additional properties which are initially false when set */
3929
3930       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3931       if (DONT_TOUCH(i))
3932         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3933       if (DONT_COLLIDE_WITH(i))
3934         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3935
3936       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3937       if (CAN_SMASH_EVERYTHING(i))
3938         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3939       if (CAN_SMASH_ENEMIES(i))
3940         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3941     }
3942
3943     /* ---------- CAN_SMASH ------------------------------------------------ */
3944     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3945                                    CAN_SMASH_ENEMIES(i) ||
3946                                    CAN_SMASH_EVERYTHING(i)));
3947
3948     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3949     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3950                                              EXPLODES_BY_FIRE(i)));
3951
3952     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3953     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3954                                              EXPLODES_SMASHED(i)));
3955
3956     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3957     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3958                                             EXPLODES_IMPACT(i)));
3959
3960     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3961     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3962
3963     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3964     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3965                                                   i == EL_BLACK_ORB));
3966
3967     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3968     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3969                                               CAN_MOVE(i) ||
3970                                               IS_CUSTOM_ELEMENT(i)));
3971
3972     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3973     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3974                                                  i == EL_SP_ELECTRON));
3975
3976     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3977     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3978       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3979                    getMoveIntoAcidProperty(&level, i));
3980
3981     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3982     if (MAYBE_DONT_COLLIDE_WITH(i))
3983       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3984                    getDontCollideWithProperty(&level, i));
3985
3986     /* ---------- SP_PORT -------------------------------------------------- */
3987     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3988                                  IS_PASSABLE_INSIDE(i)));
3989
3990     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3991     for (j = 0; j < level.num_android_clone_elements; j++)
3992       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3993                    (i != EL_EMPTY &&
3994                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3995
3996     /* ---------- CAN_CHANGE ----------------------------------------------- */
3997     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3998     for (j = 0; j < element_info[i].num_change_pages; j++)
3999       if (element_info[i].change_page[j].can_change)
4000         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4001
4002     /* ---------- HAS_ACTION ----------------------------------------------- */
4003     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4004     for (j = 0; j < element_info[i].num_change_pages; j++)
4005       if (element_info[i].change_page[j].has_action)
4006         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4007
4008     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4009     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4010                                                   HAS_ACTION(i)));
4011
4012     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4013 #if 1
4014     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4015                  element_info[i].crumbled[ACTION_DEFAULT] !=
4016                  element_info[i].graphic[ACTION_DEFAULT]);
4017 #else
4018     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
4019     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4020                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
4021 #endif
4022
4023     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4024     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4025                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4026   }
4027
4028   /* dynamically adjust element properties according to game engine version */
4029   {
4030     static int ep_em_slippery_wall[] =
4031     {
4032       EL_STEELWALL,
4033       EL_WALL,
4034       EL_EXPANDABLE_WALL,
4035       EL_EXPANDABLE_WALL_HORIZONTAL,
4036       EL_EXPANDABLE_WALL_VERTICAL,
4037       EL_EXPANDABLE_WALL_ANY,
4038       -1
4039     };
4040
4041     /* special EM style gems behaviour */
4042     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4043       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4044                    level.em_slippery_gems);
4045
4046     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4047     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4048                  (level.em_slippery_gems &&
4049                   engine_version > VERSION_IDENT(2,0,1,0)));
4050   }
4051
4052   /* this is needed because some graphics depend on element properties */
4053   if (game_status == GAME_MODE_PLAYING)
4054     InitElementGraphicInfo();
4055 }
4056
4057 void InitElementPropertiesAfterLoading(int engine_version)
4058 {
4059   int i;
4060
4061   /* set some other uninitialized values of custom elements in older levels */
4062   if (engine_version < VERSION_IDENT(3,1,0,0))
4063   {
4064     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4065     {
4066       int element = EL_CUSTOM_START + i;
4067
4068       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4069
4070       element_info[element].explosion_delay = 17;
4071       element_info[element].ignition_delay = 8;
4072     }
4073   }
4074 }
4075
4076 static void InitGlobal()
4077 {
4078   int i;
4079
4080   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4081   {
4082     /* check if element_name_info entry defined for each element in "main.h" */
4083     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4084       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4085
4086     element_info[i].token_name = element_name_info[i].token_name;
4087     element_info[i].class_name = element_name_info[i].class_name;
4088     element_info[i].editor_description=element_name_info[i].editor_description;
4089   }
4090
4091   global.autoplay_leveldir = NULL;
4092   global.convert_leveldir = NULL;
4093
4094   global.frames_per_second = 0;
4095   global.fps_slowdown = FALSE;
4096   global.fps_slowdown_factor = 1;
4097 }
4098
4099 void Execute_Command(char *command)
4100 {
4101   int i;
4102
4103   if (strEqual(command, "print graphicsinfo.conf"))
4104   {
4105     printf("# You can configure additional/alternative image files here.\n");
4106     printf("# (The entries below are default and therefore commented out.)\n");
4107     printf("\n");
4108     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4109     printf("\n");
4110     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4111     printf("\n");
4112
4113     for (i = 0; image_config[i].token != NULL; i++)
4114       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
4115                                               image_config[i].value));
4116
4117     exit(0);
4118   }
4119   else if (strEqual(command, "print soundsinfo.conf"))
4120   {
4121     printf("# You can configure additional/alternative sound files here.\n");
4122     printf("# (The entries below are default and therefore commented out.)\n");
4123     printf("\n");
4124     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4125     printf("\n");
4126     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4127     printf("\n");
4128
4129     for (i = 0; sound_config[i].token != NULL; i++)
4130       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4131                                               sound_config[i].value));
4132
4133     exit(0);
4134   }
4135   else if (strEqual(command, "print musicinfo.conf"))
4136   {
4137     printf("# You can configure additional/alternative music files here.\n");
4138     printf("# (The entries below are default and therefore commented out.)\n");
4139     printf("\n");
4140     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4141     printf("\n");
4142     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4143     printf("\n");
4144
4145     for (i = 0; music_config[i].token != NULL; i++)
4146       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4147                                               music_config[i].value));
4148
4149     exit(0);
4150   }
4151   else if (strEqual(command, "print editorsetup.conf"))
4152   {
4153     printf("# You can configure your personal editor element list here.\n");
4154     printf("# (The entries below are default and therefore commented out.)\n");
4155     printf("\n");
4156
4157     /* this is needed to be able to check element list for cascade elements */
4158     InitElementPropertiesStatic();
4159     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4160
4161     PrintEditorElementList();
4162
4163     exit(0);
4164   }
4165   else if (strEqual(command, "print helpanim.conf"))
4166   {
4167     printf("# You can configure different element help animations here.\n");
4168     printf("# (The entries below are default and therefore commented out.)\n");
4169     printf("\n");
4170
4171     for (i = 0; helpanim_config[i].token != NULL; i++)
4172     {
4173       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4174                                               helpanim_config[i].value));
4175
4176       if (strEqual(helpanim_config[i].token, "end"))
4177         printf("#\n");
4178     }
4179
4180     exit(0);
4181   }
4182   else if (strEqual(command, "print helptext.conf"))
4183   {
4184     printf("# You can configure different element help text here.\n");
4185     printf("# (The entries below are default and therefore commented out.)\n");
4186     printf("\n");
4187
4188     for (i = 0; helptext_config[i].token != NULL; i++)
4189       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4190                                               helptext_config[i].value));
4191
4192     exit(0);
4193   }
4194   else if (strncmp(command, "dump level ", 11) == 0)
4195   {
4196     char *filename = &command[11];
4197
4198     if (!fileExists(filename))
4199       Error(ERR_EXIT, "cannot open file '%s'", filename);
4200
4201     LoadLevelFromFilename(&level, filename);
4202     DumpLevel(&level);
4203
4204     exit(0);
4205   }
4206   else if (strncmp(command, "dump tape ", 10) == 0)
4207   {
4208     char *filename = &command[10];
4209
4210     if (!fileExists(filename))
4211       Error(ERR_EXIT, "cannot open file '%s'", filename);
4212
4213     LoadTapeFromFilename(filename);
4214     DumpTape(&tape);
4215
4216     exit(0);
4217   }
4218   else if (strncmp(command, "autoplay ", 9) == 0)
4219   {
4220     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4221
4222     while (*str_ptr != '\0')                    /* continue parsing string */
4223     {
4224       /* cut leading whitespace from string, replace it by string terminator */
4225       while (*str_ptr == ' ' || *str_ptr == '\t')
4226         *str_ptr++ = '\0';
4227
4228       if (*str_ptr == '\0')                     /* end of string reached */
4229         break;
4230
4231       if (global.autoplay_leveldir == NULL)     /* read level set string */
4232       {
4233         global.autoplay_leveldir = str_ptr;
4234         global.autoplay_all = TRUE;             /* default: play all tapes */
4235
4236         for (i = 0; i < MAX_TAPES_PER_SET; i++)
4237           global.autoplay_level[i] = FALSE;
4238       }
4239       else                                      /* read level number string */
4240       {
4241         int level_nr = atoi(str_ptr);           /* get level_nr value */
4242
4243         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4244           global.autoplay_level[level_nr] = TRUE;
4245
4246         global.autoplay_all = FALSE;
4247       }
4248
4249       /* advance string pointer to the next whitespace (or end of string) */
4250       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4251         str_ptr++;
4252     }
4253   }
4254   else if (strncmp(command, "convert ", 8) == 0)
4255   {
4256     char *str_copy = getStringCopy(&command[8]);
4257     char *str_ptr = strchr(str_copy, ' ');
4258
4259     global.convert_leveldir = str_copy;
4260     global.convert_level_nr = -1;
4261
4262     if (str_ptr != NULL)                        /* level number follows */
4263     {
4264       *str_ptr++ = '\0';                        /* terminate leveldir string */
4265       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
4266     }
4267   }
4268
4269 #if DEBUG
4270 #if defined(TARGET_SDL)
4271   else if (strEqual(command, "SDL_ListModes"))
4272   {
4273     SDL_Rect **modes;
4274     int i;
4275
4276     SDL_Init(SDL_INIT_VIDEO);
4277
4278     /* get available fullscreen/hardware modes */
4279     modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
4280
4281     /* check if there are any modes available */
4282     if (modes == NULL)
4283     {
4284       printf("No modes available!\n");
4285
4286       exit(-1);
4287     }
4288
4289     /* check if our resolution is restricted */
4290     if (modes == (SDL_Rect **)-1)
4291     {
4292       printf("All resolutions available.\n");
4293     }
4294     else
4295     {
4296       printf("Available Modes:\n");
4297
4298       for(i = 0; modes[i]; i++)
4299         printf("  %d x %d\n", modes[i]->w, modes[i]->h);
4300     }
4301
4302     exit(0);
4303   }
4304 #endif
4305 #endif
4306
4307   else
4308   {
4309     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4310   }
4311 }
4312
4313 static void InitSetup()
4314 {
4315   LoadSetup();                                  /* global setup info */
4316
4317   /* set some options from setup file */
4318
4319   if (setup.options.verbose)
4320     options.verbose = TRUE;
4321 }
4322
4323 static void InitGameInfo()
4324 {
4325   game.restart_level = FALSE;
4326 }
4327
4328 static void InitPlayerInfo()
4329 {
4330   int i;
4331
4332   /* choose default local player */
4333   local_player = &stored_player[0];
4334
4335   for (i = 0; i < MAX_PLAYERS; i++)
4336     stored_player[i].connected = FALSE;
4337
4338   local_player->connected = TRUE;
4339 }
4340
4341 static void InitArtworkInfo()
4342 {
4343   LoadArtworkInfo();
4344 }
4345
4346 static char *get_string_in_brackets(char *string)
4347 {
4348   char *string_in_brackets = checked_malloc(strlen(string) + 3);
4349
4350   sprintf(string_in_brackets, "[%s]", string);
4351
4352   return string_in_brackets;
4353 }
4354
4355 static char *get_level_id_suffix(int id_nr)
4356 {
4357   char *id_suffix = checked_malloc(1 + 3 + 1);
4358
4359   if (id_nr < 0 || id_nr > 999)
4360     id_nr = 0;
4361
4362   sprintf(id_suffix, ".%03d", id_nr);
4363
4364   return id_suffix;
4365 }
4366
4367 #if 0
4368 static char *get_element_class_token(int element)
4369 {
4370   char *element_class_name = element_info[element].class_name;
4371   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4372
4373   sprintf(element_class_token, "[%s]", element_class_name);
4374
4375   return element_class_token;
4376 }
4377
4378 static char *get_action_class_token(int action)
4379 {
4380   char *action_class_name = &element_action_info[action].suffix[1];
4381   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4382
4383   sprintf(action_class_token, "[%s]", action_class_name);
4384
4385   return action_class_token;
4386 }
4387 #endif
4388
4389 static void InitArtworkConfig()
4390 {
4391   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4392   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4393   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4394   static char *action_id_suffix[NUM_ACTIONS + 1];
4395   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4396   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4397   static char *level_id_suffix[MAX_LEVELS + 1];
4398   static char *dummy[1] = { NULL };
4399   static char *ignore_generic_tokens[] =
4400   {
4401     "name",
4402     "sort_priority",
4403     NULL
4404   };
4405   static char **ignore_image_tokens;
4406   static char **ignore_sound_tokens;
4407   static char **ignore_music_tokens;
4408   int num_ignore_generic_tokens;
4409   int num_ignore_image_tokens;
4410   int num_ignore_sound_tokens;
4411   int num_ignore_music_tokens;
4412   int i;
4413
4414   /* dynamically determine list of generic tokens to be ignored */
4415   num_ignore_generic_tokens = 0;
4416   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4417     num_ignore_generic_tokens++;
4418
4419   /* dynamically determine list of image tokens to be ignored */
4420   num_ignore_image_tokens = num_ignore_generic_tokens;
4421   for (i = 0; image_config_vars[i].token != NULL; i++)
4422     num_ignore_image_tokens++;
4423   ignore_image_tokens =
4424     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4425   for (i = 0; i < num_ignore_generic_tokens; i++)
4426     ignore_image_tokens[i] = ignore_generic_tokens[i];
4427   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4428     ignore_image_tokens[num_ignore_generic_tokens + i] =
4429       image_config_vars[i].token;
4430   ignore_image_tokens[num_ignore_image_tokens] = NULL;
4431
4432   /* dynamically determine list of sound tokens to be ignored */
4433   num_ignore_sound_tokens = num_ignore_generic_tokens;
4434   ignore_sound_tokens =
4435     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4436   for (i = 0; i < num_ignore_generic_tokens; i++)
4437     ignore_sound_tokens[i] = ignore_generic_tokens[i];
4438   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4439
4440   /* dynamically determine list of music tokens to be ignored */
4441   num_ignore_music_tokens = num_ignore_generic_tokens;
4442   ignore_music_tokens =
4443     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4444   for (i = 0; i < num_ignore_generic_tokens; i++)
4445     ignore_music_tokens[i] = ignore_generic_tokens[i];
4446   ignore_music_tokens[num_ignore_music_tokens] = NULL;
4447
4448   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4449     image_id_prefix[i] = element_info[i].token_name;
4450   for (i = 0; i < NUM_FONTS; i++)
4451     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4452   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4453
4454   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4455     sound_id_prefix[i] = element_info[i].token_name;
4456   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4457     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4458       get_string_in_brackets(element_info[i].class_name);
4459   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4460
4461   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4462     music_id_prefix[i] = music_prefix_info[i].prefix;
4463   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4464
4465   for (i = 0; i < NUM_ACTIONS; i++)
4466     action_id_suffix[i] = element_action_info[i].suffix;
4467   action_id_suffix[NUM_ACTIONS] = NULL;
4468
4469   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4470     direction_id_suffix[i] = element_direction_info[i].suffix;
4471   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4472
4473   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4474     special_id_suffix[i] = special_suffix_info[i].suffix;
4475   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4476
4477   for (i = 0; i < MAX_LEVELS; i++)
4478     level_id_suffix[i] = get_level_id_suffix(i);
4479   level_id_suffix[MAX_LEVELS] = NULL;
4480
4481   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4482                 image_id_prefix, action_id_suffix, direction_id_suffix,
4483                 special_id_suffix, ignore_image_tokens);
4484   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4485                 sound_id_prefix, action_id_suffix, dummy,
4486                 special_id_suffix, ignore_sound_tokens);
4487   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4488                 music_id_prefix, special_id_suffix, level_id_suffix,
4489                 dummy, ignore_music_tokens);
4490 }
4491
4492 static void InitMixer()
4493 {
4494   OpenAudio();
4495   StartMixer();
4496 }
4497
4498 void InitGfx()
4499 {
4500   char *filename_font_initial = NULL;
4501   Bitmap *bitmap_font_initial = NULL;
4502   int font_height;
4503   int i, j;
4504
4505   /* determine settings for initial font (for displaying startup messages) */
4506   for (i = 0; image_config[i].token != NULL; i++)
4507   {
4508     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4509     {
4510       char font_token[128];
4511       int len_font_token;
4512
4513       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4514       len_font_token = strlen(font_token);
4515
4516       if (strEqual(image_config[i].token, font_token))
4517         filename_font_initial = image_config[i].value;
4518       else if (strlen(image_config[i].token) > len_font_token &&
4519                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4520       {
4521         if (strEqual(&image_config[i].token[len_font_token], ".x"))
4522           font_initial[j].src_x = atoi(image_config[i].value);
4523         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
4524           font_initial[j].src_y = atoi(image_config[i].value);
4525         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
4526           font_initial[j].width = atoi(image_config[i].value);
4527         else if (strEqual(&image_config[i].token[len_font_token],".height"))
4528           font_initial[j].height = atoi(image_config[i].value);
4529       }
4530     }
4531   }
4532
4533   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4534   {
4535     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4536     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4537   }
4538
4539   if (filename_font_initial == NULL)    /* should not happen */
4540     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4541
4542   /* create additional image buffers for double-buffering and cross-fading */
4543   bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
4544   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4545   bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
4546   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4547
4548   /* initialize screen properties */
4549   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4550                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4551                    bitmap_db_field);
4552   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4553   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4554   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4555
4556   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4557
4558   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4559     font_initial[j].bitmap = bitmap_font_initial;
4560
4561   InitFontGraphicInfo();
4562
4563   font_height = getFontHeight(FC_RED);
4564
4565   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4566   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4567   DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
4568
4569   DrawInitText("Loading graphics:", 120, FC_GREEN);
4570 }
4571
4572 void RedrawBackground()
4573 {
4574   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4575              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4576
4577   redraw_mask = REDRAW_ALL;
4578 }
4579
4580 void InitGfxBackground()
4581 {
4582   int x, y;
4583
4584   drawto = backbuffer;
4585   fieldbuffer = bitmap_db_field;
4586   SetDrawtoField(DRAW_BACKBUFFER);
4587
4588   RedrawBackground();
4589
4590   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4591   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4592
4593   for (x = 0; x < MAX_BUF_XSIZE; x++)
4594     for (y = 0; y < MAX_BUF_YSIZE; y++)
4595       redraw[x][y] = 0;
4596   redraw_tiles = 0;
4597   redraw_mask = REDRAW_ALL;
4598 }
4599
4600 static void InitLevelInfo()
4601 {
4602   LoadLevelInfo();                              /* global level info */
4603   LoadLevelSetup_LastSeries();                  /* last played series info */
4604   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4605 }
4606
4607 void InitLevelArtworkInfo()
4608 {
4609   LoadLevelArtworkInfo();
4610 }
4611
4612 static void InitImages()
4613 {
4614   setLevelArtworkDir(artwork.gfx_first);
4615
4616 #if 0
4617   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4618          leveldir_current->identifier,
4619          artwork.gfx_current_identifier,
4620          artwork.gfx_current->identifier,
4621          leveldir_current->graphics_set,
4622          leveldir_current->graphics_path);
4623 #endif
4624
4625   ReloadCustomImages();
4626
4627   LoadCustomElementDescriptions();
4628   LoadSpecialMenuDesignSettings();
4629
4630   ReinitializeGraphics();
4631 }
4632
4633 static void InitSound(char *identifier)
4634 {
4635   if (identifier == NULL)
4636     identifier = artwork.snd_current->identifier;
4637
4638   /* set artwork path to send it to the sound server process */
4639   setLevelArtworkDir(artwork.snd_first);
4640
4641   InitReloadCustomSounds(identifier);
4642   ReinitializeSounds();
4643 }
4644
4645 static void InitMusic(char *identifier)
4646 {
4647   if (identifier == NULL)
4648     identifier = artwork.mus_current->identifier;
4649
4650   /* set artwork path to send it to the sound server process */
4651   setLevelArtworkDir(artwork.mus_first);
4652
4653   InitReloadCustomMusic(identifier);
4654   ReinitializeMusic();
4655 }
4656
4657 void InitNetworkServer()
4658 {
4659 #if defined(NETWORK_AVALIABLE)
4660   int nr_wanted;
4661 #endif
4662
4663   if (!options.network)
4664     return;
4665
4666 #if defined(NETWORK_AVALIABLE)
4667   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4668
4669   if (!ConnectToServer(options.server_host, options.server_port))
4670     Error(ERR_EXIT, "cannot connect to network game server");
4671
4672   SendToServer_PlayerName(setup.player_name);
4673   SendToServer_ProtocolVersion();
4674
4675   if (nr_wanted)
4676     SendToServer_NrWanted(nr_wanted);
4677 #endif
4678 }
4679
4680 static char *getNewArtworkIdentifier(int type)
4681 {
4682   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4683   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4684   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4685   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4686   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4687   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4688   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4689   char *leveldir_identifier = leveldir_current->identifier;
4690 #if 1
4691   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4692   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4693 #else
4694   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4695 #endif
4696   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4697   char *artwork_current_identifier;
4698   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4699
4700   /* leveldir_current may be invalid (level group, parent link) */
4701   if (!validLevelSeries(leveldir_current))
4702     return NULL;
4703
4704   /* 1st step: determine artwork set to be activated in descending order:
4705      --------------------------------------------------------------------
4706      1. setup artwork (when configured to override everything else)
4707      2. artwork set configured in "levelinfo.conf" of current level set
4708         (artwork in level directory will have priority when loading later)
4709      3. artwork in level directory (stored in artwork sub-directory)
4710      4. setup artwork (currently configured in setup menu) */
4711
4712   if (setup_override_artwork)
4713     artwork_current_identifier = setup_artwork_set;
4714   else if (leveldir_artwork_set != NULL)
4715     artwork_current_identifier = leveldir_artwork_set;
4716   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4717     artwork_current_identifier = leveldir_identifier;
4718   else
4719     artwork_current_identifier = setup_artwork_set;
4720
4721
4722   /* 2nd step: check if it is really needed to reload artwork set
4723      ------------------------------------------------------------ */
4724
4725 #if 0
4726   if (type == ARTWORK_TYPE_GRAPHICS)
4727     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4728            artwork_new_identifier,
4729            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4730            artwork_current_identifier,
4731            leveldir_current->graphics_set,
4732            leveldir_current->identifier);
4733 #endif
4734
4735   /* ---------- reload if level set and also artwork set has changed ------- */
4736   if (leveldir_current_identifier[type] != leveldir_identifier &&
4737       (last_has_level_artwork_set[type] || has_level_artwork_set))
4738     artwork_new_identifier = artwork_current_identifier;
4739
4740   leveldir_current_identifier[type] = leveldir_identifier;
4741   last_has_level_artwork_set[type] = has_level_artwork_set;
4742
4743 #if 0
4744   if (type == ARTWORK_TYPE_GRAPHICS)
4745     printf("::: 1: '%s'\n", artwork_new_identifier);
4746 #endif
4747
4748   /* ---------- reload if "override artwork" setting has changed ----------- */
4749   if (last_override_level_artwork[type] != setup_override_artwork)
4750     artwork_new_identifier = artwork_current_identifier;
4751
4752   last_override_level_artwork[type] = setup_override_artwork;
4753
4754 #if 0
4755   if (type == ARTWORK_TYPE_GRAPHICS)
4756     printf("::: 2: '%s'\n", artwork_new_identifier);
4757 #endif
4758
4759   /* ---------- reload if current artwork identifier has changed ----------- */
4760   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4761                 artwork_current_identifier))
4762     artwork_new_identifier = artwork_current_identifier;
4763
4764   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4765
4766 #if 0
4767   if (type == ARTWORK_TYPE_GRAPHICS)
4768     printf("::: 3: '%s'\n", artwork_new_identifier);
4769 #endif
4770
4771   /* ---------- do not reload directly after starting ---------------------- */
4772   if (!initialized[type])
4773     artwork_new_identifier = NULL;
4774
4775   initialized[type] = TRUE;
4776
4777 #if 0
4778   if (type == ARTWORK_TYPE_GRAPHICS)
4779     printf("::: 4: '%s'\n", artwork_new_identifier);
4780 #endif
4781
4782 #if 0
4783   if (type == ARTWORK_TYPE_GRAPHICS)
4784     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4785            artwork.gfx_current_identifier, artwork_current_identifier,
4786            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4787            artwork_new_identifier);
4788 #endif
4789
4790   return artwork_new_identifier;
4791 }
4792
4793 void ReloadCustomArtwork(int force_reload)
4794 {
4795   char *gfx_new_identifier;
4796   char *snd_new_identifier;
4797   char *mus_new_identifier;
4798   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4799   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4800   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4801   boolean redraw_screen = FALSE;
4802
4803   force_reload_gfx |= AdjustGraphicsForEMC();
4804
4805   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4806   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4807   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4808
4809   if (gfx_new_identifier != NULL || force_reload_gfx)
4810   {
4811 #if 0
4812     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4813            artwork.gfx_current_identifier,
4814            gfx_new_identifier,
4815            artwork.gfx_current->identifier,
4816            leveldir_current->graphics_set);
4817 #endif
4818
4819     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4820
4821     InitImages();
4822
4823     redraw_screen = TRUE;
4824   }
4825
4826   if (snd_new_identifier != NULL || force_reload_snd)
4827   {
4828     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4829
4830     InitSound(snd_new_identifier);
4831
4832     redraw_screen = TRUE;
4833   }
4834
4835   if (mus_new_identifier != NULL || force_reload_mus)
4836   {
4837     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4838
4839     InitMusic(mus_new_identifier);
4840
4841     redraw_screen = TRUE;
4842   }
4843
4844   if (redraw_screen)
4845   {
4846     RedrawBackground();
4847
4848     /* force redraw of (open or closed) door graphics */
4849     SetDoorState(DOOR_OPEN_ALL);
4850     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4851   }
4852 }
4853
4854 void KeyboardAutoRepeatOffUnlessAutoplay()
4855 {
4856   if (global.autoplay_leveldir == NULL)
4857     KeyboardAutoRepeatOff();
4858 }
4859
4860
4861 /* ========================================================================= */
4862 /* OpenAll()                                                                 */
4863 /* ========================================================================= */
4864
4865 void OpenAll()
4866 {
4867   InitGlobal();                 /* initialize some global variables */
4868
4869   if (options.execute_command)
4870     Execute_Command(options.execute_command);
4871
4872   if (options.serveronly)
4873   {
4874 #if defined(PLATFORM_UNIX)
4875     NetworkServer(options.server_port, options.serveronly);
4876 #else
4877     Error(ERR_WARN, "networking only supported in Unix version");
4878 #endif
4879
4880     exit(0);                    /* never reached, server loops forever */
4881   }
4882
4883   InitSetup();
4884
4885   InitGameInfo();
4886   InitPlayerInfo();
4887   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4888   InitArtworkConfig();          /* needed before forking sound child process */
4889   InitMixer();
4890
4891   InitCounter();
4892
4893   InitRND(NEW_RANDOMIZE);
4894   InitSimpleRandom(NEW_RANDOMIZE);
4895
4896   InitJoysticks();
4897
4898   InitVideoDisplay();
4899   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4900                   setup.fullscreen);
4901
4902   InitEventFilter(FilterMouseMotionEvents);
4903
4904   InitElementPropertiesStatic();
4905   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4906
4907   InitGfx();
4908
4909   InitLevelInfo();
4910   InitLevelArtworkInfo();
4911
4912   InitImages();                 /* needs to know current level directory */
4913   InitSound(NULL);              /* needs to know current level directory */
4914   InitMusic(NULL);              /* needs to know current level directory */
4915
4916   InitGfxBackground();
4917
4918 #if 1
4919   em_open_all();
4920 #endif
4921
4922   if (global.autoplay_leveldir)
4923   {
4924     AutoPlayTape();
4925     return;
4926   }
4927   else if (global.convert_leveldir)
4928   {
4929     ConvertLevels();
4930     return;
4931   }
4932
4933   game_status = GAME_MODE_MAIN;
4934
4935   DrawMainMenu();
4936
4937   InitNetworkServer();
4938 }
4939
4940 void CloseAllAndExit(int exit_value)
4941 {
4942   StopSounds();
4943   FreeAllSounds();
4944   FreeAllMusic();
4945   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4946
4947 #if 1
4948   em_close_all();
4949 #endif
4950
4951   FreeAllImages();
4952
4953 #if defined(TARGET_SDL)
4954   if (network_server)   /* terminate network server */
4955     SDL_KillThread(server_thread);
4956 #endif
4957
4958   CloseVideoDisplay();
4959   ClosePlatformDependentStuff();
4960
4961   if (exit_value != 0)
4962     NotifyUserAboutErrorFile();
4963
4964   exit(exit_value);
4965 }