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