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