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