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