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