rnd-20060217-2-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_FULL; 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_FULL; 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_FULL; 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_FULL; 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_FULL; 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_FULL; 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_FULL; 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_FULL];
570     int default_direction_crumbled[NUM_DIRECTIONS_FULL];
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_FULL; 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_FULL; 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_FULL; 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 #if 1
1793 static void resolve_group_element(int group_element, int recursion_depth)
1794 {
1795   static int group_nr;
1796   static struct ElementGroupInfo *group;
1797   struct ElementGroupInfo *actual_group = element_info[group_element].group;
1798   int i;
1799
1800   if (actual_group == NULL)                     /* not yet initialized */
1801     return;
1802
1803   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
1804   {
1805     Error(ERR_WARN, "recursion too deep when resolving group element %d",
1806           group_element - EL_GROUP_START + 1);
1807
1808     /* replace element which caused too deep recursion by question mark */
1809     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
1810
1811     return;
1812   }
1813
1814   if (recursion_depth == 0)                     /* initialization */
1815   {
1816     group = actual_group;
1817     group_nr = group_element - EL_GROUP_START;
1818
1819     group->num_elements_resolved = 0;
1820     group->choice_pos = 0;
1821   }
1822
1823   for (i = 0; i < actual_group->num_elements; i++)
1824   {
1825     int element = actual_group->element[i];
1826
1827     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
1828       break;
1829
1830     if (IS_GROUP_ELEMENT(element))
1831       resolve_group_element(element, recursion_depth + 1);
1832     else
1833     {
1834       group->element_resolved[group->num_elements_resolved++] = element;
1835       element_info[element].in_group[group_nr] = TRUE;
1836     }
1837   }
1838 }
1839 #endif
1840
1841 void InitElementPropertiesStatic()
1842 {
1843   static int ep_diggable[] =
1844   {
1845     EL_SAND,
1846     EL_SP_BASE,
1847     EL_SP_BUGGY_BASE,
1848     EL_SP_BUGGY_BASE_ACTIVATING,
1849     EL_TRAP,
1850     EL_INVISIBLE_SAND,
1851     EL_INVISIBLE_SAND_ACTIVE,
1852     EL_EMC_GRASS,
1853
1854     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
1855     /* (if amoeba can grow into anything diggable, maybe keep these out) */
1856 #if 0
1857     EL_LANDMINE,
1858     EL_TRAP_ACTIVE,
1859     EL_SP_BUGGY_BASE_ACTIVE,
1860     EL_EMC_PLANT,
1861 #endif
1862
1863     -1
1864   };
1865
1866   static int ep_collectible_only[] =
1867   {
1868     EL_BD_DIAMOND,
1869     EL_EMERALD,
1870     EL_DIAMOND,
1871     EL_EMERALD_YELLOW,
1872     EL_EMERALD_RED,
1873     EL_EMERALD_PURPLE,
1874     EL_KEY_1,
1875     EL_KEY_2,
1876     EL_KEY_3,
1877     EL_KEY_4,
1878     EL_EM_KEY_1,
1879     EL_EM_KEY_2,
1880     EL_EM_KEY_3,
1881     EL_EM_KEY_4,
1882     EL_EMC_KEY_5,
1883     EL_EMC_KEY_6,
1884     EL_EMC_KEY_7,
1885     EL_EMC_KEY_8,
1886     EL_DYNAMITE,
1887     EL_EM_DYNAMITE,
1888     EL_DYNABOMB_INCREASE_NUMBER,
1889     EL_DYNABOMB_INCREASE_SIZE,
1890     EL_DYNABOMB_INCREASE_POWER,
1891     EL_SP_INFOTRON,
1892     EL_SP_DISK_RED,
1893     EL_PEARL,
1894     EL_CRYSTAL,
1895     EL_KEY_WHITE,
1896     EL_SHIELD_NORMAL,
1897     EL_SHIELD_DEADLY,
1898     EL_EXTRA_TIME,
1899     EL_ENVELOPE_1,
1900     EL_ENVELOPE_2,
1901     EL_ENVELOPE_3,
1902     EL_ENVELOPE_4,
1903     EL_SPEED_PILL,
1904     EL_EMC_LENSES,
1905     EL_EMC_MAGNIFIER,
1906
1907     -1
1908   };
1909
1910   static int ep_dont_run_into[] =
1911   {
1912     /* same elements as in 'ep_dont_touch' */
1913     EL_BUG,
1914     EL_SPACESHIP,
1915     EL_BD_BUTTERFLY,
1916     EL_BD_FIREFLY,
1917
1918     /* same elements as in 'ep_dont_collide_with' */
1919     EL_YAMYAM,
1920     EL_DARK_YAMYAM,
1921     EL_ROBOT,
1922     EL_PACMAN,
1923     EL_SP_SNIKSNAK,
1924     EL_SP_ELECTRON,
1925
1926     /* new elements */
1927     EL_AMOEBA_DROP,
1928     EL_ACID,
1929
1930     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
1931 #if 1
1932     EL_LANDMINE,
1933     EL_TRAP_ACTIVE,
1934     EL_SP_BUGGY_BASE_ACTIVE,
1935     EL_EMC_PLANT,
1936 #endif
1937
1938     -1
1939   };
1940
1941   static int ep_dont_collide_with[] =
1942   {
1943     /* same elements as in 'ep_dont_touch' */
1944     EL_BUG,
1945     EL_SPACESHIP,
1946     EL_BD_BUTTERFLY,
1947     EL_BD_FIREFLY,
1948
1949     /* new elements */
1950     EL_YAMYAM,
1951     EL_DARK_YAMYAM,
1952     EL_ROBOT,
1953     EL_PACMAN,
1954     EL_SP_SNIKSNAK,
1955     EL_SP_ELECTRON,
1956
1957     -1
1958   };
1959
1960   static int ep_dont_touch[] =
1961   {
1962     EL_BUG,
1963     EL_SPACESHIP,
1964     EL_BD_BUTTERFLY,
1965     EL_BD_FIREFLY,
1966
1967     -1
1968   };
1969
1970   static int ep_indestructible[] =
1971   {
1972     EL_STEELWALL,
1973     EL_ACID,
1974     EL_ACID_POOL_TOPLEFT,
1975     EL_ACID_POOL_TOPRIGHT,
1976     EL_ACID_POOL_BOTTOMLEFT,
1977     EL_ACID_POOL_BOTTOM,
1978     EL_ACID_POOL_BOTTOMRIGHT,
1979     EL_SP_HARDWARE_GRAY,
1980     EL_SP_HARDWARE_GREEN,
1981     EL_SP_HARDWARE_BLUE,
1982     EL_SP_HARDWARE_RED,
1983     EL_SP_HARDWARE_YELLOW,
1984     EL_SP_HARDWARE_BASE_1,
1985     EL_SP_HARDWARE_BASE_2,
1986     EL_SP_HARDWARE_BASE_3,
1987     EL_SP_HARDWARE_BASE_4,
1988     EL_SP_HARDWARE_BASE_5,
1989     EL_SP_HARDWARE_BASE_6,
1990     EL_INVISIBLE_STEELWALL,
1991     EL_INVISIBLE_STEELWALL_ACTIVE,
1992     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
1993     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
1994     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
1995     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
1996     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
1997     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
1998     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
1999     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2000     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2001     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2002     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2003     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2004     EL_LIGHT_SWITCH,
2005     EL_LIGHT_SWITCH_ACTIVE,
2006     EL_SIGN_EXCLAMATION,
2007     EL_SIGN_RADIOACTIVITY,
2008     EL_SIGN_STOP,
2009     EL_SIGN_WHEELCHAIR,
2010     EL_SIGN_PARKING,
2011     EL_SIGN_ONEWAY,
2012     EL_SIGN_HEART,
2013     EL_SIGN_TRIANGLE,
2014     EL_SIGN_ROUND,
2015     EL_SIGN_EXIT,
2016     EL_SIGN_YINYANG,
2017     EL_SIGN_OTHER,
2018     EL_STEELWALL_SLIPPERY,
2019     EL_EMC_STEELWALL_1,
2020     EL_EMC_STEELWALL_2,
2021     EL_EMC_STEELWALL_3,
2022     EL_EMC_STEELWALL_4,
2023     EL_CRYSTAL,
2024     EL_GATE_1,
2025     EL_GATE_2,
2026     EL_GATE_3,
2027     EL_GATE_4,
2028     EL_GATE_1_GRAY,
2029     EL_GATE_2_GRAY,
2030     EL_GATE_3_GRAY,
2031     EL_GATE_4_GRAY,
2032     EL_GATE_1_GRAY_ACTIVE,
2033     EL_GATE_2_GRAY_ACTIVE,
2034     EL_GATE_3_GRAY_ACTIVE,
2035     EL_GATE_4_GRAY_ACTIVE,
2036     EL_EM_GATE_1,
2037     EL_EM_GATE_2,
2038     EL_EM_GATE_3,
2039     EL_EM_GATE_4,
2040     EL_EM_GATE_1_GRAY,
2041     EL_EM_GATE_2_GRAY,
2042     EL_EM_GATE_3_GRAY,
2043     EL_EM_GATE_4_GRAY,
2044     EL_EM_GATE_1_GRAY_ACTIVE,
2045     EL_EM_GATE_2_GRAY_ACTIVE,
2046     EL_EM_GATE_3_GRAY_ACTIVE,
2047     EL_EM_GATE_4_GRAY_ACTIVE,
2048     EL_EMC_GATE_5,
2049     EL_EMC_GATE_6,
2050     EL_EMC_GATE_7,
2051     EL_EMC_GATE_8,
2052     EL_EMC_GATE_5_GRAY,
2053     EL_EMC_GATE_6_GRAY,
2054     EL_EMC_GATE_7_GRAY,
2055     EL_EMC_GATE_8_GRAY,
2056     EL_EMC_GATE_5_GRAY_ACTIVE,
2057     EL_EMC_GATE_6_GRAY_ACTIVE,
2058     EL_EMC_GATE_7_GRAY_ACTIVE,
2059     EL_EMC_GATE_8_GRAY_ACTIVE,
2060     EL_SWITCHGATE_OPEN,
2061     EL_SWITCHGATE_OPENING,
2062     EL_SWITCHGATE_CLOSED,
2063     EL_SWITCHGATE_CLOSING,
2064 #if 0
2065     EL_SWITCHGATE_SWITCH_UP,
2066     EL_SWITCHGATE_SWITCH_DOWN,
2067 #endif
2068     EL_TIMEGATE_OPEN,
2069     EL_TIMEGATE_OPENING,
2070     EL_TIMEGATE_CLOSED,
2071     EL_TIMEGATE_CLOSING,
2072 #if 0
2073     EL_TIMEGATE_SWITCH,
2074     EL_TIMEGATE_SWITCH_ACTIVE,
2075 #endif
2076     EL_TUBE_ANY,
2077     EL_TUBE_VERTICAL,
2078     EL_TUBE_HORIZONTAL,
2079     EL_TUBE_VERTICAL_LEFT,
2080     EL_TUBE_VERTICAL_RIGHT,
2081     EL_TUBE_HORIZONTAL_UP,
2082     EL_TUBE_HORIZONTAL_DOWN,
2083     EL_TUBE_LEFT_UP,
2084     EL_TUBE_LEFT_DOWN,
2085     EL_TUBE_RIGHT_UP,
2086     EL_TUBE_RIGHT_DOWN,
2087
2088     -1
2089   };
2090
2091   static int ep_slippery[] =
2092   {
2093     EL_WALL_SLIPPERY,
2094     EL_BD_WALL,
2095     EL_ROCK,
2096     EL_BD_ROCK,
2097     EL_EMERALD,
2098     EL_BD_DIAMOND,
2099     EL_EMERALD_YELLOW,
2100     EL_EMERALD_RED,
2101     EL_EMERALD_PURPLE,
2102     EL_DIAMOND,
2103     EL_BOMB,
2104     EL_NUT,
2105     EL_ROBOT_WHEEL_ACTIVE,
2106     EL_ROBOT_WHEEL,
2107     EL_TIME_ORB_FULL,
2108     EL_TIME_ORB_EMPTY,
2109     EL_LAMP_ACTIVE,
2110     EL_LAMP,
2111     EL_ACID_POOL_TOPLEFT,
2112     EL_ACID_POOL_TOPRIGHT,
2113     EL_SATELLITE,
2114     EL_SP_ZONK,
2115     EL_SP_INFOTRON,
2116     EL_SP_CHIP_SINGLE,
2117     EL_SP_CHIP_LEFT,
2118     EL_SP_CHIP_RIGHT,
2119     EL_SP_CHIP_TOP,
2120     EL_SP_CHIP_BOTTOM,
2121     EL_SPEED_PILL,
2122     EL_STEELWALL_SLIPPERY,
2123     EL_PEARL,
2124     EL_CRYSTAL,
2125     EL_EMC_WALL_SLIPPERY_1,
2126     EL_EMC_WALL_SLIPPERY_2,
2127     EL_EMC_WALL_SLIPPERY_3,
2128     EL_EMC_WALL_SLIPPERY_4,
2129     EL_EMC_MAGIC_BALL,
2130     EL_EMC_MAGIC_BALL_ACTIVE,
2131
2132     -1
2133   };
2134
2135   static int ep_can_change[] =
2136   {
2137     -1
2138   };
2139
2140   static int ep_can_move[] =
2141   {
2142     /* same elements as in 'pb_can_move_into_acid' */
2143     EL_BUG,
2144     EL_SPACESHIP,
2145     EL_BD_BUTTERFLY,
2146     EL_BD_FIREFLY,
2147     EL_YAMYAM,
2148     EL_DARK_YAMYAM,
2149     EL_ROBOT,
2150     EL_PACMAN,
2151     EL_MOLE,
2152     EL_PENGUIN,
2153     EL_PIG,
2154     EL_DRAGON,
2155     EL_SATELLITE,
2156     EL_SP_SNIKSNAK,
2157     EL_SP_ELECTRON,
2158     EL_BALLOON,
2159     EL_SPRING,
2160     EL_EMC_ANDROID,
2161
2162     -1
2163   };
2164
2165   static int ep_can_fall[] =
2166   {
2167     EL_ROCK,
2168     EL_BD_ROCK,
2169     EL_EMERALD,
2170     EL_BD_DIAMOND,
2171     EL_EMERALD_YELLOW,
2172     EL_EMERALD_RED,
2173     EL_EMERALD_PURPLE,
2174     EL_DIAMOND,
2175     EL_BOMB,
2176     EL_NUT,
2177     EL_AMOEBA_DROP,
2178     EL_QUICKSAND_FULL,
2179     EL_MAGIC_WALL_FULL,
2180     EL_BD_MAGIC_WALL_FULL,
2181     EL_TIME_ORB_FULL,
2182     EL_TIME_ORB_EMPTY,
2183     EL_SP_ZONK,
2184     EL_SP_INFOTRON,
2185     EL_SP_DISK_ORANGE,
2186     EL_PEARL,
2187     EL_CRYSTAL,
2188     EL_SPRING,
2189     EL_DX_SUPABOMB,
2190
2191     -1
2192   };
2193
2194   static int ep_can_smash_player[] =
2195   {
2196     EL_ROCK,
2197     EL_BD_ROCK,
2198     EL_EMERALD,
2199     EL_BD_DIAMOND,
2200     EL_EMERALD_YELLOW,
2201     EL_EMERALD_RED,
2202     EL_EMERALD_PURPLE,
2203     EL_DIAMOND,
2204     EL_BOMB,
2205     EL_NUT,
2206     EL_AMOEBA_DROP,
2207     EL_TIME_ORB_FULL,
2208     EL_TIME_ORB_EMPTY,
2209     EL_SP_ZONK,
2210     EL_SP_INFOTRON,
2211     EL_SP_DISK_ORANGE,
2212     EL_PEARL,
2213     EL_CRYSTAL,
2214     EL_SPRING,
2215     EL_DX_SUPABOMB,
2216
2217     -1
2218   };
2219
2220   static int ep_can_smash_enemies[] =
2221   {
2222     EL_ROCK,
2223     EL_BD_ROCK,
2224     EL_SP_ZONK,
2225
2226     -1
2227   };
2228
2229   static int ep_can_smash_everything[] =
2230   {
2231     EL_ROCK,
2232     EL_BD_ROCK,
2233     EL_SP_ZONK,
2234
2235     -1
2236   };
2237
2238   static int ep_explodes_by_fire[] =
2239   {
2240     /* same elements as in 'ep_explodes_impact' */
2241     EL_BOMB,
2242     EL_SP_DISK_ORANGE,
2243     EL_DX_SUPABOMB,
2244
2245     /* same elements as in 'ep_explodes_smashed' */
2246     EL_SATELLITE,
2247     EL_PIG,
2248     EL_DRAGON,
2249     EL_MOLE,
2250
2251     /* new elements */
2252     EL_DYNAMITE,
2253     EL_DYNAMITE_ACTIVE,
2254     EL_EM_DYNAMITE,
2255     EL_EM_DYNAMITE_ACTIVE,
2256     EL_DYNABOMB_PLAYER_1_ACTIVE,
2257     EL_DYNABOMB_PLAYER_2_ACTIVE,
2258     EL_DYNABOMB_PLAYER_3_ACTIVE,
2259     EL_DYNABOMB_PLAYER_4_ACTIVE,
2260     EL_DYNABOMB_INCREASE_NUMBER,
2261     EL_DYNABOMB_INCREASE_SIZE,
2262     EL_DYNABOMB_INCREASE_POWER,
2263     EL_SP_DISK_RED_ACTIVE,
2264     EL_BUG,
2265     EL_PENGUIN,
2266     EL_SP_DISK_RED,
2267     EL_SP_DISK_YELLOW,
2268     EL_SP_SNIKSNAK,
2269     EL_SP_ELECTRON,
2270 #if 0
2271     EL_BLACK_ORB,
2272 #endif
2273
2274     -1
2275   };
2276
2277   static int ep_explodes_smashed[] =
2278   {
2279     /* same elements as in 'ep_explodes_impact' */
2280     EL_BOMB,
2281     EL_SP_DISK_ORANGE,
2282     EL_DX_SUPABOMB,
2283
2284     /* new elements */
2285     EL_SATELLITE,
2286     EL_PIG,
2287     EL_DRAGON,
2288     EL_MOLE,
2289
2290     -1
2291   };
2292
2293   static int ep_explodes_impact[] =
2294   {
2295     EL_BOMB,
2296     EL_SP_DISK_ORANGE,
2297     EL_DX_SUPABOMB,
2298
2299     -1
2300   };
2301
2302   static int ep_walkable_over[] =
2303   {
2304     EL_EMPTY_SPACE,
2305     EL_SP_EMPTY_SPACE,
2306     EL_SOKOBAN_FIELD_EMPTY,
2307     EL_EXIT_OPEN,
2308     EL_SP_EXIT_OPEN,
2309     EL_SP_EXIT_OPENING,
2310     EL_GATE_1,
2311     EL_GATE_2,
2312     EL_GATE_3,
2313     EL_GATE_4,
2314     EL_GATE_1_GRAY,
2315     EL_GATE_2_GRAY,
2316     EL_GATE_3_GRAY,
2317     EL_GATE_4_GRAY,
2318     EL_GATE_1_GRAY_ACTIVE,
2319     EL_GATE_2_GRAY_ACTIVE,
2320     EL_GATE_3_GRAY_ACTIVE,
2321     EL_GATE_4_GRAY_ACTIVE,
2322     EL_PENGUIN,
2323     EL_PIG,
2324     EL_DRAGON,
2325
2326     -1
2327   };
2328
2329   static int ep_walkable_inside[] =
2330   {
2331     EL_TUBE_ANY,
2332     EL_TUBE_VERTICAL,
2333     EL_TUBE_HORIZONTAL,
2334     EL_TUBE_VERTICAL_LEFT,
2335     EL_TUBE_VERTICAL_RIGHT,
2336     EL_TUBE_HORIZONTAL_UP,
2337     EL_TUBE_HORIZONTAL_DOWN,
2338     EL_TUBE_LEFT_UP,
2339     EL_TUBE_LEFT_DOWN,
2340     EL_TUBE_RIGHT_UP,
2341     EL_TUBE_RIGHT_DOWN,
2342
2343     -1
2344   };
2345
2346   static int ep_walkable_under[] =
2347   {
2348     -1
2349   };
2350
2351   static int ep_passable_over[] =
2352   {
2353     EL_EM_GATE_1,
2354     EL_EM_GATE_2,
2355     EL_EM_GATE_3,
2356     EL_EM_GATE_4,
2357     EL_EM_GATE_1_GRAY,
2358     EL_EM_GATE_2_GRAY,
2359     EL_EM_GATE_3_GRAY,
2360     EL_EM_GATE_4_GRAY,
2361     EL_EM_GATE_1_GRAY_ACTIVE,
2362     EL_EM_GATE_2_GRAY_ACTIVE,
2363     EL_EM_GATE_3_GRAY_ACTIVE,
2364     EL_EM_GATE_4_GRAY_ACTIVE,
2365     EL_EMC_GATE_5,
2366     EL_EMC_GATE_6,
2367     EL_EMC_GATE_7,
2368     EL_EMC_GATE_8,
2369     EL_EMC_GATE_5_GRAY,
2370     EL_EMC_GATE_6_GRAY,
2371     EL_EMC_GATE_7_GRAY,
2372     EL_EMC_GATE_8_GRAY,
2373     EL_EMC_GATE_5_GRAY_ACTIVE,
2374     EL_EMC_GATE_6_GRAY_ACTIVE,
2375     EL_EMC_GATE_7_GRAY_ACTIVE,
2376     EL_EMC_GATE_8_GRAY_ACTIVE,
2377     EL_SWITCHGATE_OPEN,
2378     EL_TIMEGATE_OPEN,
2379
2380     -1
2381   };
2382
2383   static int ep_passable_inside[] =
2384   {
2385     EL_SP_PORT_LEFT,
2386     EL_SP_PORT_RIGHT,
2387     EL_SP_PORT_UP,
2388     EL_SP_PORT_DOWN,
2389     EL_SP_PORT_HORIZONTAL,
2390     EL_SP_PORT_VERTICAL,
2391     EL_SP_PORT_ANY,
2392     EL_SP_GRAVITY_PORT_LEFT,
2393     EL_SP_GRAVITY_PORT_RIGHT,
2394     EL_SP_GRAVITY_PORT_UP,
2395     EL_SP_GRAVITY_PORT_DOWN,
2396     EL_SP_GRAVITY_ON_PORT_LEFT,
2397     EL_SP_GRAVITY_ON_PORT_RIGHT,
2398     EL_SP_GRAVITY_ON_PORT_UP,
2399     EL_SP_GRAVITY_ON_PORT_DOWN,
2400     EL_SP_GRAVITY_OFF_PORT_LEFT,
2401     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2402     EL_SP_GRAVITY_OFF_PORT_UP,
2403     EL_SP_GRAVITY_OFF_PORT_DOWN,
2404
2405     -1
2406   };
2407
2408   static int ep_passable_under[] =
2409   {
2410     -1
2411   };
2412
2413   static int ep_droppable[] =
2414   {
2415     -1
2416   };
2417
2418   static int ep_explodes_1x1_old[] =
2419   {
2420     -1
2421   };
2422
2423   static int ep_pushable[] =
2424   {
2425     EL_ROCK,
2426     EL_BOMB,
2427     EL_DX_SUPABOMB,
2428     EL_NUT,
2429     EL_TIME_ORB_EMPTY,
2430     EL_SP_ZONK,
2431     EL_SP_DISK_ORANGE,
2432     EL_SPRING,
2433     EL_BD_ROCK,
2434     EL_SOKOBAN_OBJECT,
2435     EL_SOKOBAN_FIELD_FULL,
2436     EL_SATELLITE,
2437     EL_SP_DISK_YELLOW,
2438     EL_BALLOON,
2439     EL_EMC_ANDROID,
2440
2441     -1
2442   };
2443
2444   static int ep_explodes_cross_old[] =
2445   {
2446     -1
2447   };
2448
2449   static int ep_protected[] =
2450   {
2451     /* same elements as in 'ep_walkable_inside' */
2452     EL_TUBE_ANY,
2453     EL_TUBE_VERTICAL,
2454     EL_TUBE_HORIZONTAL,
2455     EL_TUBE_VERTICAL_LEFT,
2456     EL_TUBE_VERTICAL_RIGHT,
2457     EL_TUBE_HORIZONTAL_UP,
2458     EL_TUBE_HORIZONTAL_DOWN,
2459     EL_TUBE_LEFT_UP,
2460     EL_TUBE_LEFT_DOWN,
2461     EL_TUBE_RIGHT_UP,
2462     EL_TUBE_RIGHT_DOWN,
2463
2464     /* same elements as in 'ep_passable_over' */
2465     EL_EM_GATE_1,
2466     EL_EM_GATE_2,
2467     EL_EM_GATE_3,
2468     EL_EM_GATE_4,
2469     EL_EM_GATE_1_GRAY,
2470     EL_EM_GATE_2_GRAY,
2471     EL_EM_GATE_3_GRAY,
2472     EL_EM_GATE_4_GRAY,
2473     EL_EM_GATE_1_GRAY_ACTIVE,
2474     EL_EM_GATE_2_GRAY_ACTIVE,
2475     EL_EM_GATE_3_GRAY_ACTIVE,
2476     EL_EM_GATE_4_GRAY_ACTIVE,
2477     EL_EMC_GATE_5,
2478     EL_EMC_GATE_6,
2479     EL_EMC_GATE_7,
2480     EL_EMC_GATE_8,
2481     EL_EMC_GATE_5_GRAY,
2482     EL_EMC_GATE_6_GRAY,
2483     EL_EMC_GATE_7_GRAY,
2484     EL_EMC_GATE_8_GRAY,
2485     EL_EMC_GATE_5_GRAY_ACTIVE,
2486     EL_EMC_GATE_6_GRAY_ACTIVE,
2487     EL_EMC_GATE_7_GRAY_ACTIVE,
2488     EL_EMC_GATE_8_GRAY_ACTIVE,
2489     EL_SWITCHGATE_OPEN,
2490     EL_TIMEGATE_OPEN,
2491
2492     /* same elements as in 'ep_passable_inside' */
2493     EL_SP_PORT_LEFT,
2494     EL_SP_PORT_RIGHT,
2495     EL_SP_PORT_UP,
2496     EL_SP_PORT_DOWN,
2497     EL_SP_PORT_HORIZONTAL,
2498     EL_SP_PORT_VERTICAL,
2499     EL_SP_PORT_ANY,
2500     EL_SP_GRAVITY_PORT_LEFT,
2501     EL_SP_GRAVITY_PORT_RIGHT,
2502     EL_SP_GRAVITY_PORT_UP,
2503     EL_SP_GRAVITY_PORT_DOWN,
2504     EL_SP_GRAVITY_ON_PORT_LEFT,
2505     EL_SP_GRAVITY_ON_PORT_RIGHT,
2506     EL_SP_GRAVITY_ON_PORT_UP,
2507     EL_SP_GRAVITY_ON_PORT_DOWN,
2508     EL_SP_GRAVITY_OFF_PORT_LEFT,
2509     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2510     EL_SP_GRAVITY_OFF_PORT_UP,
2511     EL_SP_GRAVITY_OFF_PORT_DOWN,
2512
2513     -1
2514   };
2515
2516   static int ep_throwable[] =
2517   {
2518     -1
2519   };
2520
2521   static int ep_can_explode[] =
2522   {
2523     /* same elements as in 'ep_explodes_impact' */
2524     EL_BOMB,
2525     EL_SP_DISK_ORANGE,
2526     EL_DX_SUPABOMB,
2527
2528     /* same elements as in 'ep_explodes_smashed' */
2529     EL_SATELLITE,
2530     EL_PIG,
2531     EL_DRAGON,
2532     EL_MOLE,
2533
2534     /* elements that can explode by explosion or by dragonfire */
2535     EL_DYNAMITE,
2536     EL_DYNAMITE_ACTIVE,
2537     EL_EM_DYNAMITE,
2538     EL_EM_DYNAMITE_ACTIVE,
2539     EL_DYNABOMB_PLAYER_1_ACTIVE,
2540     EL_DYNABOMB_PLAYER_2_ACTIVE,
2541     EL_DYNABOMB_PLAYER_3_ACTIVE,
2542     EL_DYNABOMB_PLAYER_4_ACTIVE,
2543     EL_DYNABOMB_INCREASE_NUMBER,
2544     EL_DYNABOMB_INCREASE_SIZE,
2545     EL_DYNABOMB_INCREASE_POWER,
2546     EL_SP_DISK_RED_ACTIVE,
2547     EL_BUG,
2548     EL_PENGUIN,
2549     EL_SP_DISK_RED,
2550     EL_SP_DISK_YELLOW,
2551     EL_SP_SNIKSNAK,
2552     EL_SP_ELECTRON,
2553
2554     /* elements that can explode only by explosion */
2555     EL_BLACK_ORB,
2556
2557     -1
2558   };
2559
2560   static int ep_gravity_reachable[] =
2561   {
2562     EL_SAND,
2563     EL_SP_BASE,
2564     EL_TRAP,
2565     EL_INVISIBLE_SAND,
2566     EL_INVISIBLE_SAND_ACTIVE,
2567     EL_SP_PORT_LEFT,
2568     EL_SP_PORT_RIGHT,
2569     EL_SP_PORT_UP,
2570     EL_SP_PORT_DOWN,
2571     EL_SP_PORT_HORIZONTAL,
2572     EL_SP_PORT_VERTICAL,
2573     EL_SP_PORT_ANY,
2574     EL_SP_GRAVITY_PORT_LEFT,
2575     EL_SP_GRAVITY_PORT_RIGHT,
2576     EL_SP_GRAVITY_PORT_UP,
2577     EL_SP_GRAVITY_PORT_DOWN,
2578     EL_SP_GRAVITY_ON_PORT_LEFT,
2579     EL_SP_GRAVITY_ON_PORT_RIGHT,
2580     EL_SP_GRAVITY_ON_PORT_UP,
2581     EL_SP_GRAVITY_ON_PORT_DOWN,
2582     EL_SP_GRAVITY_OFF_PORT_LEFT,
2583     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2584     EL_SP_GRAVITY_OFF_PORT_UP,
2585     EL_SP_GRAVITY_OFF_PORT_DOWN,
2586     EL_EMC_GRASS,
2587
2588     -1
2589   };
2590
2591   static int ep_player[] =
2592   {
2593     EL_PLAYER_1,
2594     EL_PLAYER_2,
2595     EL_PLAYER_3,
2596     EL_PLAYER_4,
2597     EL_SP_MURPHY,
2598     EL_SOKOBAN_FIELD_PLAYER,
2599     EL_TRIGGER_PLAYER,
2600
2601     -1
2602   };
2603
2604   static int ep_can_pass_magic_wall[] =
2605   {
2606     EL_ROCK,
2607     EL_BD_ROCK,
2608     EL_EMERALD,
2609     EL_BD_DIAMOND,
2610     EL_EMERALD_YELLOW,
2611     EL_EMERALD_RED,
2612     EL_EMERALD_PURPLE,
2613     EL_DIAMOND,
2614
2615     -1
2616   };
2617
2618   static int ep_switchable[] =
2619   {
2620     EL_ROBOT_WHEEL,
2621     EL_SP_TERMINAL,
2622     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2623     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2624     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2625     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2626     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2627     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2628     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2629     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2630     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2631     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2632     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2633     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2634     EL_SWITCHGATE_SWITCH_UP,
2635     EL_SWITCHGATE_SWITCH_DOWN,
2636     EL_LIGHT_SWITCH,
2637     EL_LIGHT_SWITCH_ACTIVE,
2638     EL_TIMEGATE_SWITCH,
2639     EL_BALLOON_SWITCH_LEFT,
2640     EL_BALLOON_SWITCH_RIGHT,
2641     EL_BALLOON_SWITCH_UP,
2642     EL_BALLOON_SWITCH_DOWN,
2643     EL_BALLOON_SWITCH_ANY,
2644     EL_BALLOON_SWITCH_NONE,
2645     EL_LAMP,
2646     EL_TIME_ORB_FULL,
2647     EL_EMC_MAGIC_BALL_SWITCH,
2648     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
2649
2650     -1
2651   };
2652
2653   static int ep_bd_element[] =
2654   {
2655     EL_EMPTY,
2656     EL_SAND,
2657     EL_WALL_SLIPPERY,
2658     EL_BD_WALL,
2659     EL_ROCK,
2660     EL_BD_ROCK,
2661     EL_BD_DIAMOND,
2662     EL_BD_MAGIC_WALL,
2663     EL_EXIT_CLOSED,
2664     EL_EXIT_OPEN,
2665     EL_STEELWALL,
2666     EL_PLAYER_1,
2667     EL_PLAYER_2,
2668     EL_PLAYER_3,
2669     EL_PLAYER_4,
2670     EL_BD_FIREFLY,
2671     EL_BD_FIREFLY_1,
2672     EL_BD_FIREFLY_2,
2673     EL_BD_FIREFLY_3,
2674     EL_BD_FIREFLY_4,
2675     EL_BD_BUTTERFLY,
2676     EL_BD_BUTTERFLY_1,
2677     EL_BD_BUTTERFLY_2,
2678     EL_BD_BUTTERFLY_3,
2679     EL_BD_BUTTERFLY_4,
2680     EL_BD_AMOEBA,
2681     EL_CHAR_QUESTION,
2682     EL_UNKNOWN,
2683
2684     -1
2685   };
2686
2687   static int ep_sp_element[] =
2688   {
2689     /* should always be valid */
2690     EL_EMPTY,
2691
2692     /* standard classic Supaplex elements */
2693     EL_SP_EMPTY,
2694     EL_SP_ZONK,
2695     EL_SP_BASE,
2696     EL_SP_MURPHY,
2697     EL_SP_INFOTRON,
2698     EL_SP_CHIP_SINGLE,
2699     EL_SP_HARDWARE_GRAY,
2700     EL_SP_EXIT_CLOSED,
2701     EL_SP_EXIT_OPEN,
2702     EL_SP_DISK_ORANGE,
2703     EL_SP_PORT_RIGHT,
2704     EL_SP_PORT_DOWN,
2705     EL_SP_PORT_LEFT,
2706     EL_SP_PORT_UP,
2707     EL_SP_GRAVITY_PORT_RIGHT,
2708     EL_SP_GRAVITY_PORT_DOWN,
2709     EL_SP_GRAVITY_PORT_LEFT,
2710     EL_SP_GRAVITY_PORT_UP,
2711     EL_SP_SNIKSNAK,
2712     EL_SP_DISK_YELLOW,
2713     EL_SP_TERMINAL,
2714     EL_SP_DISK_RED,
2715     EL_SP_PORT_VERTICAL,
2716     EL_SP_PORT_HORIZONTAL,
2717     EL_SP_PORT_ANY,
2718     EL_SP_ELECTRON,
2719     EL_SP_BUGGY_BASE,
2720     EL_SP_CHIP_LEFT,
2721     EL_SP_CHIP_RIGHT,
2722     EL_SP_HARDWARE_BASE_1,
2723     EL_SP_HARDWARE_GREEN,
2724     EL_SP_HARDWARE_BLUE,
2725     EL_SP_HARDWARE_RED,
2726     EL_SP_HARDWARE_YELLOW,
2727     EL_SP_HARDWARE_BASE_2,
2728     EL_SP_HARDWARE_BASE_3,
2729     EL_SP_HARDWARE_BASE_4,
2730     EL_SP_HARDWARE_BASE_5,
2731     EL_SP_HARDWARE_BASE_6,
2732     EL_SP_CHIP_TOP,
2733     EL_SP_CHIP_BOTTOM,
2734
2735     /* additional elements that appeared in newer Supaplex levels */
2736     EL_INVISIBLE_WALL,
2737
2738     /* additional gravity port elements (not switching, but setting gravity) */
2739     EL_SP_GRAVITY_ON_PORT_LEFT,
2740     EL_SP_GRAVITY_ON_PORT_RIGHT,
2741     EL_SP_GRAVITY_ON_PORT_UP,
2742     EL_SP_GRAVITY_ON_PORT_DOWN,
2743     EL_SP_GRAVITY_OFF_PORT_LEFT,
2744     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2745     EL_SP_GRAVITY_OFF_PORT_UP,
2746     EL_SP_GRAVITY_OFF_PORT_DOWN,
2747
2748     /* more than one Murphy in a level results in an inactive clone */
2749     EL_SP_MURPHY_CLONE,
2750
2751     /* runtime Supaplex elements */
2752     EL_SP_DISK_RED_ACTIVE,
2753     EL_SP_TERMINAL_ACTIVE,
2754     EL_SP_BUGGY_BASE_ACTIVATING,
2755     EL_SP_BUGGY_BASE_ACTIVE,
2756     EL_SP_EXIT_OPENING,
2757     EL_SP_EXIT_CLOSING,
2758
2759     -1
2760   };
2761
2762   static int ep_sb_element[] =
2763   {
2764     EL_EMPTY,
2765     EL_STEELWALL,
2766     EL_SOKOBAN_OBJECT,
2767     EL_SOKOBAN_FIELD_EMPTY,
2768     EL_SOKOBAN_FIELD_FULL,
2769     EL_SOKOBAN_FIELD_PLAYER,
2770     EL_PLAYER_1,
2771     EL_PLAYER_2,
2772     EL_PLAYER_3,
2773     EL_PLAYER_4,
2774     EL_INVISIBLE_STEELWALL,
2775
2776     -1
2777   };
2778
2779   static int ep_gem[] =
2780   {
2781     EL_BD_DIAMOND,
2782     EL_EMERALD,
2783     EL_EMERALD_YELLOW,
2784     EL_EMERALD_RED,
2785     EL_EMERALD_PURPLE,
2786     EL_DIAMOND,
2787
2788     -1
2789   };
2790
2791   static int ep_food_dark_yamyam[] =
2792   {
2793     EL_SAND,
2794     EL_BUG,
2795     EL_SPACESHIP,
2796     EL_BD_BUTTERFLY,
2797     EL_BD_FIREFLY,
2798     EL_YAMYAM,
2799     EL_ROBOT,
2800     EL_PACMAN,
2801     EL_AMOEBA_DROP,
2802     EL_AMOEBA_DEAD,
2803     EL_AMOEBA_WET,
2804     EL_AMOEBA_DRY,
2805     EL_AMOEBA_FULL,
2806     EL_BD_AMOEBA,
2807     EL_EMERALD,
2808     EL_BD_DIAMOND,
2809     EL_EMERALD_YELLOW,
2810     EL_EMERALD_RED,
2811     EL_EMERALD_PURPLE,
2812     EL_DIAMOND,
2813     EL_PEARL,
2814     EL_CRYSTAL,
2815
2816     -1
2817   };
2818
2819   static int ep_food_penguin[] =
2820   {
2821     EL_EMERALD,
2822     EL_BD_DIAMOND,
2823     EL_EMERALD_YELLOW,
2824     EL_EMERALD_RED,
2825     EL_EMERALD_PURPLE,
2826     EL_DIAMOND,
2827     EL_PEARL,
2828     EL_CRYSTAL,
2829
2830     -1
2831   };
2832
2833   static int ep_food_pig[] =
2834   {
2835     EL_EMERALD,
2836     EL_BD_DIAMOND,
2837     EL_EMERALD_YELLOW,
2838     EL_EMERALD_RED,
2839     EL_EMERALD_PURPLE,
2840     EL_DIAMOND,
2841
2842     -1
2843   };
2844
2845   static int ep_historic_wall[] =
2846   {
2847     EL_STEELWALL,
2848     EL_GATE_1,
2849     EL_GATE_2,
2850     EL_GATE_3,
2851     EL_GATE_4,
2852     EL_GATE_1_GRAY,
2853     EL_GATE_2_GRAY,
2854     EL_GATE_3_GRAY,
2855     EL_GATE_4_GRAY,
2856     EL_GATE_1_GRAY_ACTIVE,
2857     EL_GATE_2_GRAY_ACTIVE,
2858     EL_GATE_3_GRAY_ACTIVE,
2859     EL_GATE_4_GRAY_ACTIVE,
2860     EL_EM_GATE_1,
2861     EL_EM_GATE_2,
2862     EL_EM_GATE_3,
2863     EL_EM_GATE_4,
2864     EL_EM_GATE_1_GRAY,
2865     EL_EM_GATE_2_GRAY,
2866     EL_EM_GATE_3_GRAY,
2867     EL_EM_GATE_4_GRAY,
2868     EL_EM_GATE_1_GRAY_ACTIVE,
2869     EL_EM_GATE_2_GRAY_ACTIVE,
2870     EL_EM_GATE_3_GRAY_ACTIVE,
2871     EL_EM_GATE_4_GRAY_ACTIVE,
2872     EL_EXIT_CLOSED,
2873     EL_EXIT_OPENING,
2874     EL_EXIT_OPEN,
2875     EL_WALL,
2876     EL_WALL_SLIPPERY,
2877     EL_EXPANDABLE_WALL,
2878     EL_EXPANDABLE_WALL_HORIZONTAL,
2879     EL_EXPANDABLE_WALL_VERTICAL,
2880     EL_EXPANDABLE_WALL_ANY,
2881     EL_EXPANDABLE_WALL_GROWING,
2882     EL_BD_WALL,
2883     EL_SP_CHIP_SINGLE,
2884     EL_SP_CHIP_LEFT,
2885     EL_SP_CHIP_RIGHT,
2886     EL_SP_CHIP_TOP,
2887     EL_SP_CHIP_BOTTOM,
2888     EL_SP_HARDWARE_GRAY,
2889     EL_SP_HARDWARE_GREEN,
2890     EL_SP_HARDWARE_BLUE,
2891     EL_SP_HARDWARE_RED,
2892     EL_SP_HARDWARE_YELLOW,
2893     EL_SP_HARDWARE_BASE_1,
2894     EL_SP_HARDWARE_BASE_2,
2895     EL_SP_HARDWARE_BASE_3,
2896     EL_SP_HARDWARE_BASE_4,
2897     EL_SP_HARDWARE_BASE_5,
2898     EL_SP_HARDWARE_BASE_6,
2899     EL_SP_TERMINAL,
2900     EL_SP_TERMINAL_ACTIVE,
2901     EL_SP_EXIT_CLOSED,
2902     EL_SP_EXIT_OPEN,
2903     EL_INVISIBLE_STEELWALL,
2904     EL_INVISIBLE_STEELWALL_ACTIVE,
2905     EL_INVISIBLE_WALL,
2906     EL_INVISIBLE_WALL_ACTIVE,
2907     EL_STEELWALL_SLIPPERY,
2908     EL_EMC_STEELWALL_1,
2909     EL_EMC_STEELWALL_2,
2910     EL_EMC_STEELWALL_3,
2911     EL_EMC_STEELWALL_4,
2912     EL_EMC_WALL_1,
2913     EL_EMC_WALL_2,
2914     EL_EMC_WALL_3,
2915     EL_EMC_WALL_4,
2916     EL_EMC_WALL_5,
2917     EL_EMC_WALL_6,
2918     EL_EMC_WALL_7,
2919     EL_EMC_WALL_8,
2920
2921     -1
2922   };
2923
2924   static int ep_historic_solid[] =
2925   {
2926     EL_WALL,
2927     EL_EXPANDABLE_WALL,
2928     EL_EXPANDABLE_WALL_HORIZONTAL,
2929     EL_EXPANDABLE_WALL_VERTICAL,
2930     EL_EXPANDABLE_WALL_ANY,
2931     EL_BD_WALL,
2932     EL_WALL_SLIPPERY,
2933     EL_EXIT_CLOSED,
2934     EL_EXIT_OPENING,
2935     EL_EXIT_OPEN,
2936     EL_AMOEBA_DEAD,
2937     EL_AMOEBA_WET,
2938     EL_AMOEBA_DRY,
2939     EL_AMOEBA_FULL,
2940     EL_BD_AMOEBA,
2941     EL_QUICKSAND_EMPTY,
2942     EL_QUICKSAND_FULL,
2943     EL_QUICKSAND_FILLING,
2944     EL_QUICKSAND_EMPTYING,
2945     EL_MAGIC_WALL,
2946     EL_MAGIC_WALL_ACTIVE,
2947     EL_MAGIC_WALL_EMPTYING,
2948     EL_MAGIC_WALL_FILLING,
2949     EL_MAGIC_WALL_FULL,
2950     EL_MAGIC_WALL_DEAD,
2951     EL_BD_MAGIC_WALL,
2952     EL_BD_MAGIC_WALL_ACTIVE,
2953     EL_BD_MAGIC_WALL_EMPTYING,
2954     EL_BD_MAGIC_WALL_FULL,
2955     EL_BD_MAGIC_WALL_FILLING,
2956     EL_BD_MAGIC_WALL_DEAD,
2957     EL_GAME_OF_LIFE,
2958     EL_BIOMAZE,
2959     EL_SP_CHIP_SINGLE,
2960     EL_SP_CHIP_LEFT,
2961     EL_SP_CHIP_RIGHT,
2962     EL_SP_CHIP_TOP,
2963     EL_SP_CHIP_BOTTOM,
2964     EL_SP_TERMINAL,
2965     EL_SP_TERMINAL_ACTIVE,
2966     EL_SP_EXIT_CLOSED,
2967     EL_SP_EXIT_OPEN,
2968     EL_INVISIBLE_WALL,
2969     EL_INVISIBLE_WALL_ACTIVE,
2970     EL_SWITCHGATE_SWITCH_UP,
2971     EL_SWITCHGATE_SWITCH_DOWN,
2972     EL_TIMEGATE_SWITCH,
2973     EL_TIMEGATE_SWITCH_ACTIVE,
2974     EL_EMC_WALL_1,
2975     EL_EMC_WALL_2,
2976     EL_EMC_WALL_3,
2977     EL_EMC_WALL_4,
2978     EL_EMC_WALL_5,
2979     EL_EMC_WALL_6,
2980     EL_EMC_WALL_7,
2981     EL_EMC_WALL_8,
2982     EL_WALL_PEARL,
2983     EL_WALL_CRYSTAL,
2984
2985     /* the following elements are a direct copy of "indestructible" elements,
2986        except "EL_ACID", which is "indestructible", but not "solid"! */
2987 #if 0
2988     EL_ACID,
2989 #endif
2990     EL_STEELWALL,
2991     EL_ACID_POOL_TOPLEFT,
2992     EL_ACID_POOL_TOPRIGHT,
2993     EL_ACID_POOL_BOTTOMLEFT,
2994     EL_ACID_POOL_BOTTOM,
2995     EL_ACID_POOL_BOTTOMRIGHT,
2996     EL_SP_HARDWARE_GRAY,
2997     EL_SP_HARDWARE_GREEN,
2998     EL_SP_HARDWARE_BLUE,
2999     EL_SP_HARDWARE_RED,
3000     EL_SP_HARDWARE_YELLOW,
3001     EL_SP_HARDWARE_BASE_1,
3002     EL_SP_HARDWARE_BASE_2,
3003     EL_SP_HARDWARE_BASE_3,
3004     EL_SP_HARDWARE_BASE_4,
3005     EL_SP_HARDWARE_BASE_5,
3006     EL_SP_HARDWARE_BASE_6,
3007     EL_INVISIBLE_STEELWALL,
3008     EL_INVISIBLE_STEELWALL_ACTIVE,
3009     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3010     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3011     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3012     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3013     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3014     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3015     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3016     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3017     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3018     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3019     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3020     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3021     EL_LIGHT_SWITCH,
3022     EL_LIGHT_SWITCH_ACTIVE,
3023     EL_SIGN_EXCLAMATION,
3024     EL_SIGN_RADIOACTIVITY,
3025     EL_SIGN_STOP,
3026     EL_SIGN_WHEELCHAIR,
3027     EL_SIGN_PARKING,
3028     EL_SIGN_ONEWAY,
3029     EL_SIGN_HEART,
3030     EL_SIGN_TRIANGLE,
3031     EL_SIGN_ROUND,
3032     EL_SIGN_EXIT,
3033     EL_SIGN_YINYANG,
3034     EL_SIGN_OTHER,
3035     EL_STEELWALL_SLIPPERY,
3036     EL_EMC_STEELWALL_1,
3037     EL_EMC_STEELWALL_2,
3038     EL_EMC_STEELWALL_3,
3039     EL_EMC_STEELWALL_4,
3040     EL_CRYSTAL,
3041     EL_GATE_1,
3042     EL_GATE_2,
3043     EL_GATE_3,
3044     EL_GATE_4,
3045     EL_GATE_1_GRAY,
3046     EL_GATE_2_GRAY,
3047     EL_GATE_3_GRAY,
3048     EL_GATE_4_GRAY,
3049     EL_GATE_1_GRAY_ACTIVE,
3050     EL_GATE_2_GRAY_ACTIVE,
3051     EL_GATE_3_GRAY_ACTIVE,
3052     EL_GATE_4_GRAY_ACTIVE,
3053     EL_EM_GATE_1,
3054     EL_EM_GATE_2,
3055     EL_EM_GATE_3,
3056     EL_EM_GATE_4,
3057     EL_EM_GATE_1_GRAY,
3058     EL_EM_GATE_2_GRAY,
3059     EL_EM_GATE_3_GRAY,
3060     EL_EM_GATE_4_GRAY,
3061     EL_EM_GATE_1_GRAY_ACTIVE,
3062     EL_EM_GATE_2_GRAY_ACTIVE,
3063     EL_EM_GATE_3_GRAY_ACTIVE,
3064     EL_EM_GATE_4_GRAY_ACTIVE,
3065     EL_SWITCHGATE_OPEN,
3066     EL_SWITCHGATE_OPENING,
3067     EL_SWITCHGATE_CLOSED,
3068     EL_SWITCHGATE_CLOSING,
3069     EL_TIMEGATE_OPEN,
3070     EL_TIMEGATE_OPENING,
3071     EL_TIMEGATE_CLOSED,
3072     EL_TIMEGATE_CLOSING,
3073     EL_TUBE_ANY,
3074     EL_TUBE_VERTICAL,
3075     EL_TUBE_HORIZONTAL,
3076     EL_TUBE_VERTICAL_LEFT,
3077     EL_TUBE_VERTICAL_RIGHT,
3078     EL_TUBE_HORIZONTAL_UP,
3079     EL_TUBE_HORIZONTAL_DOWN,
3080     EL_TUBE_LEFT_UP,
3081     EL_TUBE_LEFT_DOWN,
3082     EL_TUBE_RIGHT_UP,
3083     EL_TUBE_RIGHT_DOWN,
3084
3085     -1
3086   };
3087
3088   static int ep_classic_enemy[] =
3089   {
3090     EL_BUG,
3091     EL_SPACESHIP,
3092     EL_BD_BUTTERFLY,
3093     EL_BD_FIREFLY,
3094
3095     EL_YAMYAM,
3096     EL_DARK_YAMYAM,
3097     EL_ROBOT,
3098     EL_PACMAN,
3099     EL_SP_SNIKSNAK,
3100     EL_SP_ELECTRON,
3101
3102     -1
3103   };
3104
3105   static int ep_belt[] =
3106   {
3107     EL_CONVEYOR_BELT_1_LEFT,
3108     EL_CONVEYOR_BELT_1_MIDDLE,
3109     EL_CONVEYOR_BELT_1_RIGHT,
3110     EL_CONVEYOR_BELT_2_LEFT,
3111     EL_CONVEYOR_BELT_2_MIDDLE,
3112     EL_CONVEYOR_BELT_2_RIGHT,
3113     EL_CONVEYOR_BELT_3_LEFT,
3114     EL_CONVEYOR_BELT_3_MIDDLE,
3115     EL_CONVEYOR_BELT_3_RIGHT,
3116     EL_CONVEYOR_BELT_4_LEFT,
3117     EL_CONVEYOR_BELT_4_MIDDLE,
3118     EL_CONVEYOR_BELT_4_RIGHT,
3119
3120     -1
3121   };
3122
3123   static int ep_belt_active[] =
3124   {
3125     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3126     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3127     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3128     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3129     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3130     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3131     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3132     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3133     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3134     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3135     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3136     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3137
3138     -1
3139   };
3140
3141   static int ep_belt_switch[] =
3142   {
3143     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3144     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3145     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3146     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3147     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3148     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3149     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3150     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3151     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3152     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3153     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3154     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3155
3156     -1
3157   };
3158
3159   static int ep_tube[] =
3160   {
3161     EL_TUBE_LEFT_UP,
3162     EL_TUBE_LEFT_DOWN,
3163     EL_TUBE_RIGHT_UP,
3164     EL_TUBE_RIGHT_DOWN,
3165     EL_TUBE_HORIZONTAL,
3166     EL_TUBE_HORIZONTAL_UP,
3167     EL_TUBE_HORIZONTAL_DOWN,
3168     EL_TUBE_VERTICAL,
3169     EL_TUBE_VERTICAL_LEFT,
3170     EL_TUBE_VERTICAL_RIGHT,
3171     EL_TUBE_ANY,
3172
3173     -1
3174   };
3175
3176   static int ep_keygate[] =
3177   {
3178     EL_GATE_1,
3179     EL_GATE_2,
3180     EL_GATE_3,
3181     EL_GATE_4,
3182     EL_GATE_1_GRAY,
3183     EL_GATE_2_GRAY,
3184     EL_GATE_3_GRAY,
3185     EL_GATE_4_GRAY,
3186     EL_GATE_1_GRAY_ACTIVE,
3187     EL_GATE_2_GRAY_ACTIVE,
3188     EL_GATE_3_GRAY_ACTIVE,
3189     EL_GATE_4_GRAY_ACTIVE,
3190     EL_EM_GATE_1,
3191     EL_EM_GATE_2,
3192     EL_EM_GATE_3,
3193     EL_EM_GATE_4,
3194     EL_EM_GATE_1_GRAY,
3195     EL_EM_GATE_2_GRAY,
3196     EL_EM_GATE_3_GRAY,
3197     EL_EM_GATE_4_GRAY,
3198     EL_EM_GATE_1_GRAY_ACTIVE,
3199     EL_EM_GATE_2_GRAY_ACTIVE,
3200     EL_EM_GATE_3_GRAY_ACTIVE,
3201     EL_EM_GATE_4_GRAY_ACTIVE,
3202     EL_EMC_GATE_5,
3203     EL_EMC_GATE_6,
3204     EL_EMC_GATE_7,
3205     EL_EMC_GATE_8,
3206     EL_EMC_GATE_5_GRAY,
3207     EL_EMC_GATE_6_GRAY,
3208     EL_EMC_GATE_7_GRAY,
3209     EL_EMC_GATE_8_GRAY,
3210     EL_EMC_GATE_5_GRAY_ACTIVE,
3211     EL_EMC_GATE_6_GRAY_ACTIVE,
3212     EL_EMC_GATE_7_GRAY_ACTIVE,
3213     EL_EMC_GATE_8_GRAY_ACTIVE,
3214
3215     -1
3216   };
3217
3218   static int ep_amoeboid[] =
3219   {
3220     EL_AMOEBA_DEAD,
3221     EL_AMOEBA_WET,
3222     EL_AMOEBA_DRY,
3223     EL_AMOEBA_FULL,
3224     EL_BD_AMOEBA,
3225     EL_EMC_DRIPPER,
3226
3227     -1
3228   };
3229
3230   static int ep_amoebalive[] =
3231   {
3232     EL_AMOEBA_WET,
3233     EL_AMOEBA_DRY,
3234     EL_AMOEBA_FULL,
3235     EL_BD_AMOEBA,
3236     EL_EMC_DRIPPER,
3237
3238     -1
3239   };
3240
3241   static int ep_has_editor_content[] =
3242   {
3243     EL_PLAYER_1,
3244     EL_PLAYER_2,
3245     EL_PLAYER_3,
3246     EL_PLAYER_4,
3247     EL_SP_MURPHY,
3248     EL_YAMYAM,
3249     EL_AMOEBA_WET,
3250     EL_AMOEBA_DRY,
3251     EL_AMOEBA_FULL,
3252     EL_BD_AMOEBA,
3253     EL_EMC_MAGIC_BALL,
3254     EL_EMC_ANDROID,
3255
3256     -1
3257   };
3258
3259   static int ep_can_turn_each_move[] =
3260   {
3261     /* !!! do something with this one !!! */
3262     -1
3263   };
3264
3265   static int ep_can_grow[] =
3266   {
3267     EL_BD_AMOEBA,
3268     EL_AMOEBA_DROP,
3269     EL_AMOEBA_WET,
3270     EL_AMOEBA_DRY,
3271     EL_AMOEBA_FULL,
3272     EL_GAME_OF_LIFE,
3273     EL_BIOMAZE,
3274     EL_EMC_DRIPPER,
3275
3276     -1
3277   };
3278
3279   static int ep_active_bomb[] =
3280   {
3281     EL_DYNAMITE_ACTIVE,
3282     EL_EM_DYNAMITE_ACTIVE,
3283     EL_DYNABOMB_PLAYER_1_ACTIVE,
3284     EL_DYNABOMB_PLAYER_2_ACTIVE,
3285     EL_DYNABOMB_PLAYER_3_ACTIVE,
3286     EL_DYNABOMB_PLAYER_4_ACTIVE,
3287     EL_SP_DISK_RED_ACTIVE,
3288
3289     -1
3290   };
3291
3292   static int ep_inactive[] =
3293   {
3294     EL_EMPTY,
3295     EL_SAND,
3296     EL_WALL,
3297     EL_BD_WALL,
3298     EL_WALL_SLIPPERY,
3299     EL_STEELWALL,
3300     EL_AMOEBA_DEAD,
3301     EL_QUICKSAND_EMPTY,
3302     EL_STONEBLOCK,
3303     EL_ROBOT_WHEEL,
3304     EL_KEY_1,
3305     EL_KEY_2,
3306     EL_KEY_3,
3307     EL_KEY_4,
3308     EL_EM_KEY_1,
3309     EL_EM_KEY_2,
3310     EL_EM_KEY_3,
3311     EL_EM_KEY_4,
3312     EL_EMC_KEY_5,
3313     EL_EMC_KEY_6,
3314     EL_EMC_KEY_7,
3315     EL_EMC_KEY_8,
3316     EL_GATE_1,
3317     EL_GATE_2,
3318     EL_GATE_3,
3319     EL_GATE_4,
3320     EL_GATE_1_GRAY,
3321     EL_GATE_2_GRAY,
3322     EL_GATE_3_GRAY,
3323     EL_GATE_4_GRAY,
3324     EL_GATE_1_GRAY_ACTIVE,
3325     EL_GATE_2_GRAY_ACTIVE,
3326     EL_GATE_3_GRAY_ACTIVE,
3327     EL_GATE_4_GRAY_ACTIVE,
3328     EL_EM_GATE_1,
3329     EL_EM_GATE_2,
3330     EL_EM_GATE_3,
3331     EL_EM_GATE_4,
3332     EL_EM_GATE_1_GRAY,
3333     EL_EM_GATE_2_GRAY,
3334     EL_EM_GATE_3_GRAY,
3335     EL_EM_GATE_4_GRAY,
3336     EL_EM_GATE_1_GRAY_ACTIVE,
3337     EL_EM_GATE_2_GRAY_ACTIVE,
3338     EL_EM_GATE_3_GRAY_ACTIVE,
3339     EL_EM_GATE_4_GRAY_ACTIVE,
3340     EL_EMC_GATE_5,
3341     EL_EMC_GATE_6,
3342     EL_EMC_GATE_7,
3343     EL_EMC_GATE_8,
3344     EL_EMC_GATE_5_GRAY,
3345     EL_EMC_GATE_6_GRAY,
3346     EL_EMC_GATE_7_GRAY,
3347     EL_EMC_GATE_8_GRAY,
3348     EL_EMC_GATE_5_GRAY_ACTIVE,
3349     EL_EMC_GATE_6_GRAY_ACTIVE,
3350     EL_EMC_GATE_7_GRAY_ACTIVE,
3351     EL_EMC_GATE_8_GRAY_ACTIVE,
3352     EL_DYNAMITE,
3353     EL_EM_DYNAMITE,
3354     EL_INVISIBLE_STEELWALL,
3355     EL_INVISIBLE_WALL,
3356     EL_INVISIBLE_SAND,
3357     EL_LAMP,
3358     EL_LAMP_ACTIVE,
3359     EL_WALL_EMERALD,
3360     EL_WALL_DIAMOND,
3361     EL_WALL_BD_DIAMOND,
3362     EL_WALL_EMERALD_YELLOW,
3363     EL_DYNABOMB_INCREASE_NUMBER,
3364     EL_DYNABOMB_INCREASE_SIZE,
3365     EL_DYNABOMB_INCREASE_POWER,
3366 #if 0
3367     EL_SOKOBAN_OBJECT,
3368 #endif
3369     EL_SOKOBAN_FIELD_EMPTY,
3370     EL_SOKOBAN_FIELD_FULL,
3371     EL_WALL_EMERALD_RED,
3372     EL_WALL_EMERALD_PURPLE,
3373     EL_ACID_POOL_TOPLEFT,
3374     EL_ACID_POOL_TOPRIGHT,
3375     EL_ACID_POOL_BOTTOMLEFT,
3376     EL_ACID_POOL_BOTTOM,
3377     EL_ACID_POOL_BOTTOMRIGHT,
3378     EL_MAGIC_WALL,
3379     EL_MAGIC_WALL_DEAD,
3380     EL_BD_MAGIC_WALL,
3381     EL_BD_MAGIC_WALL_DEAD,
3382     EL_AMOEBA_TO_DIAMOND,
3383     EL_BLOCKED,
3384     EL_SP_EMPTY,
3385     EL_SP_BASE,
3386     EL_SP_PORT_RIGHT,
3387     EL_SP_PORT_DOWN,
3388     EL_SP_PORT_LEFT,
3389     EL_SP_PORT_UP,
3390     EL_SP_GRAVITY_PORT_RIGHT,
3391     EL_SP_GRAVITY_PORT_DOWN,
3392     EL_SP_GRAVITY_PORT_LEFT,
3393     EL_SP_GRAVITY_PORT_UP,
3394     EL_SP_PORT_HORIZONTAL,
3395     EL_SP_PORT_VERTICAL,
3396     EL_SP_PORT_ANY,
3397     EL_SP_DISK_RED,
3398 #if 0
3399     EL_SP_DISK_YELLOW,
3400 #endif
3401     EL_SP_CHIP_SINGLE,
3402     EL_SP_CHIP_LEFT,
3403     EL_SP_CHIP_RIGHT,
3404     EL_SP_CHIP_TOP,
3405     EL_SP_CHIP_BOTTOM,
3406     EL_SP_HARDWARE_GRAY,
3407     EL_SP_HARDWARE_GREEN,
3408     EL_SP_HARDWARE_BLUE,
3409     EL_SP_HARDWARE_RED,
3410     EL_SP_HARDWARE_YELLOW,
3411     EL_SP_HARDWARE_BASE_1,
3412     EL_SP_HARDWARE_BASE_2,
3413     EL_SP_HARDWARE_BASE_3,
3414     EL_SP_HARDWARE_BASE_4,
3415     EL_SP_HARDWARE_BASE_5,
3416     EL_SP_HARDWARE_BASE_6,
3417     EL_SP_GRAVITY_ON_PORT_LEFT,
3418     EL_SP_GRAVITY_ON_PORT_RIGHT,
3419     EL_SP_GRAVITY_ON_PORT_UP,
3420     EL_SP_GRAVITY_ON_PORT_DOWN,
3421     EL_SP_GRAVITY_OFF_PORT_LEFT,
3422     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3423     EL_SP_GRAVITY_OFF_PORT_UP,
3424     EL_SP_GRAVITY_OFF_PORT_DOWN,
3425     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3426     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3427     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3428     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3429     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3430     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3431     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3432     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3433     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3434     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3435     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3436     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3437     EL_SIGN_EXCLAMATION,
3438     EL_SIGN_RADIOACTIVITY,
3439     EL_SIGN_STOP,
3440     EL_SIGN_WHEELCHAIR,
3441     EL_SIGN_PARKING,
3442     EL_SIGN_ONEWAY,
3443     EL_SIGN_HEART,
3444     EL_SIGN_TRIANGLE,
3445     EL_SIGN_ROUND,
3446     EL_SIGN_EXIT,
3447     EL_SIGN_YINYANG,
3448     EL_SIGN_OTHER,
3449     EL_STEELWALL_SLIPPERY,
3450     EL_EMC_STEELWALL_1,
3451     EL_EMC_STEELWALL_2,
3452     EL_EMC_STEELWALL_3,
3453     EL_EMC_STEELWALL_4,
3454     EL_EMC_WALL_SLIPPERY_1,
3455     EL_EMC_WALL_SLIPPERY_2,
3456     EL_EMC_WALL_SLIPPERY_3,
3457     EL_EMC_WALL_SLIPPERY_4,
3458     EL_EMC_WALL_1,
3459     EL_EMC_WALL_2,
3460     EL_EMC_WALL_3,
3461     EL_EMC_WALL_4,
3462     EL_EMC_WALL_5,
3463     EL_EMC_WALL_6,
3464     EL_EMC_WALL_7,
3465     EL_EMC_WALL_8,
3466     EL_EMC_WALL_9,
3467     EL_EMC_WALL_10,
3468     EL_EMC_WALL_11,
3469     EL_EMC_WALL_12,
3470     EL_EMC_WALL_13,
3471     EL_EMC_WALL_14,
3472     EL_EMC_WALL_15,
3473     EL_EMC_WALL_16,
3474
3475     -1
3476   };
3477
3478   static int ep_em_slippery_wall[] =
3479   {
3480     -1
3481   };
3482
3483   static int ep_gfx_crumbled[] =
3484   {
3485     EL_SAND,
3486     EL_LANDMINE,
3487     EL_TRAP,
3488     EL_TRAP_ACTIVE,
3489
3490     -1
3491   };
3492
3493   static int ep_editor_cascade_active[] =
3494   {
3495     EL_INTERNAL_CASCADE_BD_ACTIVE,
3496     EL_INTERNAL_CASCADE_EM_ACTIVE,
3497     EL_INTERNAL_CASCADE_EMC_ACTIVE,
3498     EL_INTERNAL_CASCADE_RND_ACTIVE,
3499     EL_INTERNAL_CASCADE_SB_ACTIVE,
3500     EL_INTERNAL_CASCADE_SP_ACTIVE,
3501     EL_INTERNAL_CASCADE_DC_ACTIVE,
3502     EL_INTERNAL_CASCADE_DX_ACTIVE,
3503     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
3504     EL_INTERNAL_CASCADE_CE_ACTIVE,
3505     EL_INTERNAL_CASCADE_GE_ACTIVE,
3506     EL_INTERNAL_CASCADE_USER_ACTIVE,
3507     EL_INTERNAL_CASCADE_GENERIC_ACTIVE,
3508     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
3509
3510     -1
3511   };
3512
3513   static int ep_editor_cascade_inactive[] =
3514   {
3515     EL_INTERNAL_CASCADE_BD,
3516     EL_INTERNAL_CASCADE_EM,
3517     EL_INTERNAL_CASCADE_EMC,
3518     EL_INTERNAL_CASCADE_RND,
3519     EL_INTERNAL_CASCADE_SB,
3520     EL_INTERNAL_CASCADE_SP,
3521     EL_INTERNAL_CASCADE_DC,
3522     EL_INTERNAL_CASCADE_DX,
3523     EL_INTERNAL_CASCADE_CHARS,
3524     EL_INTERNAL_CASCADE_CE,
3525     EL_INTERNAL_CASCADE_GE,
3526     EL_INTERNAL_CASCADE_USER,
3527     EL_INTERNAL_CASCADE_GENERIC,
3528     EL_INTERNAL_CASCADE_DYNAMIC,
3529
3530     -1
3531   };
3532
3533   static struct
3534   {
3535     int *elements;
3536     int property;
3537   } element_properties[] =
3538   {
3539     { ep_diggable,                      EP_DIGGABLE                     },
3540     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
3541     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
3542     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
3543     { ep_dont_touch,                    EP_DONT_TOUCH                   },
3544     { ep_indestructible,                EP_INDESTRUCTIBLE               },
3545     { ep_slippery,                      EP_SLIPPERY                     },
3546     { ep_can_change,                    EP_CAN_CHANGE                   },
3547     { ep_can_move,                      EP_CAN_MOVE                     },
3548     { ep_can_fall,                      EP_CAN_FALL                     },
3549     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
3550     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
3551     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
3552     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
3553     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
3554     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
3555     { ep_walkable_over,                 EP_WALKABLE_OVER                },
3556     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
3557     { ep_walkable_under,                EP_WALKABLE_UNDER               },
3558     { ep_passable_over,                 EP_PASSABLE_OVER                },
3559     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
3560     { ep_passable_under,                EP_PASSABLE_UNDER               },
3561     { ep_droppable,                     EP_DROPPABLE                    },
3562     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
3563     { ep_pushable,                      EP_PUSHABLE                     },
3564     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
3565     { ep_protected,                     EP_PROTECTED                    },
3566     { ep_throwable,                     EP_THROWABLE                    },
3567     { ep_can_explode,                   EP_CAN_EXPLODE                  },
3568     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
3569
3570     { ep_player,                        EP_PLAYER                       },
3571     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
3572     { ep_switchable,                    EP_SWITCHABLE                   },
3573     { ep_bd_element,                    EP_BD_ELEMENT                   },
3574     { ep_sp_element,                    EP_SP_ELEMENT                   },
3575     { ep_sb_element,                    EP_SB_ELEMENT                   },
3576     { ep_gem,                           EP_GEM                          },
3577     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
3578     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
3579     { ep_food_pig,                      EP_FOOD_PIG                     },
3580     { ep_historic_wall,                 EP_HISTORIC_WALL                },
3581     { ep_historic_solid,                EP_HISTORIC_SOLID               },
3582     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
3583     { ep_belt,                          EP_BELT                         },
3584     { ep_belt_active,                   EP_BELT_ACTIVE                  },
3585     { ep_belt_switch,                   EP_BELT_SWITCH                  },
3586     { ep_tube,                          EP_TUBE                         },
3587     { ep_keygate,                       EP_KEYGATE                      },
3588     { ep_amoeboid,                      EP_AMOEBOID                     },
3589     { ep_amoebalive,                    EP_AMOEBALIVE                   },
3590     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
3591     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
3592     { ep_can_grow,                      EP_CAN_GROW                     },
3593     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
3594     { ep_inactive,                      EP_INACTIVE                     },
3595
3596     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
3597
3598     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
3599
3600     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
3601     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
3602
3603     { NULL,                             -1                              }
3604   };
3605
3606   int i, j, k;
3607
3608   /* always start with reliable default values (element has no properties) */
3609   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3610     for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
3611       SET_PROPERTY(i, j, FALSE);
3612
3613   /* set all base element properties from above array definitions */
3614   for (i = 0; element_properties[i].elements != NULL; i++)
3615     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
3616       SET_PROPERTY((element_properties[i].elements)[j],
3617                    element_properties[i].property, TRUE);
3618
3619   /* copy properties to some elements that are only stored in level file */
3620   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
3621     for (j = 0; copy_properties[j][0] != -1; j++)
3622       if (HAS_PROPERTY(copy_properties[j][0], i))
3623         for (k = 1; k <= 4; k++)
3624           SET_PROPERTY(copy_properties[j][k], i, TRUE);
3625 }
3626
3627 void InitElementPropertiesEngine(int engine_version)
3628 {
3629   static int no_wall_properties[] =
3630   {
3631     EP_DIGGABLE,
3632     EP_COLLECTIBLE_ONLY,
3633     EP_DONT_RUN_INTO,
3634     EP_DONT_COLLIDE_WITH,
3635     EP_CAN_MOVE,
3636     EP_CAN_FALL,
3637     EP_CAN_SMASH_PLAYER,
3638     EP_CAN_SMASH_ENEMIES,
3639     EP_CAN_SMASH_EVERYTHING,
3640     EP_PUSHABLE,
3641
3642     EP_PLAYER,
3643     EP_GEM,
3644     EP_FOOD_DARK_YAMYAM,
3645     EP_FOOD_PENGUIN,
3646     EP_BELT,
3647     EP_BELT_ACTIVE,
3648     EP_TUBE,
3649     EP_AMOEBOID,
3650     EP_AMOEBALIVE,
3651     EP_ACTIVE_BOMB,
3652
3653     EP_ACCESSIBLE,
3654
3655     -1
3656   };
3657
3658   int i, j;
3659
3660   /* important: after initialization in InitElementPropertiesStatic(), the
3661      elements are not again initialized to a default value; therefore all
3662      changes have to make sure that they leave the element with a defined
3663      property (which means that conditional property changes must be set to
3664      a reliable default value before) */
3665
3666 #if 1
3667   /* ---------- recursively resolve group elements ------------------------- */
3668
3669   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3670     for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
3671       element_info[i].in_group[j] = FALSE;
3672
3673   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
3674     resolve_group_element(EL_GROUP_START + i, 0);
3675 #endif
3676
3677   /* set all special, combined or engine dependent element properties */
3678   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
3679   {
3680     /* ---------- INACTIVE ------------------------------------------------- */
3681     SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
3682
3683     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
3684     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
3685                                   IS_WALKABLE_INSIDE(i) ||
3686                                   IS_WALKABLE_UNDER(i)));
3687
3688     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
3689                                   IS_PASSABLE_INSIDE(i) ||
3690                                   IS_PASSABLE_UNDER(i)));
3691
3692     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
3693                                          IS_PASSABLE_OVER(i)));
3694
3695     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
3696                                            IS_PASSABLE_INSIDE(i)));
3697
3698     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
3699                                           IS_PASSABLE_UNDER(i)));
3700
3701     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
3702                                     IS_PASSABLE(i)));
3703
3704     /* ---------- COLLECTIBLE ---------------------------------------------- */
3705     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
3706                                      IS_DROPPABLE(i) ||
3707                                      IS_THROWABLE(i)));
3708
3709     /* ---------- SNAPPABLE ------------------------------------------------ */
3710     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
3711                                    IS_COLLECTIBLE(i) ||
3712                                    IS_SWITCHABLE(i) ||
3713                                    i == EL_BD_ROCK));
3714
3715     /* ---------- WALL ----------------------------------------------------- */
3716     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
3717
3718     for (j = 0; no_wall_properties[j] != -1; j++)
3719       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
3720           i >= EL_FIRST_RUNTIME_UNREAL)
3721         SET_PROPERTY(i, EP_WALL, FALSE);
3722
3723     if (IS_HISTORIC_WALL(i))
3724       SET_PROPERTY(i, EP_WALL, TRUE);
3725
3726     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
3727     if (engine_version < VERSION_IDENT(2,2,0,0))
3728       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
3729     else
3730       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
3731                                              !IS_DIGGABLE(i) &&
3732                                              !IS_COLLECTIBLE(i)));
3733
3734     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
3735
3736     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
3737       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
3738     else
3739       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
3740                                             IS_INDESTRUCTIBLE(i)));
3741
3742     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
3743     if (i == EL_FLAMES)
3744       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
3745     else if (engine_version < VERSION_IDENT(2,2,0,0))
3746       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
3747     else
3748       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
3749                                            (!IS_WALKABLE(i) ||
3750                                             IS_PROTECTED(i))));
3751
3752     if (IS_CUSTOM_ELEMENT(i))
3753     {
3754       /* these are additional properties which are initially false when set */
3755
3756       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
3757       if (DONT_TOUCH(i))
3758         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
3759       if (DONT_COLLIDE_WITH(i))
3760         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
3761
3762       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
3763       if (CAN_SMASH_EVERYTHING(i))
3764         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
3765       if (CAN_SMASH_ENEMIES(i))
3766         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
3767     }
3768
3769     /* ---------- CAN_SMASH ------------------------------------------------ */
3770     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
3771                                    CAN_SMASH_ENEMIES(i) ||
3772                                    CAN_SMASH_EVERYTHING(i)));
3773
3774     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
3775     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
3776                                              EXPLODES_BY_FIRE(i)));
3777
3778     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
3779     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
3780                                              EXPLODES_SMASHED(i)));
3781
3782     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
3783     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
3784                                             EXPLODES_IMPACT(i)));
3785
3786     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
3787     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
3788
3789     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
3790     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
3791                                                   i == EL_BLACK_ORB));
3792
3793     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
3794     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
3795                                               CAN_MOVE(i) ||
3796                                               IS_CUSTOM_ELEMENT(i)));
3797
3798     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
3799     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
3800                                                  i == EL_SP_ELECTRON));
3801
3802     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
3803     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
3804       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
3805                    getMoveIntoAcidProperty(&level, i));
3806
3807     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
3808     if (MAYBE_DONT_COLLIDE_WITH(i))
3809       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
3810                    getDontCollideWithProperty(&level, i));
3811
3812     /* ---------- SP_PORT -------------------------------------------------- */
3813     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
3814                                  IS_PASSABLE_INSIDE(i)));
3815
3816     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
3817     for (j = 0; j < level.num_android_clone_elements; j++)
3818       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
3819                    (i != EL_EMPTY &&
3820                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
3821
3822     /* ---------- CAN_CHANGE ----------------------------------------------- */
3823     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
3824     for (j = 0; j < element_info[i].num_change_pages; j++)
3825       if (element_info[i].change_page[j].can_change)
3826         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
3827
3828     /* ---------- HAS_ACTION ----------------------------------------------- */
3829     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
3830     for (j = 0; j < element_info[i].num_change_pages; j++)
3831       if (element_info[i].change_page[j].has_action)
3832         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
3833
3834     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
3835     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
3836                                                   HAS_ACTION(i)));
3837
3838     /* ---------- GFX_CRUMBLED --------------------------------------------- */
3839 #if 1
3840     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3841                  element_info[i].crumbled[ACTION_DEFAULT] !=
3842                  element_info[i].graphic[ACTION_DEFAULT]);
3843 #else
3844     /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
3845     SET_PROPERTY(i, EP_GFX_CRUMBLED,
3846                  element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
3847 #endif
3848
3849     /* ---------- EDITOR_CASCADE ------------------------------------------- */
3850     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
3851                                         IS_EDITOR_CASCADE_INACTIVE(i)));
3852   }
3853
3854   /* dynamically adjust element properties according to game engine version */
3855   {
3856     static int ep_em_slippery_wall[] =
3857     {
3858       EL_STEELWALL,
3859       EL_WALL,
3860       EL_EXPANDABLE_WALL,
3861       EL_EXPANDABLE_WALL_HORIZONTAL,
3862       EL_EXPANDABLE_WALL_VERTICAL,
3863       EL_EXPANDABLE_WALL_ANY,
3864       -1
3865     };
3866
3867     /* special EM style gems behaviour */
3868     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
3869       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
3870                    level.em_slippery_gems);
3871
3872     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
3873     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
3874                  (level.em_slippery_gems &&
3875                   engine_version > VERSION_IDENT(2,0,1,0)));
3876   }
3877
3878   /* set default push delay values (corrected since version 3.0.7-1) */
3879   if (engine_version < VERSION_IDENT(3,0,7,1))
3880   {
3881     game.default_push_delay_fixed = 2;
3882     game.default_push_delay_random = 8;
3883   }
3884   else
3885   {
3886     game.default_push_delay_fixed = 8;
3887     game.default_push_delay_random = 8;
3888   }
3889
3890   /* set uninitialized push delay values of custom elements in older levels */
3891   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3892   {
3893     int element = EL_CUSTOM_START + i;
3894
3895     if (element_info[element].push_delay_fixed == -1)
3896       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
3897     if (element_info[element].push_delay_random == -1)
3898       element_info[element].push_delay_random = game.default_push_delay_random;
3899   }
3900
3901   /* set some other uninitialized values of custom elements in older levels */
3902   if (engine_version < VERSION_IDENT(3,1,0,0))
3903   {
3904     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3905     {
3906       int element = EL_CUSTOM_START + i;
3907
3908       element_info[element].access_direction = MV_ALL_DIRECTIONS;
3909
3910       element_info[element].explosion_delay = 17;
3911       element_info[element].ignition_delay = 8;
3912     }
3913   }
3914
3915 #if 0
3916   /* set element properties that were handled incorrectly in older levels */
3917   if (engine_version < VERSION_IDENT(3,1,0,0))
3918   {
3919     SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
3920     SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
3921   }
3922 #endif
3923
3924   /* this is needed because some graphics depend on element properties */
3925   if (game_status == GAME_MODE_PLAYING)
3926     InitElementGraphicInfo();
3927 }
3928
3929 static void InitGlobal()
3930 {
3931   int i;
3932
3933   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
3934   {
3935     /* check if element_name_info entry defined for each element in "main.h" */
3936     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
3937       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
3938
3939     element_info[i].token_name = element_name_info[i].token_name;
3940     element_info[i].class_name = element_name_info[i].class_name;
3941     element_info[i].editor_description=element_name_info[i].editor_description;
3942   }
3943
3944   global.autoplay_leveldir = NULL;
3945   global.convert_leveldir = NULL;
3946
3947   global.frames_per_second = 0;
3948   global.fps_slowdown = FALSE;
3949   global.fps_slowdown_factor = 1;
3950 }
3951
3952 void Execute_Command(char *command)
3953 {
3954   int i;
3955
3956   if (strcmp(command, "print graphicsinfo.conf") == 0)
3957   {
3958     printf("# You can configure additional/alternative image files here.\n");
3959     printf("# (The entries below are default and therefore commented out.)\n");
3960     printf("\n");
3961     printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
3962     printf("\n");
3963     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3964     printf("\n");
3965
3966     for (i = 0; image_config[i].token != NULL; i++)
3967       printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
3968                                               image_config[i].value));
3969
3970     exit(0);
3971   }
3972   else if (strcmp(command, "print soundsinfo.conf") == 0)
3973   {
3974     printf("# You can configure additional/alternative sound files here.\n");
3975     printf("# (The entries below are default and therefore commented out.)\n");
3976     printf("\n");
3977     printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
3978     printf("\n");
3979     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3980     printf("\n");
3981
3982     for (i = 0; sound_config[i].token != NULL; i++)
3983       printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
3984                                               sound_config[i].value));
3985
3986     exit(0);
3987   }
3988   else if (strcmp(command, "print musicinfo.conf") == 0)
3989   {
3990     printf("# You can configure additional/alternative music files here.\n");
3991     printf("# (The entries below are default and therefore commented out.)\n");
3992     printf("\n");
3993     printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
3994     printf("\n");
3995     printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
3996     printf("\n");
3997
3998     for (i = 0; music_config[i].token != NULL; i++)
3999       printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
4000                                               music_config[i].value));
4001
4002     exit(0);
4003   }
4004   else if (strcmp(command, "print editorsetup.conf") == 0)
4005   {
4006     printf("# You can configure your personal editor element list here.\n");
4007     printf("# (The entries below are default and therefore commented out.)\n");
4008     printf("\n");
4009
4010     /* this is needed to be able to check element list for cascade elements */
4011     InitElementPropertiesStatic();
4012     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4013
4014     PrintEditorElementList();
4015
4016     exit(0);
4017   }
4018   else if (strcmp(command, "print helpanim.conf") == 0)
4019   {
4020     printf("# You can configure different element help animations here.\n");
4021     printf("# (The entries below are default and therefore commented out.)\n");
4022     printf("\n");
4023
4024     for (i = 0; helpanim_config[i].token != NULL; i++)
4025     {
4026       printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4027                                               helpanim_config[i].value));
4028
4029       if (strcmp(helpanim_config[i].token, "end") == 0)
4030         printf("#\n");
4031     }
4032
4033     exit(0);
4034   }
4035   else if (strcmp(command, "print helptext.conf") == 0)
4036   {
4037     printf("# You can configure different element help text here.\n");
4038     printf("# (The entries below are default and therefore commented out.)\n");
4039     printf("\n");
4040
4041     for (i = 0; helptext_config[i].token != NULL; i++)
4042       printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4043                                               helptext_config[i].value));
4044
4045     exit(0);
4046   }
4047   else if (strncmp(command, "dump level ", 11) == 0)
4048   {
4049     char *filename = &command[11];
4050
4051     if (!fileExists(filename))
4052       Error(ERR_EXIT, "cannot open file '%s'", filename);
4053
4054     LoadLevelFromFilename(&level, filename);
4055     DumpLevel(&level);
4056
4057     exit(0);
4058   }
4059   else if (strncmp(command, "dump tape ", 10) == 0)
4060   {
4061     char *filename = &command[10];
4062
4063     if (!fileExists(filename))
4064       Error(ERR_EXIT, "cannot open file '%s'", filename);
4065
4066     LoadTapeFromFilename(filename);
4067     DumpTape(&tape);
4068
4069     exit(0);
4070   }
4071   else if (strncmp(command, "autoplay ", 9) == 0)
4072   {
4073     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4074
4075     while (*str_ptr != '\0')                    /* continue parsing string */
4076     {
4077       /* cut leading whitespace from string, replace it by string terminator */
4078       while (*str_ptr == ' ' || *str_ptr == '\t')
4079         *str_ptr++ = '\0';
4080
4081       if (*str_ptr == '\0')                     /* end of string reached */
4082         break;
4083
4084       if (global.autoplay_leveldir == NULL)     /* read level set string */
4085       {
4086         global.autoplay_leveldir = str_ptr;
4087         global.autoplay_all = TRUE;             /* default: play all tapes */
4088
4089         for (i = 0; i < MAX_TAPES_PER_SET; i++)
4090           global.autoplay_level[i] = FALSE;
4091       }
4092       else                                      /* read level number string */
4093       {
4094         int level_nr = atoi(str_ptr);           /* get level_nr value */
4095
4096         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4097           global.autoplay_level[level_nr] = TRUE;
4098
4099         global.autoplay_all = FALSE;
4100       }
4101
4102       /* advance string pointer to the next whitespace (or end of string) */
4103       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4104         str_ptr++;
4105     }
4106   }
4107   else if (strncmp(command, "convert ", 8) == 0)
4108   {
4109     char *str_copy = getStringCopy(&command[8]);
4110     char *str_ptr = strchr(str_copy, ' ');
4111
4112     global.convert_leveldir = str_copy;
4113     global.convert_level_nr = -1;
4114
4115     if (str_ptr != NULL)                        /* level number follows */
4116     {
4117       *str_ptr++ = '\0';                        /* terminate leveldir string */
4118       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
4119     }
4120   }
4121   else
4122   {
4123     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4124   }
4125 }
4126
4127 static void InitSetup()
4128 {
4129   LoadSetup();                                  /* global setup info */
4130
4131   /* set some options from setup file */
4132
4133   if (setup.options.verbose)
4134     options.verbose = TRUE;
4135 }
4136
4137 static void InitGameInfo()
4138 {
4139   game.restart_level = FALSE;
4140 }
4141
4142 static void InitPlayerInfo()
4143 {
4144   int i;
4145
4146   /* choose default local player */
4147   local_player = &stored_player[0];
4148
4149   for (i = 0; i < MAX_PLAYERS; i++)
4150     stored_player[i].connected = FALSE;
4151
4152   local_player->connected = TRUE;
4153 }
4154
4155 static void InitArtworkInfo()
4156 {
4157   LoadArtworkInfo();
4158 }
4159
4160 static char *get_string_in_brackets(char *string)
4161 {
4162   char *string_in_brackets = checked_malloc(strlen(string) + 3);
4163
4164   sprintf(string_in_brackets, "[%s]", string);
4165
4166   return string_in_brackets;
4167 }
4168
4169 static char *get_level_id_suffix(int id_nr)
4170 {
4171   char *id_suffix = checked_malloc(1 + 3 + 1);
4172
4173   if (id_nr < 0 || id_nr > 999)
4174     id_nr = 0;
4175
4176   sprintf(id_suffix, ".%03d", id_nr);
4177
4178   return id_suffix;
4179 }
4180
4181 #if 0
4182 static char *get_element_class_token(int element)
4183 {
4184   char *element_class_name = element_info[element].class_name;
4185   char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
4186
4187   sprintf(element_class_token, "[%s]", element_class_name);
4188
4189   return element_class_token;
4190 }
4191
4192 static char *get_action_class_token(int action)
4193 {
4194   char *action_class_name = &element_action_info[action].suffix[1];
4195   char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
4196
4197   sprintf(action_class_token, "[%s]", action_class_name);
4198
4199   return action_class_token;
4200 }
4201 #endif
4202
4203 static void InitArtworkConfig()
4204 {
4205   static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
4206   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
4207   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4208   static char *action_id_suffix[NUM_ACTIONS + 1];
4209   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4210   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4211   static char *level_id_suffix[MAX_LEVELS + 1];
4212   static char *dummy[1] = { NULL };
4213   static char *ignore_generic_tokens[] =
4214   {
4215     "name",
4216     "sort_priority",
4217     NULL
4218   };
4219   static char **ignore_image_tokens;
4220   static char **ignore_sound_tokens;
4221   static char **ignore_music_tokens;
4222   int num_ignore_generic_tokens;
4223   int num_ignore_image_tokens;
4224   int num_ignore_sound_tokens;
4225   int num_ignore_music_tokens;
4226   int i;
4227
4228   /* dynamically determine list of generic tokens to be ignored */
4229   num_ignore_generic_tokens = 0;
4230   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
4231     num_ignore_generic_tokens++;
4232
4233   /* dynamically determine list of image tokens to be ignored */
4234   num_ignore_image_tokens = num_ignore_generic_tokens;
4235   for (i = 0; image_config_vars[i].token != NULL; i++)
4236     num_ignore_image_tokens++;
4237   ignore_image_tokens =
4238     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
4239   for (i = 0; i < num_ignore_generic_tokens; i++)
4240     ignore_image_tokens[i] = ignore_generic_tokens[i];
4241   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
4242     ignore_image_tokens[num_ignore_generic_tokens + i] =
4243       image_config_vars[i].token;
4244   ignore_image_tokens[num_ignore_image_tokens] = NULL;
4245
4246   /* dynamically determine list of sound tokens to be ignored */
4247   num_ignore_sound_tokens = num_ignore_generic_tokens;
4248   ignore_sound_tokens =
4249     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
4250   for (i = 0; i < num_ignore_generic_tokens; i++)
4251     ignore_sound_tokens[i] = ignore_generic_tokens[i];
4252   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
4253
4254   /* dynamically determine list of music tokens to be ignored */
4255   num_ignore_music_tokens = num_ignore_generic_tokens;
4256   ignore_music_tokens =
4257     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
4258   for (i = 0; i < num_ignore_generic_tokens; i++)
4259     ignore_music_tokens[i] = ignore_generic_tokens[i];
4260   ignore_music_tokens[num_ignore_music_tokens] = NULL;
4261
4262   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4263     image_id_prefix[i] = element_info[i].token_name;
4264   for (i = 0; i < NUM_FONTS; i++)
4265     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
4266   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
4267
4268   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4269     sound_id_prefix[i] = element_info[i].token_name;
4270   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4271     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
4272       get_string_in_brackets(element_info[i].class_name);
4273   sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
4274
4275   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
4276     music_id_prefix[i] = music_prefix_info[i].prefix;
4277   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
4278
4279   for (i = 0; i < NUM_ACTIONS; i++)
4280     action_id_suffix[i] = element_action_info[i].suffix;
4281   action_id_suffix[NUM_ACTIONS] = NULL;
4282
4283   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
4284     direction_id_suffix[i] = element_direction_info[i].suffix;
4285   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
4286
4287   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
4288     special_id_suffix[i] = special_suffix_info[i].suffix;
4289   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
4290
4291   for (i = 0; i < MAX_LEVELS; i++)
4292     level_id_suffix[i] = get_level_id_suffix(i);
4293   level_id_suffix[MAX_LEVELS] = NULL;
4294
4295   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
4296                 image_id_prefix, action_id_suffix, direction_id_suffix,
4297                 special_id_suffix, ignore_image_tokens);
4298   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
4299                 sound_id_prefix, action_id_suffix, dummy,
4300                 special_id_suffix, ignore_sound_tokens);
4301   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
4302                 music_id_prefix, special_id_suffix, level_id_suffix,
4303                 dummy, ignore_music_tokens);
4304 }
4305
4306 static void InitMixer()
4307 {
4308   OpenAudio();
4309   StartMixer();
4310 }
4311
4312 void InitGfx()
4313 {
4314   char *filename_font_initial = NULL;
4315   Bitmap *bitmap_font_initial = NULL;
4316   int i, j;
4317
4318   /* determine settings for initial font (for displaying startup messages) */
4319   for (i = 0; image_config[i].token != NULL; i++)
4320   {
4321     for (j = 0; j < NUM_INITIAL_FONTS; j++)
4322     {
4323       char font_token[128];
4324       int len_font_token;
4325
4326       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
4327       len_font_token = strlen(font_token);
4328
4329       if (strcmp(image_config[i].token, font_token) == 0)
4330         filename_font_initial = image_config[i].value;
4331       else if (strlen(image_config[i].token) > len_font_token &&
4332                strncmp(image_config[i].token, font_token, len_font_token) == 0)
4333       {
4334         if (strcmp(&image_config[i].token[len_font_token], ".x") == 0)
4335           font_initial[j].src_x = atoi(image_config[i].value);
4336         else if (strcmp(&image_config[i].token[len_font_token], ".y") == 0)
4337           font_initial[j].src_y = atoi(image_config[i].value);
4338         else if (strcmp(&image_config[i].token[len_font_token], ".width") == 0)
4339           font_initial[j].width = atoi(image_config[i].value);
4340         else if (strcmp(&image_config[i].token[len_font_token],".height") == 0)
4341           font_initial[j].height = atoi(image_config[i].value);
4342       }
4343     }
4344   }
4345
4346   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4347   {
4348     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
4349     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
4350   }
4351
4352   if (filename_font_initial == NULL)    /* should not happen */
4353     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
4354
4355   /* create additional image buffers for double-buffering */
4356   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
4357   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
4358
4359   /* initialize screen properties */
4360   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
4361                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
4362                    bitmap_db_field);
4363   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
4364   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
4365   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
4366
4367   bitmap_font_initial = LoadCustomImage(filename_font_initial);
4368
4369   for (j = 0; j < NUM_INITIAL_FONTS; j++)
4370     font_initial[j].bitmap = bitmap_font_initial;
4371
4372   InitFontGraphicInfo();
4373
4374   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
4375   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
4376
4377   DrawInitText("Loading graphics:", 120, FC_GREEN);
4378 }
4379
4380 void InitGfxBackground()
4381 {
4382   int x, y;
4383
4384   drawto = backbuffer;
4385   fieldbuffer = bitmap_db_field;
4386   SetDrawtoField(DRAW_BACKBUFFER);
4387
4388   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
4389              0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
4390   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
4391   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
4392
4393   for (x = 0; x < MAX_BUF_XSIZE; x++)
4394     for (y = 0; y < MAX_BUF_YSIZE; y++)
4395       redraw[x][y] = 0;
4396   redraw_tiles = 0;
4397   redraw_mask = REDRAW_ALL;
4398 }
4399
4400 static void InitLevelInfo()
4401 {
4402   LoadLevelInfo();                              /* global level info */
4403   LoadLevelSetup_LastSeries();                  /* last played series info */
4404   LoadLevelSetup_SeriesInfo();                  /* last played level info */
4405 }
4406
4407 void InitLevelArtworkInfo()
4408 {
4409   LoadLevelArtworkInfo();
4410 }
4411
4412 static void InitImages()
4413 {
4414   setLevelArtworkDir(artwork.gfx_first);
4415
4416 #if 0
4417   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
4418          leveldir_current->identifier,
4419          artwork.gfx_current_identifier,
4420          artwork.gfx_current->identifier,
4421          leveldir_current->graphics_set,
4422          leveldir_current->graphics_path);
4423 #endif
4424
4425   ReloadCustomImages();
4426
4427   LoadCustomElementDescriptions();
4428   LoadSpecialMenuDesignSettings();
4429
4430   ReinitializeGraphics();
4431 }
4432
4433 static void InitSound(char *identifier)
4434 {
4435   if (identifier == NULL)
4436     identifier = artwork.snd_current->identifier;
4437
4438   /* set artwork path to send it to the sound server process */
4439   setLevelArtworkDir(artwork.snd_first);
4440
4441   InitReloadCustomSounds(identifier);
4442   ReinitializeSounds();
4443 }
4444
4445 static void InitMusic(char *identifier)
4446 {
4447   if (identifier == NULL)
4448     identifier = artwork.mus_current->identifier;
4449
4450   /* set artwork path to send it to the sound server process */
4451   setLevelArtworkDir(artwork.mus_first);
4452
4453   InitReloadCustomMusic(identifier);
4454   ReinitializeMusic();
4455 }
4456
4457 void InitNetworkServer()
4458 {
4459 #if defined(NETWORK_AVALIABLE)
4460   int nr_wanted;
4461 #endif
4462
4463   if (!options.network)
4464     return;
4465
4466 #if defined(NETWORK_AVALIABLE)
4467   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
4468
4469   if (!ConnectToServer(options.server_host, options.server_port))
4470     Error(ERR_EXIT, "cannot connect to network game server");
4471
4472   SendToServer_PlayerName(setup.player_name);
4473   SendToServer_ProtocolVersion();
4474
4475   if (nr_wanted)
4476     SendToServer_NrWanted(nr_wanted);
4477 #endif
4478 }
4479
4480 static char *getNewArtworkIdentifier(int type)
4481 {
4482   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
4483   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
4484   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
4485   static boolean initialized[3] = { FALSE, FALSE, FALSE };
4486   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
4487   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
4488   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
4489   char *leveldir_identifier = leveldir_current->identifier;
4490 #if 1
4491   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
4492   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
4493 #else
4494   char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
4495 #endif
4496   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
4497   char *artwork_current_identifier;
4498   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
4499
4500   /* leveldir_current may be invalid (level group, parent link) */
4501   if (!validLevelSeries(leveldir_current))
4502     return NULL;
4503
4504   /* 1st step: determine artwork set to be activated in descending order:
4505      --------------------------------------------------------------------
4506      1. setup artwork (when configured to override everything else)
4507      2. artwork set configured in "levelinfo.conf" of current level set
4508         (artwork in level directory will have priority when loading later)
4509      3. artwork in level directory (stored in artwork sub-directory)
4510      4. setup artwork (currently configured in setup menu) */
4511
4512   if (setup_override_artwork)
4513     artwork_current_identifier = setup_artwork_set;
4514   else if (leveldir_artwork_set != NULL)
4515     artwork_current_identifier = leveldir_artwork_set;
4516   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
4517     artwork_current_identifier = leveldir_identifier;
4518   else
4519     artwork_current_identifier = setup_artwork_set;
4520
4521
4522   /* 2nd step: check if it is really needed to reload artwork set
4523      ------------------------------------------------------------ */
4524
4525 #if 0
4526   if (type == ARTWORK_TYPE_GRAPHICS)
4527     printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
4528            artwork_new_identifier,
4529            ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4530            artwork_current_identifier,
4531            leveldir_current->graphics_set,
4532            leveldir_current->identifier);
4533 #endif
4534
4535   /* ---------- reload if level set and also artwork set has changed ------- */
4536   if (leveldir_current_identifier[type] != leveldir_identifier &&
4537       (last_has_level_artwork_set[type] || has_level_artwork_set))
4538     artwork_new_identifier = artwork_current_identifier;
4539
4540   leveldir_current_identifier[type] = leveldir_identifier;
4541   last_has_level_artwork_set[type] = has_level_artwork_set;
4542
4543 #if 0
4544   if (type == ARTWORK_TYPE_GRAPHICS)
4545     printf("::: 1: '%s'\n", artwork_new_identifier);
4546 #endif
4547
4548   /* ---------- reload if "override artwork" setting has changed ----------- */
4549   if (last_override_level_artwork[type] != setup_override_artwork)
4550     artwork_new_identifier = artwork_current_identifier;
4551
4552   last_override_level_artwork[type] = setup_override_artwork;
4553
4554 #if 0
4555   if (type == ARTWORK_TYPE_GRAPHICS)
4556     printf("::: 2: '%s'\n", artwork_new_identifier);
4557 #endif
4558
4559   /* ---------- reload if current artwork identifier has changed ----------- */
4560   if (strcmp(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
4561              artwork_current_identifier) != 0)
4562     artwork_new_identifier = artwork_current_identifier;
4563
4564   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
4565
4566 #if 0
4567   if (type == ARTWORK_TYPE_GRAPHICS)
4568     printf("::: 3: '%s'\n", artwork_new_identifier);
4569 #endif
4570
4571   /* ---------- do not reload directly after starting ---------------------- */
4572   if (!initialized[type])
4573     artwork_new_identifier = NULL;
4574
4575   initialized[type] = TRUE;
4576
4577 #if 0
4578   if (type == ARTWORK_TYPE_GRAPHICS)
4579     printf("::: 4: '%s'\n", artwork_new_identifier);
4580 #endif
4581
4582 #if 0
4583   if (type == ARTWORK_TYPE_GRAPHICS)
4584     printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
4585            artwork.gfx_current_identifier, artwork_current_identifier,
4586            artwork.gfx_current->identifier, leveldir_current->graphics_set,
4587            artwork_new_identifier);
4588 #endif
4589
4590   return artwork_new_identifier;
4591 }
4592
4593 void ReloadCustomArtwork(int force_reload)
4594 {
4595   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
4596   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
4597   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
4598   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
4599   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
4600   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
4601   boolean redraw_screen = FALSE;
4602
4603   if (gfx_new_identifier != NULL || force_reload_gfx)
4604   {
4605 #if 0
4606     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
4607            artwork.gfx_current_identifier,
4608            gfx_new_identifier,
4609            artwork.gfx_current->identifier,
4610            leveldir_current->graphics_set);
4611 #endif
4612
4613     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4614
4615     InitImages();
4616
4617     redraw_screen = TRUE;
4618   }
4619
4620   if (snd_new_identifier != NULL || force_reload_snd)
4621   {
4622     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4623
4624     InitSound(snd_new_identifier);
4625
4626     redraw_screen = TRUE;
4627   }
4628
4629   if (mus_new_identifier != NULL || force_reload_mus)
4630   {
4631     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
4632
4633     InitMusic(mus_new_identifier);
4634
4635     redraw_screen = TRUE;
4636   }
4637
4638   if (redraw_screen)
4639   {
4640     InitGfxBackground();
4641
4642     /* force redraw of (open or closed) door graphics */
4643     SetDoorState(DOOR_OPEN_ALL);
4644     CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
4645   }
4646 }
4647
4648 void KeyboardAutoRepeatOffUnlessAutoplay()
4649 {
4650   if (global.autoplay_leveldir == NULL)
4651     KeyboardAutoRepeatOff();
4652 }
4653
4654
4655 /* ========================================================================= */
4656 /* OpenAll()                                                                 */
4657 /* ========================================================================= */
4658
4659 void OpenAll()
4660 {
4661   InitGlobal();                 /* initialize some global variables */
4662
4663   if (options.execute_command)
4664     Execute_Command(options.execute_command);
4665
4666   if (options.serveronly)
4667   {
4668 #if defined(PLATFORM_UNIX)
4669     NetworkServer(options.server_port, options.serveronly);
4670 #else
4671     Error(ERR_WARN, "networking only supported in Unix version");
4672 #endif
4673
4674     exit(0);                    /* never reached, server loops forever */
4675   }
4676
4677   InitSetup();
4678
4679   InitGameInfo();
4680   InitPlayerInfo();
4681   InitArtworkInfo();            /* needed before loading gfx, sound & music */
4682   InitArtworkConfig();          /* needed before forking sound child process */
4683   InitMixer();
4684
4685   InitCounter();
4686
4687   InitRND(NEW_RANDOMIZE);
4688   InitSimpleRND(NEW_RANDOMIZE);
4689
4690   InitJoysticks();
4691
4692   InitVideoDisplay();
4693   InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
4694                   setup.fullscreen);
4695
4696   InitEventFilter(FilterMouseMotionEvents);
4697
4698   InitElementPropertiesStatic();
4699   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4700
4701   InitGfx();
4702
4703   InitLevelInfo();
4704   InitLevelArtworkInfo();
4705
4706   InitImages();                 /* needs to know current level directory */
4707   InitSound(NULL);              /* needs to know current level directory */
4708   InitMusic(NULL);              /* needs to know current level directory */
4709
4710   InitGfxBackground();
4711
4712   if (global.autoplay_leveldir)
4713   {
4714     AutoPlayTape();
4715     return;
4716   }
4717   else if (global.convert_leveldir)
4718   {
4719     ConvertLevels();
4720     return;
4721   }
4722
4723   game_status = GAME_MODE_MAIN;
4724
4725 #if 1
4726   em_open_all();
4727 #endif
4728
4729   DrawMainMenu();
4730
4731   InitNetworkServer();
4732 }
4733
4734 void CloseAllAndExit(int exit_value)
4735 {
4736   StopSounds();
4737   FreeAllSounds();
4738   FreeAllMusic();
4739   CloseAudio();         /* called after freeing sounds (needed for SDL) */
4740
4741 #if 1
4742   em_close_all();
4743 #endif
4744
4745   FreeAllImages();
4746
4747 #if defined(TARGET_SDL)
4748   if (network_server)   /* terminate network server */
4749     SDL_KillThread(server_thread);
4750 #endif
4751
4752   CloseVideoDisplay();
4753   ClosePlatformDependentStuff();
4754
4755   exit(exit_value);
4756 }