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