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