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