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