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