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