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