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