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