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