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