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