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