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