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