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