removed reloading artwork set for changed level set if not required (again)
[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
2240 static void InitGameInfoFromArtworkInfo(void)
2241 {
2242   // special case: store initial value of custom artwork setting
2243   game.use_masked_elements_initial = game.use_masked_elements;
2244 }
2245
2246 static void ReinitializeGraphics(void)
2247 {
2248   print_timestamp_init("ReinitializeGraphics");
2249
2250   InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2251
2252   InitGraphicInfo();                    // graphic properties mapping
2253   print_timestamp_time("InitGraphicInfo");
2254   InitElementGraphicInfo();             // element game graphic mapping
2255   print_timestamp_time("InitElementGraphicInfo");
2256   InitElementSpecialGraphicInfo();      // element special graphic mapping
2257   print_timestamp_time("InitElementSpecialGraphicInfo");
2258
2259   InitElementSmallImages();             // scale elements to all needed sizes
2260   print_timestamp_time("InitElementSmallImages");
2261   InitScaledImages();                   // scale all other images, if needed
2262   print_timestamp_time("InitScaledImages");
2263   InitBitmapPointers();                 // set standard size bitmap pointers
2264   print_timestamp_time("InitBitmapPointers");
2265   InitFontGraphicInfo();                // initialize text drawing functions
2266   print_timestamp_time("InitFontGraphicInfo");
2267   InitGlobalAnimGraphicInfo();          // initialize global animation config
2268   print_timestamp_time("InitGlobalAnimGraphicInfo");
2269
2270   InitImageTextures();                  // create textures for certain images
2271   print_timestamp_time("InitImageTextures");
2272
2273   InitGraphicInfo_EM();                 // graphic mapping for EM engine
2274   print_timestamp_time("InitGraphicInfo_EM");
2275
2276   InitGraphicCompatibilityInfo();
2277   print_timestamp_time("InitGraphicCompatibilityInfo");
2278
2279   SetMainBackgroundImage(IMG_BACKGROUND);
2280   print_timestamp_time("SetMainBackgroundImage");
2281   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2282   print_timestamp_time("SetDoorBackgroundImage");
2283
2284   InitGadgets();
2285   print_timestamp_time("InitGadgets");
2286   InitDoors();
2287   print_timestamp_time("InitDoors");
2288
2289   InitGameInfoFromArtworkInfo();
2290
2291   print_timestamp_done("ReinitializeGraphics");
2292 }
2293
2294 static void ReinitializeSounds(void)
2295 {
2296   InitSoundInfo();              // sound properties mapping
2297   InitElementSoundInfo();       // element game sound mapping
2298   InitGameModeSoundInfo();      // game mode sound mapping
2299   InitGlobalAnimSoundInfo();    // global animation sound settings
2300
2301   InitPlayLevelSound();         // internal game sound settings
2302 }
2303
2304 static void ReinitializeMusic(void)
2305 {
2306   InitMusicInfo();              // music properties mapping
2307   InitGameModeMusicInfo();      // game mode music mapping
2308   InitGlobalAnimMusicInfo();    // global animation music settings
2309 }
2310
2311 static int get_special_property_bit(int element, int property_bit_nr)
2312 {
2313   struct PropertyBitInfo
2314   {
2315     int element;
2316     int bit_nr;
2317   };
2318
2319   static struct PropertyBitInfo pb_can_move_into_acid[] =
2320   {
2321     // the player may be able fall into acid when gravity is activated
2322     { EL_PLAYER_1,              0       },
2323     { EL_PLAYER_2,              0       },
2324     { EL_PLAYER_3,              0       },
2325     { EL_PLAYER_4,              0       },
2326     { EL_SP_MURPHY,             0       },
2327     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2328
2329     // all elements that can move may be able to also move into acid
2330     { EL_BUG,                   1       },
2331     { EL_BUG_LEFT,              1       },
2332     { EL_BUG_RIGHT,             1       },
2333     { EL_BUG_UP,                1       },
2334     { EL_BUG_DOWN,              1       },
2335     { EL_SPACESHIP,             2       },
2336     { EL_SPACESHIP_LEFT,        2       },
2337     { EL_SPACESHIP_RIGHT,       2       },
2338     { EL_SPACESHIP_UP,          2       },
2339     { EL_SPACESHIP_DOWN,        2       },
2340     { EL_BD_BUTTERFLY,          3       },
2341     { EL_BD_BUTTERFLY_LEFT,     3       },
2342     { EL_BD_BUTTERFLY_RIGHT,    3       },
2343     { EL_BD_BUTTERFLY_UP,       3       },
2344     { EL_BD_BUTTERFLY_DOWN,     3       },
2345     { EL_BD_FIREFLY,            4       },
2346     { EL_BD_FIREFLY_LEFT,       4       },
2347     { EL_BD_FIREFLY_RIGHT,      4       },
2348     { EL_BD_FIREFLY_UP,         4       },
2349     { EL_BD_FIREFLY_DOWN,       4       },
2350     { EL_YAMYAM,                5       },
2351     { EL_YAMYAM_LEFT,           5       },
2352     { EL_YAMYAM_RIGHT,          5       },
2353     { EL_YAMYAM_UP,             5       },
2354     { EL_YAMYAM_DOWN,           5       },
2355     { EL_DARK_YAMYAM,           6       },
2356     { EL_ROBOT,                 7       },
2357     { EL_PACMAN,                8       },
2358     { EL_PACMAN_LEFT,           8       },
2359     { EL_PACMAN_RIGHT,          8       },
2360     { EL_PACMAN_UP,             8       },
2361     { EL_PACMAN_DOWN,           8       },
2362     { EL_MOLE,                  9       },
2363     { EL_MOLE_LEFT,             9       },
2364     { EL_MOLE_RIGHT,            9       },
2365     { EL_MOLE_UP,               9       },
2366     { EL_MOLE_DOWN,             9       },
2367     { EL_PENGUIN,               10      },
2368     { EL_PIG,                   11      },
2369     { EL_DRAGON,                12      },
2370     { EL_SATELLITE,             13      },
2371     { EL_SP_SNIKSNAK,           14      },
2372     { EL_SP_ELECTRON,           15      },
2373     { EL_BALLOON,               16      },
2374     { EL_SPRING,                17      },
2375     { EL_SPRING_LEFT,           17      },
2376     { EL_SPRING_RIGHT,          17      },
2377     { EL_EMC_ANDROID,           18      },
2378
2379     { -1,                       -1      },
2380   };
2381
2382   static struct PropertyBitInfo pb_dont_collide_with[] =
2383   {
2384     { EL_SP_SNIKSNAK,           0       },
2385     { EL_SP_ELECTRON,           1       },
2386
2387     { -1,                       -1      },
2388   };
2389
2390   static struct
2391   {
2392     int bit_nr;
2393     struct PropertyBitInfo *pb_info;
2394   } pb_definition[] =
2395   {
2396     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2397     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2398
2399     { -1,                       NULL                    },
2400   };
2401
2402   struct PropertyBitInfo *pb_info = NULL;
2403   int i;
2404
2405   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2406     if (pb_definition[i].bit_nr == property_bit_nr)
2407       pb_info = pb_definition[i].pb_info;
2408
2409   if (pb_info == NULL)
2410     return -1;
2411
2412   for (i = 0; pb_info[i].element != -1; i++)
2413     if (pb_info[i].element == element)
2414       return pb_info[i].bit_nr;
2415
2416   return -1;
2417 }
2418
2419 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2420                          boolean property_value)
2421 {
2422   int bit_nr = get_special_property_bit(element, property_bit_nr);
2423
2424   if (bit_nr > -1)
2425   {
2426     if (property_value)
2427       *bitfield |=  (1 << bit_nr);
2428     else
2429       *bitfield &= ~(1 << bit_nr);
2430   }
2431 }
2432
2433 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2434 {
2435   int bit_nr = get_special_property_bit(element, property_bit_nr);
2436
2437   if (bit_nr > -1)
2438     return ((*bitfield & (1 << bit_nr)) != 0);
2439
2440   return FALSE;
2441 }
2442
2443 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2444 {
2445   static int group_nr;
2446   static struct ElementGroupInfo *group;
2447   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2448   int i;
2449
2450   if (actual_group == NULL)                     // not yet initialized
2451     return;
2452
2453   if (recursion_depth > NUM_GROUP_ELEMENTS)     // recursion too deep
2454   {
2455     Warn("recursion too deep when resolving group element %d",
2456           group_element - EL_GROUP_START + 1);
2457
2458     // replace element which caused too deep recursion by question mark
2459     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2460
2461     return;
2462   }
2463
2464   if (recursion_depth == 0)                     // initialization
2465   {
2466     group = actual_group;
2467     group_nr = GROUP_NR(group_element);
2468
2469     group->num_elements_resolved = 0;
2470     group->choice_pos = 0;
2471
2472     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2473       element_info[i].in_group[group_nr] = FALSE;
2474   }
2475
2476   for (i = 0; i < actual_group->num_elements; i++)
2477   {
2478     int element = actual_group->element[i];
2479
2480     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2481       break;
2482
2483     if (IS_GROUP_ELEMENT(element))
2484       ResolveGroupElementExt(element, recursion_depth + 1);
2485     else
2486     {
2487       group->element_resolved[group->num_elements_resolved++] = element;
2488       element_info[element].in_group[group_nr] = TRUE;
2489     }
2490   }
2491 }
2492
2493 void ResolveGroupElement(int group_element)
2494 {
2495   ResolveGroupElementExt(group_element, 0);
2496 }
2497
2498 void InitElementPropertiesStatic(void)
2499 {
2500   static boolean clipboard_elements_initialized = FALSE;
2501
2502   static int ep_diggable[] =
2503   {
2504     EL_SAND,
2505     EL_SP_BASE,
2506     EL_SP_BUGGY_BASE,
2507     EL_SP_BUGGY_BASE_ACTIVATING,
2508     EL_TRAP,
2509     EL_INVISIBLE_SAND,
2510     EL_INVISIBLE_SAND_ACTIVE,
2511     EL_EMC_GRASS,
2512
2513     // !!! currently not diggable, but handled by 'ep_dont_run_into' !!!
2514     // (if amoeba can grow into anything diggable, maybe keep these out)
2515 #if 0
2516     EL_LANDMINE,
2517     EL_DC_LANDMINE,
2518     EL_TRAP_ACTIVE,
2519     EL_SP_BUGGY_BASE_ACTIVE,
2520     EL_EMC_PLANT,
2521 #endif
2522
2523     -1
2524   };
2525
2526   static int ep_collectible_only[] =
2527   {
2528     EL_BD_DIAMOND,
2529     EL_EMERALD,
2530     EL_DIAMOND,
2531     EL_EMERALD_YELLOW,
2532     EL_EMERALD_RED,
2533     EL_EMERALD_PURPLE,
2534     EL_KEY_1,
2535     EL_KEY_2,
2536     EL_KEY_3,
2537     EL_KEY_4,
2538     EL_EM_KEY_1,
2539     EL_EM_KEY_2,
2540     EL_EM_KEY_3,
2541     EL_EM_KEY_4,
2542     EL_EMC_KEY_5,
2543     EL_EMC_KEY_6,
2544     EL_EMC_KEY_7,
2545     EL_EMC_KEY_8,
2546     EL_DYNAMITE,
2547     EL_EM_DYNAMITE,
2548     EL_DYNABOMB_INCREASE_NUMBER,
2549     EL_DYNABOMB_INCREASE_SIZE,
2550     EL_DYNABOMB_INCREASE_POWER,
2551     EL_SP_INFOTRON,
2552     EL_SP_DISK_RED,
2553     EL_PEARL,
2554     EL_CRYSTAL,
2555     EL_DC_KEY_WHITE,
2556     EL_SHIELD_NORMAL,
2557     EL_SHIELD_DEADLY,
2558     EL_EXTRA_TIME,
2559     EL_ENVELOPE_1,
2560     EL_ENVELOPE_2,
2561     EL_ENVELOPE_3,
2562     EL_ENVELOPE_4,
2563     EL_SPEED_PILL,
2564     EL_EMC_LENSES,
2565     EL_EMC_MAGNIFIER,
2566
2567 #if 0
2568     // !!! handle separately !!!
2569     EL_DC_LANDMINE,     // deadly when running into, but can be snapped
2570 #endif
2571
2572     -1
2573   };
2574
2575   static int ep_dont_run_into[] =
2576   {
2577     // same elements as in 'ep_dont_touch'
2578     EL_BUG,
2579     EL_SPACESHIP,
2580     EL_BD_BUTTERFLY,
2581     EL_BD_FIREFLY,
2582
2583     // same elements as in 'ep_dont_collide_with'
2584     EL_YAMYAM,
2585     EL_DARK_YAMYAM,
2586     EL_ROBOT,
2587     EL_PACMAN,
2588     EL_SP_SNIKSNAK,
2589     EL_SP_ELECTRON,
2590
2591     // new elements
2592     EL_AMOEBA_DROP,
2593     EL_ACID,
2594
2595     // !!! maybe this should better be handled by 'ep_diggable' !!!
2596 #if 1
2597     EL_LANDMINE,
2598     EL_DC_LANDMINE,
2599     EL_TRAP_ACTIVE,
2600     EL_SP_BUGGY_BASE_ACTIVE,
2601     EL_EMC_PLANT,
2602 #endif
2603
2604     -1
2605   };
2606
2607   static int ep_dont_collide_with[] =
2608   {
2609     // same elements as in 'ep_dont_touch'
2610     EL_BUG,
2611     EL_SPACESHIP,
2612     EL_BD_BUTTERFLY,
2613     EL_BD_FIREFLY,
2614
2615     // new elements
2616     EL_YAMYAM,
2617     EL_DARK_YAMYAM,
2618     EL_ROBOT,
2619     EL_PACMAN,
2620     EL_SP_SNIKSNAK,
2621     EL_SP_ELECTRON,
2622
2623     -1
2624   };
2625
2626   static int ep_dont_touch[] =
2627   {
2628     EL_BUG,
2629     EL_SPACESHIP,
2630     EL_BD_BUTTERFLY,
2631     EL_BD_FIREFLY,
2632
2633     -1
2634   };
2635
2636   static int ep_indestructible[] =
2637   {
2638     EL_STEELWALL,
2639     EL_ACID,
2640     EL_ACID_POOL_TOPLEFT,
2641     EL_ACID_POOL_TOPRIGHT,
2642     EL_ACID_POOL_BOTTOMLEFT,
2643     EL_ACID_POOL_BOTTOM,
2644     EL_ACID_POOL_BOTTOMRIGHT,
2645     EL_SP_HARDWARE_GRAY,
2646     EL_SP_HARDWARE_GREEN,
2647     EL_SP_HARDWARE_BLUE,
2648     EL_SP_HARDWARE_RED,
2649     EL_SP_HARDWARE_YELLOW,
2650     EL_SP_HARDWARE_BASE_1,
2651     EL_SP_HARDWARE_BASE_2,
2652     EL_SP_HARDWARE_BASE_3,
2653     EL_SP_HARDWARE_BASE_4,
2654     EL_SP_HARDWARE_BASE_5,
2655     EL_SP_HARDWARE_BASE_6,
2656     EL_INVISIBLE_STEELWALL,
2657     EL_INVISIBLE_STEELWALL_ACTIVE,
2658     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2659     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2660     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2661     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2662     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2663     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2664     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2665     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2666     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2667     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2668     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2669     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2670     EL_LIGHT_SWITCH,
2671     EL_LIGHT_SWITCH_ACTIVE,
2672     EL_SIGN_EXCLAMATION,
2673     EL_SIGN_RADIOACTIVITY,
2674     EL_SIGN_STOP,
2675     EL_SIGN_WHEELCHAIR,
2676     EL_SIGN_PARKING,
2677     EL_SIGN_NO_ENTRY,
2678     EL_SIGN_UNUSED_1,
2679     EL_SIGN_GIVE_WAY,
2680     EL_SIGN_ENTRY_FORBIDDEN,
2681     EL_SIGN_EMERGENCY_EXIT,
2682     EL_SIGN_YIN_YANG,
2683     EL_SIGN_UNUSED_2,
2684     EL_SIGN_SPERMS,
2685     EL_SIGN_BULLET,
2686     EL_SIGN_HEART,
2687     EL_SIGN_CROSS,
2688     EL_SIGN_FRANKIE,
2689     EL_STEEL_EXIT_CLOSED,
2690     EL_STEEL_EXIT_OPEN,
2691     EL_STEEL_EXIT_OPENING,
2692     EL_STEEL_EXIT_CLOSING,
2693     EL_EM_STEEL_EXIT_CLOSED,
2694     EL_EM_STEEL_EXIT_OPEN,
2695     EL_EM_STEEL_EXIT_OPENING,
2696     EL_EM_STEEL_EXIT_CLOSING,
2697     EL_DC_STEELWALL_1_LEFT,
2698     EL_DC_STEELWALL_1_RIGHT,
2699     EL_DC_STEELWALL_1_TOP,
2700     EL_DC_STEELWALL_1_BOTTOM,
2701     EL_DC_STEELWALL_1_HORIZONTAL,
2702     EL_DC_STEELWALL_1_VERTICAL,
2703     EL_DC_STEELWALL_1_TOPLEFT,
2704     EL_DC_STEELWALL_1_TOPRIGHT,
2705     EL_DC_STEELWALL_1_BOTTOMLEFT,
2706     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2707     EL_DC_STEELWALL_1_TOPLEFT_2,
2708     EL_DC_STEELWALL_1_TOPRIGHT_2,
2709     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2710     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2711     EL_DC_STEELWALL_2_LEFT,
2712     EL_DC_STEELWALL_2_RIGHT,
2713     EL_DC_STEELWALL_2_TOP,
2714     EL_DC_STEELWALL_2_BOTTOM,
2715     EL_DC_STEELWALL_2_HORIZONTAL,
2716     EL_DC_STEELWALL_2_VERTICAL,
2717     EL_DC_STEELWALL_2_MIDDLE,
2718     EL_DC_STEELWALL_2_SINGLE,
2719     EL_STEELWALL_SLIPPERY,
2720     EL_EMC_STEELWALL_1,
2721     EL_EMC_STEELWALL_2,
2722     EL_EMC_STEELWALL_3,
2723     EL_EMC_STEELWALL_4,
2724     EL_CRYSTAL,
2725     EL_GATE_1,
2726     EL_GATE_2,
2727     EL_GATE_3,
2728     EL_GATE_4,
2729     EL_GATE_1_GRAY,
2730     EL_GATE_2_GRAY,
2731     EL_GATE_3_GRAY,
2732     EL_GATE_4_GRAY,
2733     EL_GATE_1_GRAY_ACTIVE,
2734     EL_GATE_2_GRAY_ACTIVE,
2735     EL_GATE_3_GRAY_ACTIVE,
2736     EL_GATE_4_GRAY_ACTIVE,
2737     EL_EM_GATE_1,
2738     EL_EM_GATE_2,
2739     EL_EM_GATE_3,
2740     EL_EM_GATE_4,
2741     EL_EM_GATE_1_GRAY,
2742     EL_EM_GATE_2_GRAY,
2743     EL_EM_GATE_3_GRAY,
2744     EL_EM_GATE_4_GRAY,
2745     EL_EM_GATE_1_GRAY_ACTIVE,
2746     EL_EM_GATE_2_GRAY_ACTIVE,
2747     EL_EM_GATE_3_GRAY_ACTIVE,
2748     EL_EM_GATE_4_GRAY_ACTIVE,
2749     EL_EMC_GATE_5,
2750     EL_EMC_GATE_6,
2751     EL_EMC_GATE_7,
2752     EL_EMC_GATE_8,
2753     EL_EMC_GATE_5_GRAY,
2754     EL_EMC_GATE_6_GRAY,
2755     EL_EMC_GATE_7_GRAY,
2756     EL_EMC_GATE_8_GRAY,
2757     EL_EMC_GATE_5_GRAY_ACTIVE,
2758     EL_EMC_GATE_6_GRAY_ACTIVE,
2759     EL_EMC_GATE_7_GRAY_ACTIVE,
2760     EL_EMC_GATE_8_GRAY_ACTIVE,
2761     EL_DC_GATE_WHITE,
2762     EL_DC_GATE_WHITE_GRAY,
2763     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2764     EL_DC_GATE_FAKE_GRAY,
2765     EL_SWITCHGATE_OPEN,
2766     EL_SWITCHGATE_OPENING,
2767     EL_SWITCHGATE_CLOSED,
2768     EL_SWITCHGATE_CLOSING,
2769     EL_DC_SWITCHGATE_SWITCH_UP,
2770     EL_DC_SWITCHGATE_SWITCH_DOWN,
2771     EL_TIMEGATE_OPEN,
2772     EL_TIMEGATE_OPENING,
2773     EL_TIMEGATE_CLOSED,
2774     EL_TIMEGATE_CLOSING,
2775     EL_DC_TIMEGATE_SWITCH,
2776     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2777     EL_TUBE_ANY,
2778     EL_TUBE_VERTICAL,
2779     EL_TUBE_HORIZONTAL,
2780     EL_TUBE_VERTICAL_LEFT,
2781     EL_TUBE_VERTICAL_RIGHT,
2782     EL_TUBE_HORIZONTAL_UP,
2783     EL_TUBE_HORIZONTAL_DOWN,
2784     EL_TUBE_LEFT_UP,
2785     EL_TUBE_LEFT_DOWN,
2786     EL_TUBE_RIGHT_UP,
2787     EL_TUBE_RIGHT_DOWN,
2788     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2789     EL_EXPANDABLE_STEELWALL_VERTICAL,
2790     EL_EXPANDABLE_STEELWALL_ANY,
2791
2792     -1
2793   };
2794
2795   static int ep_slippery[] =
2796   {
2797     EL_WALL_SLIPPERY,
2798     EL_BD_WALL,
2799     EL_ROCK,
2800     EL_BD_ROCK,
2801     EL_EMERALD,
2802     EL_BD_DIAMOND,
2803     EL_EMERALD_YELLOW,
2804     EL_EMERALD_RED,
2805     EL_EMERALD_PURPLE,
2806     EL_DIAMOND,
2807     EL_BOMB,
2808     EL_NUT,
2809     EL_ROBOT_WHEEL_ACTIVE,
2810     EL_ROBOT_WHEEL,
2811     EL_TIME_ORB_FULL,
2812     EL_TIME_ORB_EMPTY,
2813     EL_LAMP_ACTIVE,
2814     EL_LAMP,
2815     EL_ACID_POOL_TOPLEFT,
2816     EL_ACID_POOL_TOPRIGHT,
2817     EL_SATELLITE,
2818     EL_SP_ZONK,
2819     EL_SP_INFOTRON,
2820     EL_SP_CHIP_SINGLE,
2821     EL_SP_CHIP_LEFT,
2822     EL_SP_CHIP_RIGHT,
2823     EL_SP_CHIP_TOP,
2824     EL_SP_CHIP_BOTTOM,
2825     EL_SPEED_PILL,
2826     EL_STEELWALL_SLIPPERY,
2827     EL_PEARL,
2828     EL_CRYSTAL,
2829     EL_EMC_WALL_SLIPPERY_1,
2830     EL_EMC_WALL_SLIPPERY_2,
2831     EL_EMC_WALL_SLIPPERY_3,
2832     EL_EMC_WALL_SLIPPERY_4,
2833     EL_EMC_MAGIC_BALL,
2834     EL_EMC_MAGIC_BALL_ACTIVE,
2835
2836     -1
2837   };
2838
2839   static int ep_can_change[] =
2840   {
2841     -1
2842   };
2843
2844   static int ep_can_move[] =
2845   {
2846     // same elements as in 'pb_can_move_into_acid'
2847     EL_BUG,
2848     EL_SPACESHIP,
2849     EL_BD_BUTTERFLY,
2850     EL_BD_FIREFLY,
2851     EL_YAMYAM,
2852     EL_DARK_YAMYAM,
2853     EL_ROBOT,
2854     EL_PACMAN,
2855     EL_MOLE,
2856     EL_PENGUIN,
2857     EL_PIG,
2858     EL_DRAGON,
2859     EL_SATELLITE,
2860     EL_SP_SNIKSNAK,
2861     EL_SP_ELECTRON,
2862     EL_BALLOON,
2863     EL_SPRING,
2864     EL_EMC_ANDROID,
2865
2866     -1
2867   };
2868
2869   static int ep_can_fall[] =
2870   {
2871     EL_ROCK,
2872     EL_BD_ROCK,
2873     EL_EMERALD,
2874     EL_BD_DIAMOND,
2875     EL_EMERALD_YELLOW,
2876     EL_EMERALD_RED,
2877     EL_EMERALD_PURPLE,
2878     EL_DIAMOND,
2879     EL_BOMB,
2880     EL_NUT,
2881     EL_AMOEBA_DROP,
2882     EL_AMOEBA_DROPPING,
2883     EL_QUICKSAND_FULL,
2884     EL_QUICKSAND_FAST_FULL,
2885     EL_MAGIC_WALL_FULL,
2886     EL_BD_MAGIC_WALL_FULL,
2887     EL_DC_MAGIC_WALL_FULL,
2888     EL_TIME_ORB_FULL,
2889     EL_TIME_ORB_EMPTY,
2890     EL_SP_ZONK,
2891     EL_SP_INFOTRON,
2892     EL_SP_DISK_ORANGE,
2893     EL_PEARL,
2894     EL_CRYSTAL,
2895     EL_SPRING,
2896     EL_DX_SUPABOMB,
2897
2898     -1
2899   };
2900
2901   static int ep_can_smash_player[] =
2902   {
2903     EL_ROCK,
2904     EL_BD_ROCK,
2905     EL_EMERALD,
2906     EL_BD_DIAMOND,
2907     EL_EMERALD_YELLOW,
2908     EL_EMERALD_RED,
2909     EL_EMERALD_PURPLE,
2910     EL_DIAMOND,
2911     EL_BOMB,
2912     EL_NUT,
2913     EL_AMOEBA_DROP,
2914     EL_TIME_ORB_FULL,
2915     EL_TIME_ORB_EMPTY,
2916     EL_SP_ZONK,
2917     EL_SP_INFOTRON,
2918     EL_SP_DISK_ORANGE,
2919     EL_PEARL,
2920     EL_CRYSTAL,
2921     EL_SPRING,
2922     EL_DX_SUPABOMB,
2923
2924     -1
2925   };
2926
2927   static int ep_can_smash_enemies[] =
2928   {
2929     EL_ROCK,
2930     EL_BD_ROCK,
2931     EL_SP_ZONK,
2932
2933     -1
2934   };
2935
2936   static int ep_can_smash_everything[] =
2937   {
2938     EL_ROCK,
2939     EL_BD_ROCK,
2940     EL_SP_ZONK,
2941
2942     -1
2943   };
2944
2945   static int ep_explodes_by_fire[] =
2946   {
2947     // same elements as in 'ep_explodes_impact'
2948     EL_BOMB,
2949     EL_SP_DISK_ORANGE,
2950     EL_DX_SUPABOMB,
2951
2952     // same elements as in 'ep_explodes_smashed'
2953     EL_SATELLITE,
2954     EL_PIG,
2955     EL_DRAGON,
2956     EL_MOLE,
2957
2958     // new elements
2959     EL_DYNAMITE,
2960     EL_DYNAMITE_ACTIVE,
2961     EL_EM_DYNAMITE,
2962     EL_EM_DYNAMITE_ACTIVE,
2963     EL_DYNABOMB_PLAYER_1_ACTIVE,
2964     EL_DYNABOMB_PLAYER_2_ACTIVE,
2965     EL_DYNABOMB_PLAYER_3_ACTIVE,
2966     EL_DYNABOMB_PLAYER_4_ACTIVE,
2967     EL_DYNABOMB_INCREASE_NUMBER,
2968     EL_DYNABOMB_INCREASE_SIZE,
2969     EL_DYNABOMB_INCREASE_POWER,
2970     EL_SP_DISK_RED_ACTIVE,
2971     EL_BUG,
2972     EL_PENGUIN,
2973     EL_SP_DISK_RED,
2974     EL_SP_DISK_YELLOW,
2975     EL_SP_SNIKSNAK,
2976     EL_SP_ELECTRON,
2977 #if 0
2978     EL_BLACK_ORB,
2979 #endif
2980
2981     -1
2982   };
2983
2984   static int ep_explodes_smashed[] =
2985   {
2986     // same elements as in 'ep_explodes_impact'
2987     EL_BOMB,
2988     EL_SP_DISK_ORANGE,
2989     EL_DX_SUPABOMB,
2990
2991     // new elements
2992     EL_SATELLITE,
2993     EL_PIG,
2994     EL_DRAGON,
2995     EL_MOLE,
2996
2997     -1
2998   };
2999
3000   static int ep_explodes_impact[] =
3001   {
3002     EL_BOMB,
3003     EL_SP_DISK_ORANGE,
3004     EL_DX_SUPABOMB,
3005
3006     -1
3007   };
3008
3009   static int ep_walkable_over[] =
3010   {
3011     EL_EMPTY_SPACE,
3012     EL_EMPTY_SPACE_1,
3013     EL_EMPTY_SPACE_2,
3014     EL_EMPTY_SPACE_3,
3015     EL_EMPTY_SPACE_4,
3016     EL_EMPTY_SPACE_5,
3017     EL_EMPTY_SPACE_6,
3018     EL_EMPTY_SPACE_7,
3019     EL_EMPTY_SPACE_8,
3020     EL_EMPTY_SPACE_9,
3021     EL_EMPTY_SPACE_10,
3022     EL_EMPTY_SPACE_11,
3023     EL_EMPTY_SPACE_12,
3024     EL_EMPTY_SPACE_13,
3025     EL_EMPTY_SPACE_14,
3026     EL_EMPTY_SPACE_15,
3027     EL_EMPTY_SPACE_16,
3028     EL_SP_EMPTY_SPACE,
3029     EL_SOKOBAN_FIELD_EMPTY,
3030     EL_EXIT_OPEN,
3031     EL_EM_EXIT_OPEN,
3032     EL_EM_EXIT_OPENING,
3033     EL_SP_EXIT_OPEN,
3034     EL_SP_EXIT_OPENING,
3035     EL_STEEL_EXIT_OPEN,
3036     EL_EM_STEEL_EXIT_OPEN,
3037     EL_EM_STEEL_EXIT_OPENING,
3038     EL_GATE_1,
3039     EL_GATE_2,
3040     EL_GATE_3,
3041     EL_GATE_4,
3042     EL_GATE_1_GRAY,
3043     EL_GATE_2_GRAY,
3044     EL_GATE_3_GRAY,
3045     EL_GATE_4_GRAY,
3046     EL_GATE_1_GRAY_ACTIVE,
3047     EL_GATE_2_GRAY_ACTIVE,
3048     EL_GATE_3_GRAY_ACTIVE,
3049     EL_GATE_4_GRAY_ACTIVE,
3050     EL_PENGUIN,
3051     EL_PIG,
3052     EL_DRAGON,
3053
3054     -1
3055   };
3056
3057   static int ep_walkable_inside[] =
3058   {
3059     EL_TUBE_ANY,
3060     EL_TUBE_VERTICAL,
3061     EL_TUBE_HORIZONTAL,
3062     EL_TUBE_VERTICAL_LEFT,
3063     EL_TUBE_VERTICAL_RIGHT,
3064     EL_TUBE_HORIZONTAL_UP,
3065     EL_TUBE_HORIZONTAL_DOWN,
3066     EL_TUBE_LEFT_UP,
3067     EL_TUBE_LEFT_DOWN,
3068     EL_TUBE_RIGHT_UP,
3069     EL_TUBE_RIGHT_DOWN,
3070
3071     -1
3072   };
3073
3074   static int ep_walkable_under[] =
3075   {
3076     -1
3077   };
3078
3079   static int ep_passable_over[] =
3080   {
3081     EL_EM_GATE_1,
3082     EL_EM_GATE_2,
3083     EL_EM_GATE_3,
3084     EL_EM_GATE_4,
3085     EL_EM_GATE_1_GRAY,
3086     EL_EM_GATE_2_GRAY,
3087     EL_EM_GATE_3_GRAY,
3088     EL_EM_GATE_4_GRAY,
3089     EL_EM_GATE_1_GRAY_ACTIVE,
3090     EL_EM_GATE_2_GRAY_ACTIVE,
3091     EL_EM_GATE_3_GRAY_ACTIVE,
3092     EL_EM_GATE_4_GRAY_ACTIVE,
3093     EL_EMC_GATE_5,
3094     EL_EMC_GATE_6,
3095     EL_EMC_GATE_7,
3096     EL_EMC_GATE_8,
3097     EL_EMC_GATE_5_GRAY,
3098     EL_EMC_GATE_6_GRAY,
3099     EL_EMC_GATE_7_GRAY,
3100     EL_EMC_GATE_8_GRAY,
3101     EL_EMC_GATE_5_GRAY_ACTIVE,
3102     EL_EMC_GATE_6_GRAY_ACTIVE,
3103     EL_EMC_GATE_7_GRAY_ACTIVE,
3104     EL_EMC_GATE_8_GRAY_ACTIVE,
3105     EL_DC_GATE_WHITE,
3106     EL_DC_GATE_WHITE_GRAY,
3107     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3108     EL_SWITCHGATE_OPEN,
3109     EL_TIMEGATE_OPEN,
3110
3111     -1
3112   };
3113
3114   static int ep_passable_inside[] =
3115   {
3116     EL_SP_PORT_LEFT,
3117     EL_SP_PORT_RIGHT,
3118     EL_SP_PORT_UP,
3119     EL_SP_PORT_DOWN,
3120     EL_SP_PORT_HORIZONTAL,
3121     EL_SP_PORT_VERTICAL,
3122     EL_SP_PORT_ANY,
3123     EL_SP_GRAVITY_PORT_LEFT,
3124     EL_SP_GRAVITY_PORT_RIGHT,
3125     EL_SP_GRAVITY_PORT_UP,
3126     EL_SP_GRAVITY_PORT_DOWN,
3127     EL_SP_GRAVITY_ON_PORT_LEFT,
3128     EL_SP_GRAVITY_ON_PORT_RIGHT,
3129     EL_SP_GRAVITY_ON_PORT_UP,
3130     EL_SP_GRAVITY_ON_PORT_DOWN,
3131     EL_SP_GRAVITY_OFF_PORT_LEFT,
3132     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3133     EL_SP_GRAVITY_OFF_PORT_UP,
3134     EL_SP_GRAVITY_OFF_PORT_DOWN,
3135
3136     -1
3137   };
3138
3139   static int ep_passable_under[] =
3140   {
3141     -1
3142   };
3143
3144   static int ep_droppable[] =
3145   {
3146     -1
3147   };
3148
3149   static int ep_explodes_1x1_old[] =
3150   {
3151     -1
3152   };
3153
3154   static int ep_pushable[] =
3155   {
3156     EL_ROCK,
3157     EL_BOMB,
3158     EL_DX_SUPABOMB,
3159     EL_NUT,
3160     EL_TIME_ORB_EMPTY,
3161     EL_SP_ZONK,
3162     EL_SP_DISK_ORANGE,
3163     EL_SPRING,
3164     EL_BD_ROCK,
3165     EL_SOKOBAN_OBJECT,
3166     EL_SOKOBAN_FIELD_FULL,
3167     EL_SATELLITE,
3168     EL_SP_DISK_YELLOW,
3169     EL_BALLOON,
3170     EL_EMC_ANDROID,
3171
3172     -1
3173   };
3174
3175   static int ep_explodes_cross_old[] =
3176   {
3177     -1
3178   };
3179
3180   static int ep_protected[] =
3181   {
3182     // same elements as in 'ep_walkable_inside'
3183     EL_TUBE_ANY,
3184     EL_TUBE_VERTICAL,
3185     EL_TUBE_HORIZONTAL,
3186     EL_TUBE_VERTICAL_LEFT,
3187     EL_TUBE_VERTICAL_RIGHT,
3188     EL_TUBE_HORIZONTAL_UP,
3189     EL_TUBE_HORIZONTAL_DOWN,
3190     EL_TUBE_LEFT_UP,
3191     EL_TUBE_LEFT_DOWN,
3192     EL_TUBE_RIGHT_UP,
3193     EL_TUBE_RIGHT_DOWN,
3194
3195     // same elements as in 'ep_passable_over'
3196     EL_EM_GATE_1,
3197     EL_EM_GATE_2,
3198     EL_EM_GATE_3,
3199     EL_EM_GATE_4,
3200     EL_EM_GATE_1_GRAY,
3201     EL_EM_GATE_2_GRAY,
3202     EL_EM_GATE_3_GRAY,
3203     EL_EM_GATE_4_GRAY,
3204     EL_EM_GATE_1_GRAY_ACTIVE,
3205     EL_EM_GATE_2_GRAY_ACTIVE,
3206     EL_EM_GATE_3_GRAY_ACTIVE,
3207     EL_EM_GATE_4_GRAY_ACTIVE,
3208     EL_EMC_GATE_5,
3209     EL_EMC_GATE_6,
3210     EL_EMC_GATE_7,
3211     EL_EMC_GATE_8,
3212     EL_EMC_GATE_5_GRAY,
3213     EL_EMC_GATE_6_GRAY,
3214     EL_EMC_GATE_7_GRAY,
3215     EL_EMC_GATE_8_GRAY,
3216     EL_EMC_GATE_5_GRAY_ACTIVE,
3217     EL_EMC_GATE_6_GRAY_ACTIVE,
3218     EL_EMC_GATE_7_GRAY_ACTIVE,
3219     EL_EMC_GATE_8_GRAY_ACTIVE,
3220     EL_DC_GATE_WHITE,
3221     EL_DC_GATE_WHITE_GRAY,
3222     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3223     EL_SWITCHGATE_OPEN,
3224     EL_TIMEGATE_OPEN,
3225
3226     // same elements as in 'ep_passable_inside'
3227     EL_SP_PORT_LEFT,
3228     EL_SP_PORT_RIGHT,
3229     EL_SP_PORT_UP,
3230     EL_SP_PORT_DOWN,
3231     EL_SP_PORT_HORIZONTAL,
3232     EL_SP_PORT_VERTICAL,
3233     EL_SP_PORT_ANY,
3234     EL_SP_GRAVITY_PORT_LEFT,
3235     EL_SP_GRAVITY_PORT_RIGHT,
3236     EL_SP_GRAVITY_PORT_UP,
3237     EL_SP_GRAVITY_PORT_DOWN,
3238     EL_SP_GRAVITY_ON_PORT_LEFT,
3239     EL_SP_GRAVITY_ON_PORT_RIGHT,
3240     EL_SP_GRAVITY_ON_PORT_UP,
3241     EL_SP_GRAVITY_ON_PORT_DOWN,
3242     EL_SP_GRAVITY_OFF_PORT_LEFT,
3243     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3244     EL_SP_GRAVITY_OFF_PORT_UP,
3245     EL_SP_GRAVITY_OFF_PORT_DOWN,
3246
3247     -1
3248   };
3249
3250   static int ep_throwable[] =
3251   {
3252     -1
3253   };
3254
3255   static int ep_can_explode[] =
3256   {
3257     // same elements as in 'ep_explodes_impact'
3258     EL_BOMB,
3259     EL_SP_DISK_ORANGE,
3260     EL_DX_SUPABOMB,
3261
3262     // same elements as in 'ep_explodes_smashed'
3263     EL_SATELLITE,
3264     EL_PIG,
3265     EL_DRAGON,
3266     EL_MOLE,
3267
3268     // elements that can explode by explosion or by dragonfire
3269     EL_DYNAMITE,
3270     EL_DYNAMITE_ACTIVE,
3271     EL_EM_DYNAMITE,
3272     EL_EM_DYNAMITE_ACTIVE,
3273     EL_DYNABOMB_PLAYER_1_ACTIVE,
3274     EL_DYNABOMB_PLAYER_2_ACTIVE,
3275     EL_DYNABOMB_PLAYER_3_ACTIVE,
3276     EL_DYNABOMB_PLAYER_4_ACTIVE,
3277     EL_DYNABOMB_INCREASE_NUMBER,
3278     EL_DYNABOMB_INCREASE_SIZE,
3279     EL_DYNABOMB_INCREASE_POWER,
3280     EL_SP_DISK_RED_ACTIVE,
3281     EL_BUG,
3282     EL_PENGUIN,
3283     EL_SP_DISK_RED,
3284     EL_SP_DISK_YELLOW,
3285     EL_SP_SNIKSNAK,
3286     EL_SP_ELECTRON,
3287
3288     // elements that can explode only by explosion
3289     EL_BLACK_ORB,
3290
3291     -1
3292   };
3293
3294   static int ep_gravity_reachable[] =
3295   {
3296     EL_SAND,
3297     EL_SP_BASE,
3298     EL_TRAP,
3299     EL_INVISIBLE_SAND,
3300     EL_INVISIBLE_SAND_ACTIVE,
3301     EL_SP_PORT_LEFT,
3302     EL_SP_PORT_RIGHT,
3303     EL_SP_PORT_UP,
3304     EL_SP_PORT_DOWN,
3305     EL_SP_PORT_HORIZONTAL,
3306     EL_SP_PORT_VERTICAL,
3307     EL_SP_PORT_ANY,
3308     EL_SP_GRAVITY_PORT_LEFT,
3309     EL_SP_GRAVITY_PORT_RIGHT,
3310     EL_SP_GRAVITY_PORT_UP,
3311     EL_SP_GRAVITY_PORT_DOWN,
3312     EL_SP_GRAVITY_ON_PORT_LEFT,
3313     EL_SP_GRAVITY_ON_PORT_RIGHT,
3314     EL_SP_GRAVITY_ON_PORT_UP,
3315     EL_SP_GRAVITY_ON_PORT_DOWN,
3316     EL_SP_GRAVITY_OFF_PORT_LEFT,
3317     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3318     EL_SP_GRAVITY_OFF_PORT_UP,
3319     EL_SP_GRAVITY_OFF_PORT_DOWN,
3320     EL_EMC_GRASS,
3321
3322     -1
3323   };
3324
3325   static int ep_empty_space[] =
3326   {
3327     EL_EMPTY_SPACE,
3328     EL_EMPTY_SPACE_1,
3329     EL_EMPTY_SPACE_2,
3330     EL_EMPTY_SPACE_3,
3331     EL_EMPTY_SPACE_4,
3332     EL_EMPTY_SPACE_5,
3333     EL_EMPTY_SPACE_6,
3334     EL_EMPTY_SPACE_7,
3335     EL_EMPTY_SPACE_8,
3336     EL_EMPTY_SPACE_9,
3337     EL_EMPTY_SPACE_10,
3338     EL_EMPTY_SPACE_11,
3339     EL_EMPTY_SPACE_12,
3340     EL_EMPTY_SPACE_13,
3341     EL_EMPTY_SPACE_14,
3342     EL_EMPTY_SPACE_15,
3343     EL_EMPTY_SPACE_16,
3344
3345     -1
3346   };
3347
3348   static int ep_player[] =
3349   {
3350     EL_PLAYER_1,
3351     EL_PLAYER_2,
3352     EL_PLAYER_3,
3353     EL_PLAYER_4,
3354     EL_SP_MURPHY,
3355     EL_SOKOBAN_FIELD_PLAYER,
3356     EL_TRIGGER_PLAYER,
3357
3358     -1
3359   };
3360
3361   static int ep_can_pass_magic_wall[] =
3362   {
3363     EL_ROCK,
3364     EL_BD_ROCK,
3365     EL_EMERALD,
3366     EL_BD_DIAMOND,
3367     EL_EMERALD_YELLOW,
3368     EL_EMERALD_RED,
3369     EL_EMERALD_PURPLE,
3370     EL_DIAMOND,
3371
3372     -1
3373   };
3374
3375   static int ep_can_pass_dc_magic_wall[] =
3376   {
3377     EL_ROCK,
3378     EL_BD_ROCK,
3379     EL_EMERALD,
3380     EL_BD_DIAMOND,
3381     EL_EMERALD_YELLOW,
3382     EL_EMERALD_RED,
3383     EL_EMERALD_PURPLE,
3384     EL_DIAMOND,
3385     EL_PEARL,
3386     EL_CRYSTAL,
3387
3388     -1
3389   };
3390
3391   static int ep_switchable[] =
3392   {
3393     EL_ROBOT_WHEEL,
3394     EL_SP_TERMINAL,
3395     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3396     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3397     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3398     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3399     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3400     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3401     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3402     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3403     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3404     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3405     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3406     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3407     EL_SWITCHGATE_SWITCH_UP,
3408     EL_SWITCHGATE_SWITCH_DOWN,
3409     EL_DC_SWITCHGATE_SWITCH_UP,
3410     EL_DC_SWITCHGATE_SWITCH_DOWN,
3411     EL_LIGHT_SWITCH,
3412     EL_LIGHT_SWITCH_ACTIVE,
3413     EL_TIMEGATE_SWITCH,
3414     EL_DC_TIMEGATE_SWITCH,
3415     EL_BALLOON_SWITCH_LEFT,
3416     EL_BALLOON_SWITCH_RIGHT,
3417     EL_BALLOON_SWITCH_UP,
3418     EL_BALLOON_SWITCH_DOWN,
3419     EL_BALLOON_SWITCH_ANY,
3420     EL_BALLOON_SWITCH_NONE,
3421     EL_LAMP,
3422     EL_TIME_ORB_FULL,
3423     EL_EMC_MAGIC_BALL_SWITCH,
3424     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3425
3426     -1
3427   };
3428
3429   static int ep_bd_element[] =
3430   {
3431     EL_EMPTY,
3432     EL_SAND,
3433     EL_WALL_SLIPPERY,
3434     EL_BD_WALL,
3435     EL_ROCK,
3436     EL_BD_ROCK,
3437     EL_BD_DIAMOND,
3438     EL_BD_MAGIC_WALL,
3439     EL_EXIT_CLOSED,
3440     EL_EXIT_OPEN,
3441     EL_STEELWALL,
3442     EL_PLAYER_1,
3443     EL_PLAYER_2,
3444     EL_PLAYER_3,
3445     EL_PLAYER_4,
3446     EL_BD_FIREFLY,
3447     EL_BD_FIREFLY_1,
3448     EL_BD_FIREFLY_2,
3449     EL_BD_FIREFLY_3,
3450     EL_BD_FIREFLY_4,
3451     EL_BD_BUTTERFLY,
3452     EL_BD_BUTTERFLY_1,
3453     EL_BD_BUTTERFLY_2,
3454     EL_BD_BUTTERFLY_3,
3455     EL_BD_BUTTERFLY_4,
3456     EL_BD_AMOEBA,
3457     EL_CHAR_QUESTION,
3458     EL_UNKNOWN,
3459
3460     -1
3461   };
3462
3463   static int ep_sp_element[] =
3464   {
3465     // should always be valid
3466     EL_EMPTY,
3467
3468     // standard classic Supaplex elements
3469     EL_SP_EMPTY,
3470     EL_SP_ZONK,
3471     EL_SP_BASE,
3472     EL_SP_MURPHY,
3473     EL_SP_INFOTRON,
3474     EL_SP_CHIP_SINGLE,
3475     EL_SP_HARDWARE_GRAY,
3476     EL_SP_EXIT_CLOSED,
3477     EL_SP_EXIT_OPEN,
3478     EL_SP_DISK_ORANGE,
3479     EL_SP_PORT_RIGHT,
3480     EL_SP_PORT_DOWN,
3481     EL_SP_PORT_LEFT,
3482     EL_SP_PORT_UP,
3483     EL_SP_GRAVITY_PORT_RIGHT,
3484     EL_SP_GRAVITY_PORT_DOWN,
3485     EL_SP_GRAVITY_PORT_LEFT,
3486     EL_SP_GRAVITY_PORT_UP,
3487     EL_SP_SNIKSNAK,
3488     EL_SP_DISK_YELLOW,
3489     EL_SP_TERMINAL,
3490     EL_SP_DISK_RED,
3491     EL_SP_PORT_VERTICAL,
3492     EL_SP_PORT_HORIZONTAL,
3493     EL_SP_PORT_ANY,
3494     EL_SP_ELECTRON,
3495     EL_SP_BUGGY_BASE,
3496     EL_SP_CHIP_LEFT,
3497     EL_SP_CHIP_RIGHT,
3498     EL_SP_HARDWARE_BASE_1,
3499     EL_SP_HARDWARE_GREEN,
3500     EL_SP_HARDWARE_BLUE,
3501     EL_SP_HARDWARE_RED,
3502     EL_SP_HARDWARE_YELLOW,
3503     EL_SP_HARDWARE_BASE_2,
3504     EL_SP_HARDWARE_BASE_3,
3505     EL_SP_HARDWARE_BASE_4,
3506     EL_SP_HARDWARE_BASE_5,
3507     EL_SP_HARDWARE_BASE_6,
3508     EL_SP_CHIP_TOP,
3509     EL_SP_CHIP_BOTTOM,
3510
3511     // additional elements that appeared in newer Supaplex levels
3512     EL_INVISIBLE_WALL,
3513
3514     // additional gravity port elements (not switching, but setting gravity)
3515     EL_SP_GRAVITY_ON_PORT_LEFT,
3516     EL_SP_GRAVITY_ON_PORT_RIGHT,
3517     EL_SP_GRAVITY_ON_PORT_UP,
3518     EL_SP_GRAVITY_ON_PORT_DOWN,
3519     EL_SP_GRAVITY_OFF_PORT_LEFT,
3520     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3521     EL_SP_GRAVITY_OFF_PORT_UP,
3522     EL_SP_GRAVITY_OFF_PORT_DOWN,
3523
3524     // more than one Murphy in a level results in an inactive clone
3525     EL_SP_MURPHY_CLONE,
3526
3527     // runtime Supaplex elements
3528     EL_SP_DISK_RED_ACTIVE,
3529     EL_SP_TERMINAL_ACTIVE,
3530     EL_SP_BUGGY_BASE_ACTIVATING,
3531     EL_SP_BUGGY_BASE_ACTIVE,
3532     EL_SP_EXIT_OPENING,
3533     EL_SP_EXIT_CLOSING,
3534
3535     -1
3536   };
3537
3538   static int ep_sb_element[] =
3539   {
3540     EL_EMPTY,
3541     EL_STEELWALL,
3542     EL_SOKOBAN_OBJECT,
3543     EL_SOKOBAN_FIELD_EMPTY,
3544     EL_SOKOBAN_FIELD_FULL,
3545     EL_SOKOBAN_FIELD_PLAYER,
3546     EL_PLAYER_1,
3547     EL_PLAYER_2,
3548     EL_PLAYER_3,
3549     EL_PLAYER_4,
3550     EL_INVISIBLE_STEELWALL,
3551
3552     -1
3553   };
3554
3555   static int ep_gem[] =
3556   {
3557     EL_BD_DIAMOND,
3558     EL_EMERALD,
3559     EL_EMERALD_YELLOW,
3560     EL_EMERALD_RED,
3561     EL_EMERALD_PURPLE,
3562     EL_DIAMOND,
3563
3564     -1
3565   };
3566
3567   static int ep_food_dark_yamyam[] =
3568   {
3569     EL_SAND,
3570     EL_BUG,
3571     EL_SPACESHIP,
3572     EL_BD_BUTTERFLY,
3573     EL_BD_FIREFLY,
3574     EL_YAMYAM,
3575     EL_ROBOT,
3576     EL_PACMAN,
3577     EL_AMOEBA_DROP,
3578     EL_AMOEBA_DEAD,
3579     EL_AMOEBA_WET,
3580     EL_AMOEBA_DRY,
3581     EL_AMOEBA_FULL,
3582     EL_BD_AMOEBA,
3583     EL_EMERALD,
3584     EL_BD_DIAMOND,
3585     EL_EMERALD_YELLOW,
3586     EL_EMERALD_RED,
3587     EL_EMERALD_PURPLE,
3588     EL_DIAMOND,
3589     EL_PEARL,
3590     EL_CRYSTAL,
3591
3592     -1
3593   };
3594
3595   static int ep_food_penguin[] =
3596   {
3597     EL_EMERALD,
3598     EL_BD_DIAMOND,
3599     EL_EMERALD_YELLOW,
3600     EL_EMERALD_RED,
3601     EL_EMERALD_PURPLE,
3602     EL_DIAMOND,
3603     EL_PEARL,
3604     EL_CRYSTAL,
3605
3606     -1
3607   };
3608
3609   static int ep_food_pig[] =
3610   {
3611     EL_EMERALD,
3612     EL_BD_DIAMOND,
3613     EL_EMERALD_YELLOW,
3614     EL_EMERALD_RED,
3615     EL_EMERALD_PURPLE,
3616     EL_DIAMOND,
3617
3618     -1
3619   };
3620
3621   static int ep_historic_wall[] =
3622   {
3623     EL_STEELWALL,
3624     EL_GATE_1,
3625     EL_GATE_2,
3626     EL_GATE_3,
3627     EL_GATE_4,
3628     EL_GATE_1_GRAY,
3629     EL_GATE_2_GRAY,
3630     EL_GATE_3_GRAY,
3631     EL_GATE_4_GRAY,
3632     EL_GATE_1_GRAY_ACTIVE,
3633     EL_GATE_2_GRAY_ACTIVE,
3634     EL_GATE_3_GRAY_ACTIVE,
3635     EL_GATE_4_GRAY_ACTIVE,
3636     EL_EM_GATE_1,
3637     EL_EM_GATE_2,
3638     EL_EM_GATE_3,
3639     EL_EM_GATE_4,
3640     EL_EM_GATE_1_GRAY,
3641     EL_EM_GATE_2_GRAY,
3642     EL_EM_GATE_3_GRAY,
3643     EL_EM_GATE_4_GRAY,
3644     EL_EM_GATE_1_GRAY_ACTIVE,
3645     EL_EM_GATE_2_GRAY_ACTIVE,
3646     EL_EM_GATE_3_GRAY_ACTIVE,
3647     EL_EM_GATE_4_GRAY_ACTIVE,
3648     EL_EXIT_CLOSED,
3649     EL_EXIT_OPENING,
3650     EL_EXIT_OPEN,
3651     EL_WALL,
3652     EL_WALL_SLIPPERY,
3653     EL_EXPANDABLE_WALL,
3654     EL_EXPANDABLE_WALL_HORIZONTAL,
3655     EL_EXPANDABLE_WALL_VERTICAL,
3656     EL_EXPANDABLE_WALL_ANY,
3657     EL_EXPANDABLE_WALL_GROWING,
3658     EL_BD_EXPANDABLE_WALL,
3659     EL_BD_WALL,
3660     EL_SP_CHIP_SINGLE,
3661     EL_SP_CHIP_LEFT,
3662     EL_SP_CHIP_RIGHT,
3663     EL_SP_CHIP_TOP,
3664     EL_SP_CHIP_BOTTOM,
3665     EL_SP_HARDWARE_GRAY,
3666     EL_SP_HARDWARE_GREEN,
3667     EL_SP_HARDWARE_BLUE,
3668     EL_SP_HARDWARE_RED,
3669     EL_SP_HARDWARE_YELLOW,
3670     EL_SP_HARDWARE_BASE_1,
3671     EL_SP_HARDWARE_BASE_2,
3672     EL_SP_HARDWARE_BASE_3,
3673     EL_SP_HARDWARE_BASE_4,
3674     EL_SP_HARDWARE_BASE_5,
3675     EL_SP_HARDWARE_BASE_6,
3676     EL_SP_TERMINAL,
3677     EL_SP_TERMINAL_ACTIVE,
3678     EL_SP_EXIT_CLOSED,
3679     EL_SP_EXIT_OPEN,
3680     EL_INVISIBLE_STEELWALL,
3681     EL_INVISIBLE_STEELWALL_ACTIVE,
3682     EL_INVISIBLE_WALL,
3683     EL_INVISIBLE_WALL_ACTIVE,
3684     EL_STEELWALL_SLIPPERY,
3685     EL_EMC_STEELWALL_1,
3686     EL_EMC_STEELWALL_2,
3687     EL_EMC_STEELWALL_3,
3688     EL_EMC_STEELWALL_4,
3689     EL_EMC_WALL_1,
3690     EL_EMC_WALL_2,
3691     EL_EMC_WALL_3,
3692     EL_EMC_WALL_4,
3693     EL_EMC_WALL_5,
3694     EL_EMC_WALL_6,
3695     EL_EMC_WALL_7,
3696     EL_EMC_WALL_8,
3697
3698     -1
3699   };
3700
3701   static int ep_historic_solid[] =
3702   {
3703     EL_WALL,
3704     EL_EXPANDABLE_WALL,
3705     EL_EXPANDABLE_WALL_HORIZONTAL,
3706     EL_EXPANDABLE_WALL_VERTICAL,
3707     EL_EXPANDABLE_WALL_ANY,
3708     EL_BD_EXPANDABLE_WALL,
3709     EL_BD_WALL,
3710     EL_WALL_SLIPPERY,
3711     EL_EXIT_CLOSED,
3712     EL_EXIT_OPENING,
3713     EL_EXIT_OPEN,
3714     EL_AMOEBA_DEAD,
3715     EL_AMOEBA_WET,
3716     EL_AMOEBA_DRY,
3717     EL_AMOEBA_FULL,
3718     EL_BD_AMOEBA,
3719     EL_QUICKSAND_EMPTY,
3720     EL_QUICKSAND_FULL,
3721     EL_QUICKSAND_FILLING,
3722     EL_QUICKSAND_EMPTYING,
3723     EL_MAGIC_WALL,
3724     EL_MAGIC_WALL_ACTIVE,
3725     EL_MAGIC_WALL_EMPTYING,
3726     EL_MAGIC_WALL_FILLING,
3727     EL_MAGIC_WALL_FULL,
3728     EL_MAGIC_WALL_DEAD,
3729     EL_BD_MAGIC_WALL,
3730     EL_BD_MAGIC_WALL_ACTIVE,
3731     EL_BD_MAGIC_WALL_EMPTYING,
3732     EL_BD_MAGIC_WALL_FULL,
3733     EL_BD_MAGIC_WALL_FILLING,
3734     EL_BD_MAGIC_WALL_DEAD,
3735     EL_GAME_OF_LIFE,
3736     EL_BIOMAZE,
3737     EL_SP_CHIP_SINGLE,
3738     EL_SP_CHIP_LEFT,
3739     EL_SP_CHIP_RIGHT,
3740     EL_SP_CHIP_TOP,
3741     EL_SP_CHIP_BOTTOM,
3742     EL_SP_TERMINAL,
3743     EL_SP_TERMINAL_ACTIVE,
3744     EL_SP_EXIT_CLOSED,
3745     EL_SP_EXIT_OPEN,
3746     EL_INVISIBLE_WALL,
3747     EL_INVISIBLE_WALL_ACTIVE,
3748     EL_SWITCHGATE_SWITCH_UP,
3749     EL_SWITCHGATE_SWITCH_DOWN,
3750     EL_TIMEGATE_SWITCH,
3751     EL_TIMEGATE_SWITCH_ACTIVE,
3752     EL_EMC_WALL_1,
3753     EL_EMC_WALL_2,
3754     EL_EMC_WALL_3,
3755     EL_EMC_WALL_4,
3756     EL_EMC_WALL_5,
3757     EL_EMC_WALL_6,
3758     EL_EMC_WALL_7,
3759     EL_EMC_WALL_8,
3760     EL_WALL_PEARL,
3761     EL_WALL_CRYSTAL,
3762
3763     // the following elements are a direct copy of "indestructible" elements,
3764     // except "EL_ACID", which is "indestructible", but not "solid"!
3765 #if 0
3766     EL_ACID,
3767 #endif
3768     EL_STEELWALL,
3769     EL_ACID_POOL_TOPLEFT,
3770     EL_ACID_POOL_TOPRIGHT,
3771     EL_ACID_POOL_BOTTOMLEFT,
3772     EL_ACID_POOL_BOTTOM,
3773     EL_ACID_POOL_BOTTOMRIGHT,
3774     EL_SP_HARDWARE_GRAY,
3775     EL_SP_HARDWARE_GREEN,
3776     EL_SP_HARDWARE_BLUE,
3777     EL_SP_HARDWARE_RED,
3778     EL_SP_HARDWARE_YELLOW,
3779     EL_SP_HARDWARE_BASE_1,
3780     EL_SP_HARDWARE_BASE_2,
3781     EL_SP_HARDWARE_BASE_3,
3782     EL_SP_HARDWARE_BASE_4,
3783     EL_SP_HARDWARE_BASE_5,
3784     EL_SP_HARDWARE_BASE_6,
3785     EL_INVISIBLE_STEELWALL,
3786     EL_INVISIBLE_STEELWALL_ACTIVE,
3787     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3788     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3789     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3790     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3791     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3792     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3793     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3794     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3795     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3796     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3797     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3798     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3799     EL_LIGHT_SWITCH,
3800     EL_LIGHT_SWITCH_ACTIVE,
3801     EL_SIGN_EXCLAMATION,
3802     EL_SIGN_RADIOACTIVITY,
3803     EL_SIGN_STOP,
3804     EL_SIGN_WHEELCHAIR,
3805     EL_SIGN_PARKING,
3806     EL_SIGN_NO_ENTRY,
3807     EL_SIGN_UNUSED_1,
3808     EL_SIGN_GIVE_WAY,
3809     EL_SIGN_ENTRY_FORBIDDEN,
3810     EL_SIGN_EMERGENCY_EXIT,
3811     EL_SIGN_YIN_YANG,
3812     EL_SIGN_UNUSED_2,
3813     EL_SIGN_SPERMS,
3814     EL_SIGN_BULLET,
3815     EL_SIGN_HEART,
3816     EL_SIGN_CROSS,
3817     EL_SIGN_FRANKIE,
3818     EL_STEEL_EXIT_CLOSED,
3819     EL_STEEL_EXIT_OPEN,
3820     EL_STEEL_EXIT_OPENING,
3821     EL_STEEL_EXIT_CLOSING,
3822     EL_EM_STEEL_EXIT_CLOSED,
3823     EL_EM_STEEL_EXIT_OPEN,
3824     EL_EM_STEEL_EXIT_OPENING,
3825     EL_EM_STEEL_EXIT_CLOSING,
3826     EL_DC_STEELWALL_1_LEFT,
3827     EL_DC_STEELWALL_1_RIGHT,
3828     EL_DC_STEELWALL_1_TOP,
3829     EL_DC_STEELWALL_1_BOTTOM,
3830     EL_DC_STEELWALL_1_HORIZONTAL,
3831     EL_DC_STEELWALL_1_VERTICAL,
3832     EL_DC_STEELWALL_1_TOPLEFT,
3833     EL_DC_STEELWALL_1_TOPRIGHT,
3834     EL_DC_STEELWALL_1_BOTTOMLEFT,
3835     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3836     EL_DC_STEELWALL_1_TOPLEFT_2,
3837     EL_DC_STEELWALL_1_TOPRIGHT_2,
3838     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3839     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3840     EL_DC_STEELWALL_2_LEFT,
3841     EL_DC_STEELWALL_2_RIGHT,
3842     EL_DC_STEELWALL_2_TOP,
3843     EL_DC_STEELWALL_2_BOTTOM,
3844     EL_DC_STEELWALL_2_HORIZONTAL,
3845     EL_DC_STEELWALL_2_VERTICAL,
3846     EL_DC_STEELWALL_2_MIDDLE,
3847     EL_DC_STEELWALL_2_SINGLE,
3848     EL_STEELWALL_SLIPPERY,
3849     EL_EMC_STEELWALL_1,
3850     EL_EMC_STEELWALL_2,
3851     EL_EMC_STEELWALL_3,
3852     EL_EMC_STEELWALL_4,
3853     EL_CRYSTAL,
3854     EL_GATE_1,
3855     EL_GATE_2,
3856     EL_GATE_3,
3857     EL_GATE_4,
3858     EL_GATE_1_GRAY,
3859     EL_GATE_2_GRAY,
3860     EL_GATE_3_GRAY,
3861     EL_GATE_4_GRAY,
3862     EL_GATE_1_GRAY_ACTIVE,
3863     EL_GATE_2_GRAY_ACTIVE,
3864     EL_GATE_3_GRAY_ACTIVE,
3865     EL_GATE_4_GRAY_ACTIVE,
3866     EL_EM_GATE_1,
3867     EL_EM_GATE_2,
3868     EL_EM_GATE_3,
3869     EL_EM_GATE_4,
3870     EL_EM_GATE_1_GRAY,
3871     EL_EM_GATE_2_GRAY,
3872     EL_EM_GATE_3_GRAY,
3873     EL_EM_GATE_4_GRAY,
3874     EL_EM_GATE_1_GRAY_ACTIVE,
3875     EL_EM_GATE_2_GRAY_ACTIVE,
3876     EL_EM_GATE_3_GRAY_ACTIVE,
3877     EL_EM_GATE_4_GRAY_ACTIVE,
3878     EL_EMC_GATE_5,
3879     EL_EMC_GATE_6,
3880     EL_EMC_GATE_7,
3881     EL_EMC_GATE_8,
3882     EL_EMC_GATE_5_GRAY,
3883     EL_EMC_GATE_6_GRAY,
3884     EL_EMC_GATE_7_GRAY,
3885     EL_EMC_GATE_8_GRAY,
3886     EL_EMC_GATE_5_GRAY_ACTIVE,
3887     EL_EMC_GATE_6_GRAY_ACTIVE,
3888     EL_EMC_GATE_7_GRAY_ACTIVE,
3889     EL_EMC_GATE_8_GRAY_ACTIVE,
3890     EL_DC_GATE_WHITE,
3891     EL_DC_GATE_WHITE_GRAY,
3892     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3893     EL_DC_GATE_FAKE_GRAY,
3894     EL_SWITCHGATE_OPEN,
3895     EL_SWITCHGATE_OPENING,
3896     EL_SWITCHGATE_CLOSED,
3897     EL_SWITCHGATE_CLOSING,
3898     EL_DC_SWITCHGATE_SWITCH_UP,
3899     EL_DC_SWITCHGATE_SWITCH_DOWN,
3900     EL_TIMEGATE_OPEN,
3901     EL_TIMEGATE_OPENING,
3902     EL_TIMEGATE_CLOSED,
3903     EL_TIMEGATE_CLOSING,
3904     EL_DC_TIMEGATE_SWITCH,
3905     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3906     EL_TUBE_ANY,
3907     EL_TUBE_VERTICAL,
3908     EL_TUBE_HORIZONTAL,
3909     EL_TUBE_VERTICAL_LEFT,
3910     EL_TUBE_VERTICAL_RIGHT,
3911     EL_TUBE_HORIZONTAL_UP,
3912     EL_TUBE_HORIZONTAL_DOWN,
3913     EL_TUBE_LEFT_UP,
3914     EL_TUBE_LEFT_DOWN,
3915     EL_TUBE_RIGHT_UP,
3916     EL_TUBE_RIGHT_DOWN,
3917     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3918     EL_EXPANDABLE_STEELWALL_VERTICAL,
3919     EL_EXPANDABLE_STEELWALL_ANY,
3920
3921     -1
3922   };
3923
3924   static int ep_classic_enemy[] =
3925   {
3926     EL_BUG,
3927     EL_SPACESHIP,
3928     EL_BD_BUTTERFLY,
3929     EL_BD_FIREFLY,
3930
3931     EL_YAMYAM,
3932     EL_DARK_YAMYAM,
3933     EL_ROBOT,
3934     EL_PACMAN,
3935     EL_SP_SNIKSNAK,
3936     EL_SP_ELECTRON,
3937
3938     -1
3939   };
3940
3941   static int ep_belt[] =
3942   {
3943     EL_CONVEYOR_BELT_1_LEFT,
3944     EL_CONVEYOR_BELT_1_MIDDLE,
3945     EL_CONVEYOR_BELT_1_RIGHT,
3946     EL_CONVEYOR_BELT_2_LEFT,
3947     EL_CONVEYOR_BELT_2_MIDDLE,
3948     EL_CONVEYOR_BELT_2_RIGHT,
3949     EL_CONVEYOR_BELT_3_LEFT,
3950     EL_CONVEYOR_BELT_3_MIDDLE,
3951     EL_CONVEYOR_BELT_3_RIGHT,
3952     EL_CONVEYOR_BELT_4_LEFT,
3953     EL_CONVEYOR_BELT_4_MIDDLE,
3954     EL_CONVEYOR_BELT_4_RIGHT,
3955
3956     -1
3957   };
3958
3959   static int ep_belt_active[] =
3960   {
3961     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3962     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3963     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3964     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3965     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3966     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3967     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3968     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3969     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3970     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3971     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3972     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3973
3974     -1
3975   };
3976
3977   static int ep_belt_switch[] =
3978   {
3979     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3980     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3981     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3982     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3983     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3984     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3985     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3986     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3987     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3988     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3989     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3990     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3991
3992     -1
3993   };
3994
3995   static int ep_tube[] =
3996   {
3997     EL_TUBE_LEFT_UP,
3998     EL_TUBE_LEFT_DOWN,
3999     EL_TUBE_RIGHT_UP,
4000     EL_TUBE_RIGHT_DOWN,
4001     EL_TUBE_HORIZONTAL,
4002     EL_TUBE_HORIZONTAL_UP,
4003     EL_TUBE_HORIZONTAL_DOWN,
4004     EL_TUBE_VERTICAL,
4005     EL_TUBE_VERTICAL_LEFT,
4006     EL_TUBE_VERTICAL_RIGHT,
4007     EL_TUBE_ANY,
4008
4009     -1
4010   };
4011
4012   static int ep_acid_pool[] =
4013   {
4014     EL_ACID_POOL_TOPLEFT,
4015     EL_ACID_POOL_TOPRIGHT,
4016     EL_ACID_POOL_BOTTOMLEFT,
4017     EL_ACID_POOL_BOTTOM,
4018     EL_ACID_POOL_BOTTOMRIGHT,
4019
4020     -1
4021   };
4022
4023   static int ep_keygate[] =
4024   {
4025     EL_GATE_1,
4026     EL_GATE_2,
4027     EL_GATE_3,
4028     EL_GATE_4,
4029     EL_GATE_1_GRAY,
4030     EL_GATE_2_GRAY,
4031     EL_GATE_3_GRAY,
4032     EL_GATE_4_GRAY,
4033     EL_GATE_1_GRAY_ACTIVE,
4034     EL_GATE_2_GRAY_ACTIVE,
4035     EL_GATE_3_GRAY_ACTIVE,
4036     EL_GATE_4_GRAY_ACTIVE,
4037     EL_EM_GATE_1,
4038     EL_EM_GATE_2,
4039     EL_EM_GATE_3,
4040     EL_EM_GATE_4,
4041     EL_EM_GATE_1_GRAY,
4042     EL_EM_GATE_2_GRAY,
4043     EL_EM_GATE_3_GRAY,
4044     EL_EM_GATE_4_GRAY,
4045     EL_EM_GATE_1_GRAY_ACTIVE,
4046     EL_EM_GATE_2_GRAY_ACTIVE,
4047     EL_EM_GATE_3_GRAY_ACTIVE,
4048     EL_EM_GATE_4_GRAY_ACTIVE,
4049     EL_EMC_GATE_5,
4050     EL_EMC_GATE_6,
4051     EL_EMC_GATE_7,
4052     EL_EMC_GATE_8,
4053     EL_EMC_GATE_5_GRAY,
4054     EL_EMC_GATE_6_GRAY,
4055     EL_EMC_GATE_7_GRAY,
4056     EL_EMC_GATE_8_GRAY,
4057     EL_EMC_GATE_5_GRAY_ACTIVE,
4058     EL_EMC_GATE_6_GRAY_ACTIVE,
4059     EL_EMC_GATE_7_GRAY_ACTIVE,
4060     EL_EMC_GATE_8_GRAY_ACTIVE,
4061     EL_DC_GATE_WHITE,
4062     EL_DC_GATE_WHITE_GRAY,
4063     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4064
4065     -1
4066   };
4067
4068   static int ep_amoeboid[] =
4069   {
4070     EL_AMOEBA_DEAD,
4071     EL_AMOEBA_WET,
4072     EL_AMOEBA_DRY,
4073     EL_AMOEBA_FULL,
4074     EL_BD_AMOEBA,
4075     EL_EMC_DRIPPER,
4076
4077     -1
4078   };
4079
4080   static int ep_amoebalive[] =
4081   {
4082     EL_AMOEBA_WET,
4083     EL_AMOEBA_DRY,
4084     EL_AMOEBA_FULL,
4085     EL_BD_AMOEBA,
4086     EL_EMC_DRIPPER,
4087
4088     -1
4089   };
4090
4091   static int ep_has_editor_content[] =
4092   {
4093     EL_PLAYER_1,
4094     EL_PLAYER_2,
4095     EL_PLAYER_3,
4096     EL_PLAYER_4,
4097     EL_SOKOBAN_FIELD_PLAYER,
4098     EL_SP_MURPHY,
4099     EL_YAMYAM,
4100     EL_YAMYAM_LEFT,
4101     EL_YAMYAM_RIGHT,
4102     EL_YAMYAM_UP,
4103     EL_YAMYAM_DOWN,
4104     EL_AMOEBA_WET,
4105     EL_AMOEBA_DRY,
4106     EL_AMOEBA_FULL,
4107     EL_BD_AMOEBA,
4108     EL_EMC_MAGIC_BALL,
4109     EL_EMC_ANDROID,
4110
4111     -1
4112   };
4113
4114   static int ep_can_turn_each_move[] =
4115   {
4116     // !!! do something with this one !!!
4117     -1
4118   };
4119
4120   static int ep_can_grow[] =
4121   {
4122     EL_BD_AMOEBA,
4123     EL_AMOEBA_DROP,
4124     EL_AMOEBA_WET,
4125     EL_AMOEBA_DRY,
4126     EL_AMOEBA_FULL,
4127     EL_GAME_OF_LIFE,
4128     EL_BIOMAZE,
4129     EL_EMC_DRIPPER,
4130
4131     -1
4132   };
4133
4134   static int ep_active_bomb[] =
4135   {
4136     EL_DYNAMITE_ACTIVE,
4137     EL_EM_DYNAMITE_ACTIVE,
4138     EL_DYNABOMB_PLAYER_1_ACTIVE,
4139     EL_DYNABOMB_PLAYER_2_ACTIVE,
4140     EL_DYNABOMB_PLAYER_3_ACTIVE,
4141     EL_DYNABOMB_PLAYER_4_ACTIVE,
4142     EL_SP_DISK_RED_ACTIVE,
4143
4144     -1
4145   };
4146
4147   static int ep_inactive[] =
4148   {
4149     EL_EMPTY,
4150     EL_EMPTY_SPACE_1,
4151     EL_EMPTY_SPACE_2,
4152     EL_EMPTY_SPACE_3,
4153     EL_EMPTY_SPACE_4,
4154     EL_EMPTY_SPACE_5,
4155     EL_EMPTY_SPACE_6,
4156     EL_EMPTY_SPACE_7,
4157     EL_EMPTY_SPACE_8,
4158     EL_EMPTY_SPACE_9,
4159     EL_EMPTY_SPACE_10,
4160     EL_EMPTY_SPACE_11,
4161     EL_EMPTY_SPACE_12,
4162     EL_EMPTY_SPACE_13,
4163     EL_EMPTY_SPACE_14,
4164     EL_EMPTY_SPACE_15,
4165     EL_EMPTY_SPACE_16,
4166     EL_SAND,
4167     EL_WALL,
4168     EL_BD_WALL,
4169     EL_WALL_SLIPPERY,
4170     EL_STEELWALL,
4171     EL_AMOEBA_DEAD,
4172     EL_QUICKSAND_EMPTY,
4173     EL_QUICKSAND_FAST_EMPTY,
4174     EL_STONEBLOCK,
4175     EL_ROBOT_WHEEL,
4176     EL_KEY_1,
4177     EL_KEY_2,
4178     EL_KEY_3,
4179     EL_KEY_4,
4180     EL_EM_KEY_1,
4181     EL_EM_KEY_2,
4182     EL_EM_KEY_3,
4183     EL_EM_KEY_4,
4184     EL_EMC_KEY_5,
4185     EL_EMC_KEY_6,
4186     EL_EMC_KEY_7,
4187     EL_EMC_KEY_8,
4188     EL_GATE_1,
4189     EL_GATE_2,
4190     EL_GATE_3,
4191     EL_GATE_4,
4192     EL_GATE_1_GRAY,
4193     EL_GATE_2_GRAY,
4194     EL_GATE_3_GRAY,
4195     EL_GATE_4_GRAY,
4196     EL_GATE_1_GRAY_ACTIVE,
4197     EL_GATE_2_GRAY_ACTIVE,
4198     EL_GATE_3_GRAY_ACTIVE,
4199     EL_GATE_4_GRAY_ACTIVE,
4200     EL_EM_GATE_1,
4201     EL_EM_GATE_2,
4202     EL_EM_GATE_3,
4203     EL_EM_GATE_4,
4204     EL_EM_GATE_1_GRAY,
4205     EL_EM_GATE_2_GRAY,
4206     EL_EM_GATE_3_GRAY,
4207     EL_EM_GATE_4_GRAY,
4208     EL_EM_GATE_1_GRAY_ACTIVE,
4209     EL_EM_GATE_2_GRAY_ACTIVE,
4210     EL_EM_GATE_3_GRAY_ACTIVE,
4211     EL_EM_GATE_4_GRAY_ACTIVE,
4212     EL_EMC_GATE_5,
4213     EL_EMC_GATE_6,
4214     EL_EMC_GATE_7,
4215     EL_EMC_GATE_8,
4216     EL_EMC_GATE_5_GRAY,
4217     EL_EMC_GATE_6_GRAY,
4218     EL_EMC_GATE_7_GRAY,
4219     EL_EMC_GATE_8_GRAY,
4220     EL_EMC_GATE_5_GRAY_ACTIVE,
4221     EL_EMC_GATE_6_GRAY_ACTIVE,
4222     EL_EMC_GATE_7_GRAY_ACTIVE,
4223     EL_EMC_GATE_8_GRAY_ACTIVE,
4224     EL_DC_GATE_WHITE,
4225     EL_DC_GATE_WHITE_GRAY,
4226     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4227     EL_DC_GATE_FAKE_GRAY,
4228     EL_DYNAMITE,
4229     EL_EM_DYNAMITE,
4230     EL_INVISIBLE_STEELWALL,
4231     EL_INVISIBLE_WALL,
4232     EL_INVISIBLE_SAND,
4233     EL_LAMP,
4234     EL_LAMP_ACTIVE,
4235     EL_WALL_EMERALD,
4236     EL_WALL_DIAMOND,
4237     EL_WALL_BD_DIAMOND,
4238     EL_WALL_EMERALD_YELLOW,
4239     EL_DYNABOMB_INCREASE_NUMBER,
4240     EL_DYNABOMB_INCREASE_SIZE,
4241     EL_DYNABOMB_INCREASE_POWER,
4242 #if 0
4243     EL_SOKOBAN_OBJECT,
4244 #endif
4245     EL_SOKOBAN_FIELD_EMPTY,
4246     EL_SOKOBAN_FIELD_FULL,
4247     EL_WALL_EMERALD_RED,
4248     EL_WALL_EMERALD_PURPLE,
4249     EL_ACID_POOL_TOPLEFT,
4250     EL_ACID_POOL_TOPRIGHT,
4251     EL_ACID_POOL_BOTTOMLEFT,
4252     EL_ACID_POOL_BOTTOM,
4253     EL_ACID_POOL_BOTTOMRIGHT,
4254     EL_MAGIC_WALL,
4255     EL_MAGIC_WALL_DEAD,
4256     EL_BD_MAGIC_WALL,
4257     EL_BD_MAGIC_WALL_DEAD,
4258     EL_DC_MAGIC_WALL,
4259     EL_DC_MAGIC_WALL_DEAD,
4260     EL_AMOEBA_TO_DIAMOND,
4261     EL_BLOCKED,
4262     EL_SP_EMPTY,
4263     EL_SP_BASE,
4264     EL_SP_PORT_RIGHT,
4265     EL_SP_PORT_DOWN,
4266     EL_SP_PORT_LEFT,
4267     EL_SP_PORT_UP,
4268     EL_SP_GRAVITY_PORT_RIGHT,
4269     EL_SP_GRAVITY_PORT_DOWN,
4270     EL_SP_GRAVITY_PORT_LEFT,
4271     EL_SP_GRAVITY_PORT_UP,
4272     EL_SP_PORT_HORIZONTAL,
4273     EL_SP_PORT_VERTICAL,
4274     EL_SP_PORT_ANY,
4275     EL_SP_DISK_RED,
4276 #if 0
4277     EL_SP_DISK_YELLOW,
4278 #endif
4279     EL_SP_CHIP_SINGLE,
4280     EL_SP_CHIP_LEFT,
4281     EL_SP_CHIP_RIGHT,
4282     EL_SP_CHIP_TOP,
4283     EL_SP_CHIP_BOTTOM,
4284     EL_SP_HARDWARE_GRAY,
4285     EL_SP_HARDWARE_GREEN,
4286     EL_SP_HARDWARE_BLUE,
4287     EL_SP_HARDWARE_RED,
4288     EL_SP_HARDWARE_YELLOW,
4289     EL_SP_HARDWARE_BASE_1,
4290     EL_SP_HARDWARE_BASE_2,
4291     EL_SP_HARDWARE_BASE_3,
4292     EL_SP_HARDWARE_BASE_4,
4293     EL_SP_HARDWARE_BASE_5,
4294     EL_SP_HARDWARE_BASE_6,
4295     EL_SP_GRAVITY_ON_PORT_LEFT,
4296     EL_SP_GRAVITY_ON_PORT_RIGHT,
4297     EL_SP_GRAVITY_ON_PORT_UP,
4298     EL_SP_GRAVITY_ON_PORT_DOWN,
4299     EL_SP_GRAVITY_OFF_PORT_LEFT,
4300     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4301     EL_SP_GRAVITY_OFF_PORT_UP,
4302     EL_SP_GRAVITY_OFF_PORT_DOWN,
4303     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4304     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4305     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4306     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4307     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4308     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4309     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4310     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4311     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4312     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4313     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4314     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4315     EL_SIGN_EXCLAMATION,
4316     EL_SIGN_RADIOACTIVITY,
4317     EL_SIGN_STOP,
4318     EL_SIGN_WHEELCHAIR,
4319     EL_SIGN_PARKING,
4320     EL_SIGN_NO_ENTRY,
4321     EL_SIGN_UNUSED_1,
4322     EL_SIGN_GIVE_WAY,
4323     EL_SIGN_ENTRY_FORBIDDEN,
4324     EL_SIGN_EMERGENCY_EXIT,
4325     EL_SIGN_YIN_YANG,
4326     EL_SIGN_UNUSED_2,
4327     EL_SIGN_SPERMS,
4328     EL_SIGN_BULLET,
4329     EL_SIGN_HEART,
4330     EL_SIGN_CROSS,
4331     EL_SIGN_FRANKIE,
4332     EL_DC_STEELWALL_1_LEFT,
4333     EL_DC_STEELWALL_1_RIGHT,
4334     EL_DC_STEELWALL_1_TOP,
4335     EL_DC_STEELWALL_1_BOTTOM,
4336     EL_DC_STEELWALL_1_HORIZONTAL,
4337     EL_DC_STEELWALL_1_VERTICAL,
4338     EL_DC_STEELWALL_1_TOPLEFT,
4339     EL_DC_STEELWALL_1_TOPRIGHT,
4340     EL_DC_STEELWALL_1_BOTTOMLEFT,
4341     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4342     EL_DC_STEELWALL_1_TOPLEFT_2,
4343     EL_DC_STEELWALL_1_TOPRIGHT_2,
4344     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4345     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4346     EL_DC_STEELWALL_2_LEFT,
4347     EL_DC_STEELWALL_2_RIGHT,
4348     EL_DC_STEELWALL_2_TOP,
4349     EL_DC_STEELWALL_2_BOTTOM,
4350     EL_DC_STEELWALL_2_HORIZONTAL,
4351     EL_DC_STEELWALL_2_VERTICAL,
4352     EL_DC_STEELWALL_2_MIDDLE,
4353     EL_DC_STEELWALL_2_SINGLE,
4354     EL_STEELWALL_SLIPPERY,
4355     EL_EMC_STEELWALL_1,
4356     EL_EMC_STEELWALL_2,
4357     EL_EMC_STEELWALL_3,
4358     EL_EMC_STEELWALL_4,
4359     EL_EMC_WALL_SLIPPERY_1,
4360     EL_EMC_WALL_SLIPPERY_2,
4361     EL_EMC_WALL_SLIPPERY_3,
4362     EL_EMC_WALL_SLIPPERY_4,
4363     EL_EMC_WALL_1,
4364     EL_EMC_WALL_2,
4365     EL_EMC_WALL_3,
4366     EL_EMC_WALL_4,
4367     EL_EMC_WALL_5,
4368     EL_EMC_WALL_6,
4369     EL_EMC_WALL_7,
4370     EL_EMC_WALL_8,
4371     EL_EMC_WALL_9,
4372     EL_EMC_WALL_10,
4373     EL_EMC_WALL_11,
4374     EL_EMC_WALL_12,
4375     EL_EMC_WALL_13,
4376     EL_EMC_WALL_14,
4377     EL_EMC_WALL_15,
4378     EL_EMC_WALL_16,
4379
4380     -1
4381   };
4382
4383   static int ep_em_slippery_wall[] =
4384   {
4385     -1
4386   };
4387
4388   static int ep_gfx_crumbled[] =
4389   {
4390     EL_SAND,
4391     EL_LANDMINE,
4392     EL_DC_LANDMINE,
4393     EL_TRAP,
4394     EL_TRAP_ACTIVE,
4395
4396     -1
4397   };
4398
4399   static int ep_editor_cascade_active[] =
4400   {
4401     EL_INTERNAL_CASCADE_BD_ACTIVE,
4402     EL_INTERNAL_CASCADE_EM_ACTIVE,
4403     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4404     EL_INTERNAL_CASCADE_RND_ACTIVE,
4405     EL_INTERNAL_CASCADE_SB_ACTIVE,
4406     EL_INTERNAL_CASCADE_SP_ACTIVE,
4407     EL_INTERNAL_CASCADE_DC_ACTIVE,
4408     EL_INTERNAL_CASCADE_DX_ACTIVE,
4409     EL_INTERNAL_CASCADE_MM_ACTIVE,
4410     EL_INTERNAL_CASCADE_DF_ACTIVE,
4411     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4412     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4413     EL_INTERNAL_CASCADE_CE_ACTIVE,
4414     EL_INTERNAL_CASCADE_GE_ACTIVE,
4415     EL_INTERNAL_CASCADE_ES_ACTIVE,
4416     EL_INTERNAL_CASCADE_REF_ACTIVE,
4417     EL_INTERNAL_CASCADE_USER_ACTIVE,
4418     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4419
4420     -1
4421   };
4422
4423   static int ep_editor_cascade_inactive[] =
4424   {
4425     EL_INTERNAL_CASCADE_BD,
4426     EL_INTERNAL_CASCADE_EM,
4427     EL_INTERNAL_CASCADE_EMC,
4428     EL_INTERNAL_CASCADE_RND,
4429     EL_INTERNAL_CASCADE_SB,
4430     EL_INTERNAL_CASCADE_SP,
4431     EL_INTERNAL_CASCADE_DC,
4432     EL_INTERNAL_CASCADE_DX,
4433     EL_INTERNAL_CASCADE_MM,
4434     EL_INTERNAL_CASCADE_DF,
4435     EL_INTERNAL_CASCADE_CHARS,
4436     EL_INTERNAL_CASCADE_STEEL_CHARS,
4437     EL_INTERNAL_CASCADE_CE,
4438     EL_INTERNAL_CASCADE_GE,
4439     EL_INTERNAL_CASCADE_ES,
4440     EL_INTERNAL_CASCADE_REF,
4441     EL_INTERNAL_CASCADE_USER,
4442     EL_INTERNAL_CASCADE_DYNAMIC,
4443
4444     -1
4445   };
4446
4447   static int ep_obsolete[] =
4448   {
4449     EL_PLAYER_OBSOLETE,
4450     EL_KEY_OBSOLETE,
4451     EL_EM_KEY_1_FILE_OBSOLETE,
4452     EL_EM_KEY_2_FILE_OBSOLETE,
4453     EL_EM_KEY_3_FILE_OBSOLETE,
4454     EL_EM_KEY_4_FILE_OBSOLETE,
4455     EL_ENVELOPE_OBSOLETE,
4456
4457     -1
4458   };
4459
4460   static struct
4461   {
4462     int *elements;
4463     int property;
4464   } element_properties[] =
4465   {
4466     { ep_diggable,                      EP_DIGGABLE                     },
4467     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4468     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4469     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4470     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4471     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4472     { ep_slippery,                      EP_SLIPPERY                     },
4473     { ep_can_change,                    EP_CAN_CHANGE                   },
4474     { ep_can_move,                      EP_CAN_MOVE                     },
4475     { ep_can_fall,                      EP_CAN_FALL                     },
4476     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4477     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4478     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4479     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4480     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4481     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4482     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4483     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4484     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4485     { ep_passable_over,                 EP_PASSABLE_OVER                },
4486     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4487     { ep_passable_under,                EP_PASSABLE_UNDER               },
4488     { ep_droppable,                     EP_DROPPABLE                    },
4489     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4490     { ep_pushable,                      EP_PUSHABLE                     },
4491     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4492     { ep_protected,                     EP_PROTECTED                    },
4493     { ep_throwable,                     EP_THROWABLE                    },
4494     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4495     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4496
4497     { ep_empty_space,                   EP_EMPTY_SPACE                  },
4498     { ep_player,                        EP_PLAYER                       },
4499     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4500     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4501     { ep_switchable,                    EP_SWITCHABLE                   },
4502     { ep_bd_element,                    EP_BD_ELEMENT                   },
4503     { ep_sp_element,                    EP_SP_ELEMENT                   },
4504     { ep_sb_element,                    EP_SB_ELEMENT                   },
4505     { ep_gem,                           EP_GEM                          },
4506     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4507     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4508     { ep_food_pig,                      EP_FOOD_PIG                     },
4509     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4510     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4511     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4512     { ep_belt,                          EP_BELT                         },
4513     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4514     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4515     { ep_tube,                          EP_TUBE                         },
4516     { ep_acid_pool,                     EP_ACID_POOL                    },
4517     { ep_keygate,                       EP_KEYGATE                      },
4518     { ep_amoeboid,                      EP_AMOEBOID                     },
4519     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4520     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4521     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4522     { ep_can_grow,                      EP_CAN_GROW                     },
4523     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4524     { ep_inactive,                      EP_INACTIVE                     },
4525
4526     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4527
4528     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4529
4530     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4531     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4532
4533     { ep_obsolete,                      EP_OBSOLETE                     },
4534
4535     { NULL,                             -1                              }
4536   };
4537
4538   int i, j, k;
4539
4540   // always start with reliable default values (element has no properties)
4541   // (but never initialize clipboard elements after the very first time)
4542   // (to be able to use clipboard elements between several levels)
4543   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4544     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4545       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4546         SET_PROPERTY(i, j, FALSE);
4547
4548   // set all base element properties from above array definitions
4549   for (i = 0; element_properties[i].elements != NULL; i++)
4550     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4551       SET_PROPERTY((element_properties[i].elements)[j],
4552                    element_properties[i].property, TRUE);
4553
4554   // copy properties to some elements that are only stored in level file
4555   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4556     for (j = 0; copy_properties[j][0] != -1; j++)
4557       if (HAS_PROPERTY(copy_properties[j][0], i))
4558         for (k = 1; k <= 4; k++)
4559           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4560
4561   // set static element properties that are not listed in array definitions
4562   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4563     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4564
4565   clipboard_elements_initialized = TRUE;
4566 }
4567
4568 void InitElementPropertiesEngine(int engine_version)
4569 {
4570   static int no_wall_properties[] =
4571   {
4572     EP_DIGGABLE,
4573     EP_COLLECTIBLE_ONLY,
4574     EP_DONT_RUN_INTO,
4575     EP_DONT_COLLIDE_WITH,
4576     EP_CAN_MOVE,
4577     EP_CAN_FALL,
4578     EP_CAN_SMASH_PLAYER,
4579     EP_CAN_SMASH_ENEMIES,
4580     EP_CAN_SMASH_EVERYTHING,
4581     EP_PUSHABLE,
4582
4583     EP_PLAYER,
4584     EP_GEM,
4585     EP_FOOD_DARK_YAMYAM,
4586     EP_FOOD_PENGUIN,
4587     EP_BELT,
4588     EP_BELT_ACTIVE,
4589     EP_TUBE,
4590     EP_AMOEBOID,
4591     EP_AMOEBALIVE,
4592     EP_ACTIVE_BOMB,
4593
4594     EP_ACCESSIBLE,
4595
4596     -1
4597   };
4598
4599   int i, j;
4600
4601   /* important: after initialization in InitElementPropertiesStatic(), the
4602      elements are not again initialized to a default value; therefore all
4603      changes have to make sure that they leave the element with a defined
4604      property (which means that conditional property changes must be set to
4605      a reliable default value before) */
4606
4607   // resolve group elements
4608   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4609     ResolveGroupElement(EL_GROUP_START + i);
4610
4611   // set all special, combined or engine dependent element properties
4612   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4613   {
4614     // do not change (already initialized) clipboard elements here
4615     if (IS_CLIPBOARD_ELEMENT(i))
4616       continue;
4617
4618     // ---------- INACTIVE ----------------------------------------------------
4619     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4620                                    i <= EL_CHAR_END) ||
4621                                   (i >= EL_STEEL_CHAR_START &&
4622                                    i <= EL_STEEL_CHAR_END)));
4623
4624     // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4625     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4626                                   IS_WALKABLE_INSIDE(i) ||
4627                                   IS_WALKABLE_UNDER(i)));
4628
4629     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4630                                   IS_PASSABLE_INSIDE(i) ||
4631                                   IS_PASSABLE_UNDER(i)));
4632
4633     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4634                                          IS_PASSABLE_OVER(i)));
4635
4636     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4637                                            IS_PASSABLE_INSIDE(i)));
4638
4639     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4640                                           IS_PASSABLE_UNDER(i)));
4641
4642     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4643                                     IS_PASSABLE(i)));
4644
4645     // ---------- COLLECTIBLE -------------------------------------------------
4646     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4647                                      IS_DROPPABLE(i) ||
4648                                      IS_THROWABLE(i)));
4649
4650     // ---------- SNAPPABLE ---------------------------------------------------
4651     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4652                                    IS_COLLECTIBLE(i) ||
4653                                    IS_SWITCHABLE(i) ||
4654                                    i == EL_BD_ROCK));
4655
4656     // ---------- WALL --------------------------------------------------------
4657     SET_PROPERTY(i, EP_WALL, TRUE);     // default: element is wall
4658
4659     for (j = 0; no_wall_properties[j] != -1; j++)
4660       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4661           i >= EL_FIRST_RUNTIME_UNREAL)
4662         SET_PROPERTY(i, EP_WALL, FALSE);
4663
4664     if (IS_HISTORIC_WALL(i))
4665       SET_PROPERTY(i, EP_WALL, TRUE);
4666
4667     // ---------- SOLID_FOR_PUSHING -------------------------------------------
4668     if (engine_version < VERSION_IDENT(2,2,0,0))
4669       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4670     else
4671       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4672                                              !IS_DIGGABLE(i) &&
4673                                              !IS_COLLECTIBLE(i)));
4674
4675     // ---------- DRAGONFIRE_PROOF --------------------------------------------
4676     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4677       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4678     else
4679       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4680                                             i != EL_ACID));
4681
4682     // ---------- EXPLOSION_PROOF ---------------------------------------------
4683     if (i == EL_FLAMES)
4684       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4685     else if (engine_version < VERSION_IDENT(2,2,0,0))
4686       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4687     else
4688       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4689                                            (!IS_WALKABLE(i) ||
4690                                             IS_PROTECTED(i))));
4691
4692     if (IS_CUSTOM_ELEMENT(i))
4693     {
4694       // these are additional properties which are initially false when set
4695
4696       // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4697       if (DONT_TOUCH(i))
4698         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4699       if (DONT_COLLIDE_WITH(i))
4700         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4701
4702       // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4703       if (CAN_SMASH_EVERYTHING(i))
4704         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4705       if (CAN_SMASH_ENEMIES(i))
4706         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4707     }
4708
4709     // ---------- CAN_SMASH ---------------------------------------------------
4710     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4711                                    CAN_SMASH_ENEMIES(i) ||
4712                                    CAN_SMASH_EVERYTHING(i)));
4713
4714     // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4715     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4716                                              EXPLODES_BY_FIRE(i)));
4717
4718     // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4719     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4720                                              EXPLODES_SMASHED(i)));
4721
4722     // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4723     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4724                                             EXPLODES_IMPACT(i)));
4725
4726     // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4727     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4728
4729     // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4730     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4731                                                   i == EL_BLACK_ORB));
4732
4733     // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4734     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
4735                                               CAN_MOVE(i) ||
4736                                               IS_CUSTOM_ELEMENT(i)));
4737
4738     // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4739     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4740                                                  i == EL_SP_ELECTRON));
4741
4742     // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4743     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4744       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4745                    getMoveIntoAcidProperty(&level, i));
4746
4747     // ---------- DONT_COLLIDE_WITH -------------------------------------------
4748     if (MAYBE_DONT_COLLIDE_WITH(i))
4749       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4750                    getDontCollideWithProperty(&level, i));
4751
4752     // ---------- SP_PORT -----------------------------------------------------
4753     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4754                                  IS_PASSABLE_INSIDE(i)));
4755
4756     // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4757     for (j = 0; j < level.num_android_clone_elements; j++)
4758       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4759                    (!IS_EMPTY(i) &&
4760                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4761
4762     // ---------- CAN_CHANGE --------------------------------------------------
4763     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      // default: cannot change
4764     for (j = 0; j < element_info[i].num_change_pages; j++)
4765       if (element_info[i].change_page[j].can_change)
4766         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4767
4768     // ---------- HAS_ACTION --------------------------------------------------
4769     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      // default: has no action
4770     for (j = 0; j < element_info[i].num_change_pages; j++)
4771       if (element_info[i].change_page[j].has_action)
4772         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4773
4774     // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4775     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4776                                                   HAS_ACTION(i)));
4777
4778     // ---------- GFX_CRUMBLED ------------------------------------------------
4779     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4780                  element_info[i].crumbled[ACTION_DEFAULT] !=
4781                  element_info[i].graphic[ACTION_DEFAULT]);
4782
4783     // ---------- EDITOR_CASCADE ----------------------------------------------
4784     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4785                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4786   }
4787
4788   // dynamically adjust element properties according to game engine version
4789   {
4790     static int ep_em_slippery_wall[] =
4791     {
4792       EL_WALL,
4793       EL_STEELWALL,
4794       EL_EXPANDABLE_WALL,
4795       EL_EXPANDABLE_WALL_HORIZONTAL,
4796       EL_EXPANDABLE_WALL_VERTICAL,
4797       EL_EXPANDABLE_WALL_ANY,
4798       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4799       EL_EXPANDABLE_STEELWALL_VERTICAL,
4800       EL_EXPANDABLE_STEELWALL_ANY,
4801       EL_EXPANDABLE_STEELWALL_GROWING,
4802       -1
4803     };
4804
4805     static int ep_em_explodes_by_fire[] =
4806     {
4807       EL_EM_DYNAMITE,
4808       EL_EM_DYNAMITE_ACTIVE,
4809       EL_MOLE,
4810       -1
4811     };
4812
4813     // special EM style gems behaviour
4814     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4815       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4816                    level.em_slippery_gems);
4817
4818     // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4819     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4820                  (level.em_slippery_gems &&
4821                   engine_version > VERSION_IDENT(2,0,1,0)));
4822
4823     // special EM style explosion behaviour regarding chain reactions
4824     for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4825       SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4826                    level.em_explodes_by_fire);
4827   }
4828
4829   // this is needed because some graphics depend on element properties
4830   if (game_status == GAME_MODE_PLAYING)
4831     InitElementGraphicInfo();
4832 }
4833
4834 void InitElementPropertiesGfxElement(void)
4835 {
4836   int i;
4837
4838   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4839   {
4840     struct ElementInfo *ei = &element_info[i];
4841
4842     ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4843   }
4844 }
4845
4846 static void InitGlobal(void)
4847 {
4848   int graphic;
4849   int i;
4850
4851   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4852   {
4853     // check if element_name_info entry defined for each element in "main.h"
4854     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4855       Fail("undefined 'element_name_info' entry for element %d", i);
4856
4857     element_info[i].token_name = element_name_info[i].token_name;
4858     element_info[i].class_name = element_name_info[i].class_name;
4859     element_info[i].editor_description= element_name_info[i].editor_description;
4860   }
4861
4862   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4863   {
4864     // check if global_anim_name_info defined for each entry in "main.h"
4865     if (i < NUM_GLOBAL_ANIM_TOKENS &&
4866         global_anim_name_info[i].token_name == NULL)
4867       Fail("undefined 'global_anim_name_info' entry for anim %d", i);
4868
4869     global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4870   }
4871
4872   // create hash from image config list
4873   image_config_hash = newSetupFileHash();
4874   for (i = 0; image_config[i].token != NULL; i++)
4875     setHashEntry(image_config_hash,
4876                  image_config[i].token,
4877                  image_config[i].value);
4878
4879   // create hash from element token list
4880   element_token_hash = newSetupFileHash();
4881   for (i = 0; element_name_info[i].token_name != NULL; i++)
4882     setHashEntry(element_token_hash,
4883                  element_name_info[i].token_name,
4884                  int2str(i, 0));
4885
4886   // create hash from graphic token list
4887   graphic_token_hash = newSetupFileHash();
4888   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4889     if (strSuffix(image_config[i].value, ".png") ||
4890         strSuffix(image_config[i].value, ".pcx") ||
4891         strSuffix(image_config[i].value, ".wav") ||
4892         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4893       setHashEntry(graphic_token_hash,
4894                    image_config[i].token,
4895                    int2str(graphic++, 0));
4896
4897   // create hash from font token list
4898   font_token_hash = newSetupFileHash();
4899   for (i = 0; font_info[i].token_name != NULL; i++)
4900     setHashEntry(font_token_hash,
4901                  font_info[i].token_name,
4902                  int2str(i, 0));
4903
4904   // set default filenames for all cloned graphics in static configuration
4905   for (i = 0; image_config[i].token != NULL; i++)
4906   {
4907     if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4908     {
4909       char *token = image_config[i].token;
4910       char *token_clone_from = getStringCat2(token, ".clone_from");
4911       char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4912
4913       if (token_cloned != NULL)
4914       {
4915         char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4916
4917         if (value_cloned != NULL)
4918         {
4919           // set default filename in static configuration
4920           image_config[i].value = value_cloned;
4921
4922           // set default filename in image config hash
4923           setHashEntry(image_config_hash, token, value_cloned);
4924         }
4925       }
4926
4927       free(token_clone_from);
4928     }
4929   }
4930
4931   // always start with reliable default values (all elements)
4932   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4933     ActiveElement[i] = i;
4934
4935   // now add all entries that have an active state (active elements)
4936   for (i = 0; element_with_active_state[i].element != -1; i++)
4937   {
4938     int element = element_with_active_state[i].element;
4939     int element_active = element_with_active_state[i].element_active;
4940
4941     ActiveElement[element] = element_active;
4942   }
4943
4944   // always start with reliable default values (all buttons)
4945   for (i = 0; i < NUM_IMAGE_FILES; i++)
4946     ActiveButton[i] = i;
4947
4948   // now add all entries that have an active state (active buttons)
4949   for (i = 0; button_with_active_state[i].button != -1; i++)
4950   {
4951     int button = button_with_active_state[i].button;
4952     int button_active = button_with_active_state[i].button_active;
4953
4954     ActiveButton[button] = button_active;
4955   }
4956
4957   // always start with reliable default values (all fonts)
4958   for (i = 0; i < NUM_FONTS; i++)
4959     ActiveFont[i] = i;
4960
4961   // now add all entries that have an active state (active fonts)
4962   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4963   {
4964     int font = font_with_active_state[i].font_nr;
4965     int font_active = font_with_active_state[i].font_nr_active;
4966
4967     ActiveFont[font] = font_active;
4968   }
4969
4970   global.autoplay_leveldir = NULL;
4971   global.patchtapes_leveldir = NULL;
4972   global.convert_leveldir = NULL;
4973   global.dumplevel_leveldir = NULL;
4974   global.dumptape_leveldir = NULL;
4975   global.create_sketch_images_dir = NULL;
4976   global.create_collect_images_dir = NULL;
4977
4978   global.frames_per_second = 0;
4979   global.show_frames_per_second = FALSE;
4980
4981   global.border_status = GAME_MODE_LOADING;
4982   global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4983
4984   global.use_envelope_request = FALSE;
4985
4986   global.user_names = NULL;
4987 }
4988
4989 static void Execute_Command(char *command)
4990 {
4991   int i;
4992
4993   if (strEqual(command, "print graphicsinfo.conf"))
4994   {
4995     Print("# You can configure additional/alternative image files here.\n");
4996     Print("# (The entries below are default and therefore commented out.)\n");
4997     Print("\n");
4998     Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4999     Print("\n");
5000     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5001     Print("\n");
5002
5003     for (i = 0; image_config[i].token != NULL; i++)
5004       Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
5005                                              image_config[i].value));
5006
5007     exit(0);
5008   }
5009   else if (strEqual(command, "print soundsinfo.conf"))
5010   {
5011     Print("# You can configure additional/alternative sound files here.\n");
5012     Print("# (The entries below are default and therefore commented out.)\n");
5013     Print("\n");
5014     Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
5015     Print("\n");
5016     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5017     Print("\n");
5018
5019     for (i = 0; sound_config[i].token != NULL; i++)
5020       Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
5021                                              sound_config[i].value));
5022
5023     exit(0);
5024   }
5025   else if (strEqual(command, "print musicinfo.conf"))
5026   {
5027     Print("# You can configure additional/alternative music files here.\n");
5028     Print("# (The entries below are default and therefore commented out.)\n");
5029     Print("\n");
5030     Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
5031     Print("\n");
5032     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
5033     Print("\n");
5034
5035     for (i = 0; music_config[i].token != NULL; i++)
5036       Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
5037                                              music_config[i].value));
5038
5039     exit(0);
5040   }
5041   else if (strEqual(command, "print editorsetup.conf"))
5042   {
5043     Print("# You can configure your personal editor element list here.\n");
5044     Print("# (The entries below are default and therefore commented out.)\n");
5045     Print("\n");
5046
5047     // this is needed to be able to check element list for cascade elements
5048     InitElementPropertiesStatic();
5049     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5050
5051     PrintEditorElementList();
5052
5053     exit(0);
5054   }
5055   else if (strEqual(command, "print helpanim.conf"))
5056   {
5057     Print("# You can configure different element help animations here.\n");
5058     Print("# (The entries below are default and therefore commented out.)\n");
5059     Print("\n");
5060
5061     for (i = 0; helpanim_config[i].token != NULL; i++)
5062     {
5063       Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
5064                                              helpanim_config[i].value));
5065
5066       if (strEqual(helpanim_config[i].token, "end"))
5067         Print("#\n");
5068     }
5069
5070     exit(0);
5071   }
5072   else if (strEqual(command, "print helptext.conf"))
5073   {
5074     Print("# You can configure different element help text here.\n");
5075     Print("# (The entries below are default and therefore commented out.)\n");
5076     Print("\n");
5077
5078     for (i = 0; helptext_config[i].token != NULL; i++)
5079       Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
5080                                              helptext_config[i].value));
5081
5082     exit(0);
5083   }
5084   else if (strPrefix(command, "dump level "))
5085   {
5086     char *filename = &command[11];
5087
5088     if (fileExists(filename))
5089     {
5090       LoadLevelFromFilename(&level, filename);
5091       DumpLevel(&level);
5092
5093       exit(0);
5094     }
5095
5096     char *leveldir = getStringCopy(filename);   // read command parameters
5097     char *level_nr = strchr(leveldir, ' ');
5098
5099     if (level_nr == NULL)
5100       Fail("cannot open file '%s'", filename);
5101
5102     *level_nr++ = '\0';
5103
5104     global.dumplevel_leveldir = leveldir;
5105     global.dumplevel_level_nr = atoi(level_nr);
5106
5107     program.headless = TRUE;
5108   }
5109   else if (strPrefix(command, "dump tape "))
5110   {
5111     char *filename = &command[10];
5112
5113     if (fileExists(filename))
5114     {
5115       LoadTapeFromFilename(filename);
5116       DumpTape(&tape);
5117
5118       exit(0);
5119     }
5120
5121     char *leveldir = getStringCopy(filename);   // read command parameters
5122     char *level_nr = strchr(leveldir, ' ');
5123
5124     if (level_nr == NULL)
5125       Fail("cannot open file '%s'", filename);
5126
5127     *level_nr++ = '\0';
5128
5129     global.dumptape_leveldir = leveldir;
5130     global.dumptape_level_nr = atoi(level_nr);
5131
5132     program.headless = TRUE;
5133   }
5134   else if (strPrefix(command, "autoplay ") ||
5135            strPrefix(command, "autoffwd ") ||
5136            strPrefix(command, "autowarp ") ||
5137            strPrefix(command, "autotest ") ||
5138            strPrefix(command, "autosave ") ||
5139            strPrefix(command, "autoupload ") ||
5140            strPrefix(command, "autofix "))
5141   {
5142     char *arg_ptr = strchr(command, ' ');
5143     char *str_ptr = getStringCopy(arg_ptr);     // read command parameters
5144
5145     global.autoplay_mode =
5146       (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5147        strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5148        strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5149        strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5150        strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
5151        strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
5152        strPrefix(command, "autofix")  ? AUTOPLAY_MODE_FIX :
5153        AUTOPLAY_MODE_NONE);
5154
5155     while (*str_ptr != '\0')                    // continue parsing string
5156     {
5157       // cut leading whitespace from string, replace it by string terminator
5158       while (*str_ptr == ' ' || *str_ptr == '\t')
5159         *str_ptr++ = '\0';
5160
5161       if (*str_ptr == '\0')                     // end of string reached
5162         break;
5163
5164       if (global.autoplay_leveldir == NULL)     // read level set string
5165       {
5166         global.autoplay_leveldir = str_ptr;
5167         global.autoplay_all = TRUE;             // default: play all tapes
5168
5169         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5170           global.autoplay_level[i] = FALSE;
5171       }
5172       else                                      // read level number string
5173       {
5174         int level_nr = atoi(str_ptr);           // get level_nr value
5175
5176         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5177           global.autoplay_level[level_nr] = TRUE;
5178
5179         global.autoplay_all = FALSE;
5180       }
5181
5182       // advance string pointer to the next whitespace (or end of string)
5183       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5184         str_ptr++;
5185     }
5186
5187     if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
5188       program.headless = TRUE;
5189   }
5190   else if (strPrefix(command, "patch tapes "))
5191   {
5192     char *str_ptr = getStringCopy(&command[12]); // read command parameters
5193
5194     // skip leading whitespace
5195     while (*str_ptr == ' ' || *str_ptr == '\t')
5196       str_ptr++;
5197
5198     if (*str_ptr == '\0')
5199       Fail("cannot find MODE in command '%s'", command);
5200
5201     global.patchtapes_mode = str_ptr;           // store patch mode
5202
5203     // advance to next whitespace (or end of string)
5204     while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5205       str_ptr++;
5206
5207     while (*str_ptr != '\0')                    // continue parsing string
5208     {
5209       // cut leading whitespace from string, replace it by string terminator
5210       while (*str_ptr == ' ' || *str_ptr == '\t')
5211         *str_ptr++ = '\0';
5212
5213       if (*str_ptr == '\0')                     // end of string reached
5214         break;
5215
5216       if (global.patchtapes_leveldir == NULL)   // read level set string
5217       {
5218         global.patchtapes_leveldir = str_ptr;
5219         global.patchtapes_all = TRUE;           // default: patch all tapes
5220
5221         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5222           global.patchtapes_level[i] = FALSE;
5223       }
5224       else                                      // read level number string
5225       {
5226         int level_nr = atoi(str_ptr);           // get level_nr value
5227
5228         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5229           global.patchtapes_level[level_nr] = TRUE;
5230
5231         global.patchtapes_all = FALSE;
5232       }
5233
5234       // advance string pointer to the next whitespace (or end of string)
5235       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5236         str_ptr++;
5237     }
5238
5239     if (global.patchtapes_leveldir == NULL)
5240     {
5241       if (strEqual(global.patchtapes_mode, "help"))
5242         global.patchtapes_leveldir = UNDEFINED_LEVELSET;
5243       else
5244         Fail("cannot find LEVELDIR in command '%s'", command);
5245     }
5246
5247     program.headless = TRUE;
5248   }
5249   else if (strPrefix(command, "convert "))
5250   {
5251     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5252     char *str_ptr = strchr(str_copy, ' ');
5253
5254     global.convert_leveldir = str_copy;
5255     global.convert_level_nr = -1;
5256
5257     if (str_ptr != NULL)                        // level number follows
5258     {
5259       *str_ptr++ = '\0';                        // terminate leveldir string
5260       global.convert_level_nr = atoi(str_ptr);  // get level_nr value
5261     }
5262
5263     program.headless = TRUE;
5264   }
5265   else if (strPrefix(command, "create sketch images "))
5266   {
5267     global.create_sketch_images_dir = getStringCopy(&command[21]);
5268
5269     if (access(global.create_sketch_images_dir, W_OK) != 0)
5270       Fail("image target directory '%s' not found or not writable",
5271            global.create_sketch_images_dir);
5272   }
5273   else if (strPrefix(command, "create collect image "))
5274   {
5275     global.create_collect_images_dir = getStringCopy(&command[21]);
5276
5277     if (access(global.create_collect_images_dir, W_OK) != 0)
5278       Fail("image target directory '%s' not found or not writable",
5279            global.create_collect_images_dir);
5280   }
5281   else if (strPrefix(command, "create CE image "))
5282   {
5283     CreateCustomElementImages(&command[16]);
5284
5285     exit(0);
5286   }
5287   else
5288   {
5289     FailWithHelp("unrecognized command '%s'", command);
5290   }
5291
5292   // disable networking if any valid command was recognized
5293   options.network = setup.network_mode = FALSE;
5294 }
5295
5296 static void InitSetup(void)
5297 {
5298   LoadUserNames();                              // global user names
5299   LoadUserSetup();                              // global user number
5300
5301   LoadSetup();                                  // global setup info
5302
5303   // set some options from setup file
5304
5305   if (setup.options.verbose)
5306     options.verbose = TRUE;
5307
5308   if (setup.debug.show_frames_per_second)
5309     global.show_frames_per_second = TRUE;
5310 }
5311
5312 static void InitGameInfo(void)
5313 {
5314   game.restart_level = FALSE;
5315   game.restart_game_message = NULL;
5316
5317   game.request_active = FALSE;
5318   game.request_active_or_moving = FALSE;
5319
5320   game.use_masked_elements_initial = FALSE;
5321 }
5322
5323 static void InitPlayerInfo(void)
5324 {
5325   int i;
5326
5327   // choose default local player
5328   local_player = &stored_player[0];
5329
5330   for (i = 0; i < MAX_PLAYERS; i++)
5331   {
5332     stored_player[i].connected_locally = FALSE;
5333     stored_player[i].connected_network = FALSE;
5334   }
5335
5336   local_player->connected_locally = TRUE;
5337 }
5338
5339 static void InitArtworkInfo(void)
5340 {
5341   LoadArtworkInfo();
5342 }
5343
5344 static char *get_string_in_brackets(char *string)
5345 {
5346   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5347
5348   sprintf(string_in_brackets, "[%s]", string);
5349
5350   return string_in_brackets;
5351 }
5352
5353 static char *get_level_id_suffix(int id_nr)
5354 {
5355   char *id_suffix = checked_malloc(1 + 3 + 1);
5356
5357   if (id_nr < 0 || id_nr > 999)
5358     id_nr = 0;
5359
5360   sprintf(id_suffix, ".%03d", id_nr);
5361
5362   return id_suffix;
5363 }
5364
5365 static void InitArtworkConfig(void)
5366 {
5367   static char *image_id_prefix[MAX_NUM_ELEMENTS +
5368                                NUM_FONTS +
5369                                NUM_GLOBAL_ANIM_TOKENS + 1];
5370   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5371                                NUM_GLOBAL_ANIM_TOKENS + 1];
5372   static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5373                                NUM_GLOBAL_ANIM_TOKENS + 1];
5374   static char *action_id_suffix[NUM_ACTIONS + 1];
5375   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5376   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5377   static char *level_id_suffix[MAX_LEVELS + 1];
5378   static char *dummy[1] = { NULL };
5379   static char *ignore_generic_tokens[] =
5380   {
5381     "name",
5382     "sort_priority",
5383     "program_title",
5384     "program_copyright",
5385     "program_company",
5386
5387     NULL
5388   };
5389   static char **ignore_image_tokens;
5390   static char **ignore_sound_tokens;
5391   static char **ignore_music_tokens;
5392   int num_ignore_generic_tokens;
5393   int num_ignore_image_tokens;
5394   int num_ignore_sound_tokens;
5395   int num_ignore_music_tokens;
5396   int i;
5397
5398   // dynamically determine list of generic tokens to be ignored
5399   num_ignore_generic_tokens = 0;
5400   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5401     num_ignore_generic_tokens++;
5402
5403   // dynamically determine list of image tokens to be ignored
5404   num_ignore_image_tokens = num_ignore_generic_tokens;
5405   for (i = 0; image_config_vars[i].token != NULL; i++)
5406     num_ignore_image_tokens++;
5407   ignore_image_tokens =
5408     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5409   for (i = 0; i < num_ignore_generic_tokens; i++)
5410     ignore_image_tokens[i] = ignore_generic_tokens[i];
5411   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5412     ignore_image_tokens[num_ignore_generic_tokens + i] =
5413       image_config_vars[i].token;
5414   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5415
5416   // dynamically determine list of sound tokens to be ignored
5417   num_ignore_sound_tokens = num_ignore_generic_tokens;
5418   ignore_sound_tokens =
5419     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5420   for (i = 0; i < num_ignore_generic_tokens; i++)
5421     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5422   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5423
5424   // dynamically determine list of music tokens to be ignored
5425   num_ignore_music_tokens = num_ignore_generic_tokens;
5426   ignore_music_tokens =
5427     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5428   for (i = 0; i < num_ignore_generic_tokens; i++)
5429     ignore_music_tokens[i] = ignore_generic_tokens[i];
5430   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5431
5432   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5433     image_id_prefix[i] = element_info[i].token_name;
5434   for (i = 0; i < NUM_FONTS; i++)
5435     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5436   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5437     image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5438       global_anim_info[i].token_name;
5439   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5440
5441   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5442     sound_id_prefix[i] = element_info[i].token_name;
5443   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5444     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5445       get_string_in_brackets(element_info[i].class_name);
5446   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5447     sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5448       global_anim_info[i].token_name;
5449   sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5450
5451   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5452     music_id_prefix[i] = music_prefix_info[i].prefix;
5453   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5454     music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5455       global_anim_info[i].token_name;
5456   music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5457
5458   for (i = 0; i < NUM_ACTIONS; i++)
5459     action_id_suffix[i] = element_action_info[i].suffix;
5460   action_id_suffix[NUM_ACTIONS] = NULL;
5461
5462   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5463     direction_id_suffix[i] = element_direction_info[i].suffix;
5464   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5465
5466   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5467     special_id_suffix[i] = special_suffix_info[i].suffix;
5468   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5469
5470   for (i = 0; i < MAX_LEVELS; i++)
5471     level_id_suffix[i] = get_level_id_suffix(i);
5472   level_id_suffix[MAX_LEVELS] = NULL;
5473
5474   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5475                 image_id_prefix, action_id_suffix, direction_id_suffix,
5476                 special_id_suffix, ignore_image_tokens);
5477   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5478                 sound_id_prefix, action_id_suffix, dummy,
5479                 special_id_suffix, ignore_sound_tokens);
5480   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5481                 music_id_prefix, action_id_suffix, special_id_suffix,
5482                 level_id_suffix, ignore_music_tokens);
5483 }
5484
5485 static void InitMixer(void)
5486 {
5487   OpenAudio();
5488
5489   StartMixer();
5490 }
5491
5492 static void InitVideoOverlay(void)
5493 {
5494   // if virtual buttons are not loaded from setup file, repeat initializing
5495   // virtual buttons grid with default values now that video is initialized
5496   if (!setup.touch.grid_initialized)
5497     InitSetup();
5498
5499   InitTileCursorInfo();
5500   InitOverlayInfo();
5501 }
5502
5503 void InitGfxBuffers(void)
5504 {
5505   static int win_xsize_last = -1;
5506   static int win_ysize_last = -1;
5507
5508   // create additional image buffers for double-buffering and cross-fading
5509
5510   if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5511   {
5512     // used to temporarily store the backbuffer -- only re-create if changed
5513     ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5514     ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5515
5516     win_xsize_last = WIN_XSIZE;
5517     win_ysize_last = WIN_YSIZE;
5518   }
5519
5520   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5521   ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5522   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5523   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5524
5525   // initialize screen properties
5526   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5527                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5528                    bitmap_db_field);
5529   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5530   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5531   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5532   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5533   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5534   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5535
5536   // required if door size definitions have changed
5537   InitGraphicCompatibilityInfo_Doors();
5538
5539   InitGfxBuffers_EM();
5540   InitGfxBuffers_SP();
5541 }
5542
5543 static void InitGfx(void)
5544 {
5545   struct GraphicInfo *graphic_info_last = graphic_info;
5546   char *filename_font_initial = NULL;
5547   char *filename_anim_initial = NULL;
5548   Bitmap *bitmap_font_initial = NULL;
5549   int i, j;
5550
5551   // determine settings for initial font (for displaying startup messages)
5552   for (i = 0; image_config[i].token != NULL; i++)
5553   {
5554     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5555     {
5556       char font_token[128];
5557       int len_font_token;
5558
5559       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5560       len_font_token = strlen(font_token);
5561
5562       if (strEqual(image_config[i].token, font_token))
5563         filename_font_initial = image_config[i].value;
5564       else if (strlen(image_config[i].token) > len_font_token &&
5565                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5566       {
5567         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5568           font_initial[j].src_x = atoi(image_config[i].value);
5569         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5570           font_initial[j].src_y = atoi(image_config[i].value);
5571         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5572           font_initial[j].width = atoi(image_config[i].value);
5573         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5574           font_initial[j].height = atoi(image_config[i].value);
5575       }
5576     }
5577   }
5578
5579   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5580   {
5581     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5582     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5583   }
5584
5585   if (filename_font_initial == NULL)    // should not happen
5586     Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5587
5588   InitGfxBuffers();
5589   InitGfxCustomArtworkInfo();
5590   InitGfxOtherSettings();
5591
5592   InitGfxTileSizeInfo(TILESIZE, TILESIZE);
5593
5594   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5595
5596   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5597     font_initial[j].bitmap = bitmap_font_initial;
5598
5599   InitFontGraphicInfo();
5600
5601   DrawProgramInfo();
5602
5603   DrawInitTextHead("Loading graphics");
5604
5605   InitMenuDesignSettings_Static();
5606
5607   // initialize settings for busy animation with default values
5608   int parameter[NUM_GFX_ARGS];
5609   for (i = 0; i < NUM_GFX_ARGS; i++)
5610     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5611                                                image_config_suffix[i].token,
5612                                                image_config_suffix[i].type);
5613
5614   char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5615   int len_anim_token = strlen(anim_token);
5616
5617   // read settings for busy animation from default custom artwork config
5618   char *gfx_config_filename = getPath3(options.graphics_directory,
5619                                        GFX_DEFAULT_SUBDIR,
5620                                        GRAPHICSINFO_FILENAME);
5621
5622   if (fileExists(gfx_config_filename))
5623   {
5624     SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5625
5626     if (setup_file_hash)
5627     {
5628       char *filename = getHashEntry(setup_file_hash, anim_token);
5629
5630       if (filename)
5631       {
5632         filename_anim_initial = getStringCopy(filename);
5633
5634         for (j = 0; image_config_suffix[j].token != NULL; j++)
5635         {
5636           int type = image_config_suffix[j].type;
5637           char *suffix = image_config_suffix[j].token;
5638           char *token = getStringCat2(anim_token, suffix);
5639           char *value = getHashEntry(setup_file_hash, token);
5640
5641           checked_free(token);
5642
5643           if (value)
5644             parameter[j] = get_graphic_parameter_value(value, suffix, type);
5645         }
5646       }
5647
5648       // read values from custom graphics config file
5649       InitMenuDesignSettings_FromHash(setup_file_hash, FALSE);
5650
5651       freeSetupFileHash(setup_file_hash);
5652     }
5653   }
5654
5655   if (filename_anim_initial == NULL)
5656   {
5657     // read settings for busy animation from static default artwork config
5658     for (i = 0; image_config[i].token != NULL; i++)
5659     {
5660       if (strEqual(image_config[i].token, anim_token))
5661         filename_anim_initial = getStringCopy(image_config[i].value);
5662       else if (strlen(image_config[i].token) > len_anim_token &&
5663                strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5664       {
5665         for (j = 0; image_config_suffix[j].token != NULL; j++)
5666         {
5667           if (strEqual(&image_config[i].token[len_anim_token],
5668                        image_config_suffix[j].token))
5669             parameter[j] =
5670               get_graphic_parameter_value(image_config[i].value,
5671                                           image_config_suffix[j].token,
5672                                           image_config_suffix[j].type);
5673         }
5674       }
5675     }
5676   }
5677
5678   if (filename_anim_initial == NULL)    // should not happen
5679     Fail("cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5680
5681   anim_initial.bitmaps =
5682     checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5683
5684   anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5685     LoadCustomImage(filename_anim_initial);
5686
5687   checked_free(filename_anim_initial);
5688
5689   graphic_info = &anim_initial;         // graphic == 0 => anim_initial
5690
5691   set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5692
5693   graphic_info = graphic_info_last;
5694
5695   init.busy.width  = anim_initial.width;
5696   init.busy.height = anim_initial.height;
5697
5698   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5699   InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5700   InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5701   InitGfxDrawTileCursorFunction(DrawTileCursor);
5702
5703   gfx.fade_border_source_status = global.border_status;
5704   gfx.fade_border_target_status = global.border_status;
5705   gfx.masked_border_bitmap_ptr = backbuffer;
5706
5707   // use copy of busy animation to prevent change while reloading artwork
5708   init_last = init;
5709 }
5710
5711 static void InitGfxBackground(void)
5712 {
5713   fieldbuffer = bitmap_db_field;
5714   SetDrawtoField(DRAW_TO_BACKBUFFER);
5715
5716   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5717
5718   redraw_mask = REDRAW_ALL;
5719 }
5720
5721 static void InitLevelInfo(void)
5722 {
5723   LoadLevelInfo();                              // global level info
5724   LoadLevelSetup_LastSeries();                  // last played series info
5725   LoadLevelSetup_SeriesInfo();                  // last played level info
5726
5727   if (global.autoplay_leveldir &&
5728       global.autoplay_mode != AUTOPLAY_MODE_TEST)
5729   {
5730     leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5731                                                  global.autoplay_leveldir);
5732     if (leveldir_current == NULL)
5733       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5734   }
5735
5736   SetLevelSetInfo(leveldir_current->identifier, level_nr);
5737 }
5738
5739 static void InitLevelArtworkInfo(void)
5740 {
5741   LoadLevelArtworkInfo();
5742 }
5743
5744 static void InitImages(void)
5745 {
5746   print_timestamp_init("InitImages");
5747
5748 #if 0
5749   Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5750         leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5751   Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5752         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5753   Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5754         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5755   Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5756         leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5757 #endif
5758
5759   setLevelArtworkDir(artwork.gfx_first);
5760
5761 #if 0
5762   Debug("init:InitImages", "leveldir_current->identifier == '%s'",
5763         leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5764   Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
5765         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5766   Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
5767          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5768   Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5769         leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5770 #endif
5771
5772 #if 0
5773   Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
5774         leveldir_current->identifier,
5775         artwork.gfx_current_identifier,
5776         artwork.gfx_current->identifier,
5777         leveldir_current->graphics_set,
5778         leveldir_current->graphics_path);
5779 #endif
5780
5781   UPDATE_BUSY_STATE();
5782
5783   ReloadCustomImages();
5784   print_timestamp_time("ReloadCustomImages");
5785
5786   UPDATE_BUSY_STATE();
5787
5788   LoadCustomElementDescriptions();
5789   print_timestamp_time("LoadCustomElementDescriptions");
5790
5791   UPDATE_BUSY_STATE();
5792
5793   LoadMenuDesignSettings();
5794   print_timestamp_time("LoadMenuDesignSettings");
5795
5796   UPDATE_BUSY_STATE();
5797
5798   ReinitializeGraphics();
5799   print_timestamp_time("ReinitializeGraphics");
5800
5801   LoadMenuDesignSettings_AfterGraphics();
5802   print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5803
5804   UPDATE_BUSY_STATE();
5805
5806   print_timestamp_done("InitImages");
5807 }
5808
5809 static void InitSound(char *identifier)
5810 {
5811   print_timestamp_init("InitSound");
5812
5813   if (identifier == NULL)
5814     identifier = artwork.snd_current->identifier;
5815
5816   // set artwork path to send it to the sound server process
5817   setLevelArtworkDir(artwork.snd_first);
5818
5819   InitReloadCustomSounds(identifier);
5820   print_timestamp_time("InitReloadCustomSounds");
5821
5822   ReinitializeSounds();
5823   print_timestamp_time("ReinitializeSounds");
5824
5825   print_timestamp_done("InitSound");
5826 }
5827
5828 static void InitMusic(char *identifier)
5829 {
5830   print_timestamp_init("InitMusic");
5831
5832   if (identifier == NULL)
5833     identifier = artwork.mus_current->identifier;
5834
5835   // set artwork path to send it to the sound server process
5836   setLevelArtworkDir(artwork.mus_first);
5837
5838   InitReloadCustomMusic(identifier);
5839   print_timestamp_time("InitReloadCustomMusic");
5840
5841   ReinitializeMusic();
5842   print_timestamp_time("ReinitializeMusic");
5843
5844   print_timestamp_done("InitMusic");
5845 }
5846
5847 static void InitArtworkDone(void)
5848 {
5849   if (program.headless)
5850     return;
5851
5852   InitGlobalAnimations();
5853 }
5854
5855 static void InitNetworkSettings(void)
5856 {
5857   boolean network_enabled = (options.network || setup.network_mode);
5858   char *network_server = (options.server_host != NULL ? options.server_host :
5859                           setup.network_server_hostname);
5860
5861   if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5862     network_server = NULL;
5863
5864   InitNetworkInfo(network_enabled,
5865                   FALSE,
5866                   options.serveronly,
5867                   network_server,
5868                   options.server_port);
5869 }
5870
5871 void InitNetworkServer(void)
5872 {
5873   if (!network.enabled || network.connected)
5874     return;
5875
5876   LimitScreenUpdates(FALSE);
5877
5878   if (game_status == GAME_MODE_LOADING)
5879     DrawProgramInfo();
5880
5881   if (!ConnectToServer(network.server_host, network.server_port))
5882   {
5883     network.enabled = FALSE;
5884
5885     setup.network_mode = FALSE;
5886   }
5887   else
5888   {
5889     SendToServer_ProtocolVersion();
5890     SendToServer_PlayerName(setup.player_name);
5891     SendToServer_NrWanted(setup.network_player_nr + 1);
5892
5893     network.connected = TRUE;
5894   }
5895
5896   // short time to recognize result of network initialization
5897   if (game_status == GAME_MODE_LOADING)
5898     Delay_WithScreenUpdates(1000);
5899 }
5900
5901 static boolean CheckArtworkConfigForCustomElements(char *filename)
5902 {
5903   SetupFileHash *setup_file_hash;
5904   boolean redefined_ce_found = FALSE;
5905
5906   // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5907
5908   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5909   {
5910     BEGIN_HASH_ITERATION(setup_file_hash, itr)
5911     {
5912       char *token = HASH_ITERATION_TOKEN(itr);
5913
5914       if (strPrefix(token, "custom_"))
5915       {
5916         redefined_ce_found = TRUE;
5917
5918         break;
5919       }
5920     }
5921     END_HASH_ITERATION(setup_file_hash, itr)
5922
5923     freeSetupFileHash(setup_file_hash);
5924   }
5925
5926   return redefined_ce_found;
5927 }
5928
5929 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5930 {
5931   char *filename_base, *filename_local;
5932   boolean redefined_ce_found = FALSE;
5933
5934   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5935
5936 #if 0
5937   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5938         "leveldir_current->identifier == '%s'",
5939         leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5940   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5941         "leveldir_current->graphics_path == '%s'",
5942         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5943   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5944         "leveldir_current->graphics_set == '%s'",
5945         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5946   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5947         "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
5948         leveldir_current == NULL ? "[NULL]" :
5949         LEVELDIR_ARTWORK_SET(leveldir_current, type));
5950 #endif
5951
5952   // first look for special artwork configured in level series config
5953   filename_base = getCustomArtworkLevelConfigFilename(type);
5954
5955 #if 0
5956   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5957         "filename_base == '%s'", filename_base);
5958 #endif
5959
5960   if (fileExists(filename_base))
5961     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5962
5963   filename_local = getCustomArtworkConfigFilename(type);
5964
5965 #if 0
5966   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5967         "filename_local == '%s'", filename_local);
5968 #endif
5969
5970   if (filename_local != NULL && !strEqual(filename_base, filename_local))
5971     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5972
5973 #if 0
5974   Debug("init:CheckArtworkTypeForRedefinedCustomElements",
5975         "redefined_ce_found == %d", redefined_ce_found);
5976 #endif
5977
5978   return redefined_ce_found;
5979 }
5980
5981 static void InitOverrideArtwork(void)
5982 {
5983   boolean redefined_ce_found = FALSE;
5984
5985   // to check if this level set redefines any CEs, do not use overriding
5986   gfx.override_level_graphics = FALSE;
5987   gfx.override_level_sounds   = FALSE;
5988   gfx.override_level_music    = FALSE;
5989
5990   // now check if this level set has definitions for custom elements
5991   if (setup.override_level_graphics == AUTO ||
5992       setup.override_level_sounds   == AUTO ||
5993       setup.override_level_music    == AUTO)
5994     redefined_ce_found =
5995       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5996        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5997        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5998
5999 #if 0
6000   Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
6001         redefined_ce_found);
6002 #endif
6003
6004   if (redefined_ce_found)
6005   {
6006     // this level set has CE definitions: change "AUTO" to "FALSE"
6007     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
6008     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
6009     gfx.override_level_music    = (setup.override_level_music    == TRUE);
6010   }
6011   else
6012   {
6013     // this level set has no CE definitions: change "AUTO" to "TRUE"
6014     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
6015     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
6016     gfx.override_level_music    = (setup.override_level_music    != FALSE);
6017   }
6018
6019 #if 0
6020   Debug("init:InitOverrideArtwork", "%d, %d, %d",
6021         gfx.override_level_graphics,
6022         gfx.override_level_sounds,
6023         gfx.override_level_music);
6024 #endif
6025 }
6026
6027 static char *getNewArtworkIdentifier(int type)
6028 {
6029   static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
6030   static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
6031   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
6032   static boolean last_has_custom_artwork_set[3] = { FALSE, FALSE, FALSE };
6033   static boolean initialized[3] = { FALSE, FALSE, FALSE };
6034   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
6035   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
6036   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
6037   char *leveldir_identifier = leveldir_current->identifier;
6038   // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
6039   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
6040   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
6041   TreeInfo *custom_artwork_set =
6042     getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier);
6043   boolean has_custom_artwork_set = (custom_artwork_set != NULL);
6044   char *artwork_current_identifier;
6045   char *artwork_new_identifier = NULL;  // default: nothing has changed
6046
6047   // leveldir_current may be invalid (level group, parent link)
6048   if (!validLevelSeries(leveldir_current))
6049     return NULL;
6050
6051   /* 1st step: determine artwork set to be activated in descending order:
6052      --------------------------------------------------------------------
6053      1. setup artwork (when configured to override everything else)
6054      2. artwork set configured in "levelinfo.conf" of current level set
6055         (artwork in level directory will have priority when loading later)
6056      3. artwork in level directory (stored in artwork sub-directory)
6057      4. setup artwork (currently configured in setup menu) */
6058
6059   if (setup_override_artwork)
6060     artwork_current_identifier = setup_artwork_set;
6061   else if (has_level_artwork_set)
6062     artwork_current_identifier = leveldir_artwork_set;
6063   else if (has_custom_artwork_set)
6064     artwork_current_identifier = leveldir_identifier;
6065   else
6066     artwork_current_identifier = setup_artwork_set;
6067
6068   /* 2nd step: check if it is really needed to reload artwork set
6069      ------------------------------------------------------------ */
6070
6071   // ---------- reload if level set and also artwork set has changed ----------
6072   if (last_leveldir_identifier[type] != leveldir_identifier &&
6073       (last_has_custom_artwork_set[type] || has_custom_artwork_set))
6074     artwork_new_identifier = artwork_current_identifier;
6075
6076   last_leveldir_identifier[type] = leveldir_identifier;
6077   last_has_custom_artwork_set[type] = has_custom_artwork_set;
6078
6079   // ---------- reload if "override artwork" setting has changed --------------
6080   if (last_override_level_artwork[type] != setup_override_artwork)
6081     artwork_new_identifier = artwork_current_identifier;
6082
6083   last_override_level_artwork[type] = setup_override_artwork;
6084
6085   // ---------- reload if current artwork identifier has changed --------------
6086   if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
6087     artwork_new_identifier = artwork_current_identifier;
6088
6089   // (we cannot compare string pointers here, so copy string content itself)
6090   setString(&last_artwork_identifier[type], artwork_current_identifier);
6091
6092   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
6093
6094   // ---------- do not reload directly after starting -------------------------
6095   if (!initialized[type])
6096     artwork_new_identifier = NULL;
6097
6098   initialized[type] = TRUE;
6099
6100   return artwork_new_identifier;
6101 }
6102
6103 void ReloadCustomArtwork(int force_reload)
6104 {
6105   int last_game_status = game_status;   // save current game status
6106   char *gfx_new_identifier;
6107   char *snd_new_identifier;
6108   char *mus_new_identifier;
6109   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
6110   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
6111   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
6112   boolean reload_needed;
6113
6114   InitOverrideArtwork();
6115
6116   AdjustGraphicsForEMC();
6117   AdjustSoundsForEMC();
6118
6119   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
6120   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
6121   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
6122
6123   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
6124                    snd_new_identifier != NULL || force_reload_snd ||
6125                    mus_new_identifier != NULL || force_reload_mus);
6126
6127   if (!reload_needed)
6128     return;
6129
6130   print_timestamp_init("ReloadCustomArtwork");
6131
6132   SetGameStatus(GAME_MODE_LOADING);
6133
6134   FadeOut(REDRAW_ALL);
6135
6136   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6137   print_timestamp_time("ClearRectangle");
6138
6139   FadeIn(REDRAW_ALL);
6140
6141   if (gfx_new_identifier != NULL || force_reload_gfx)
6142   {
6143 #if 0
6144     Debug("init:ReloadCustomArtwork",
6145           "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
6146           artwork.gfx_current_identifier,
6147           gfx_new_identifier,
6148           artwork.gfx_current->identifier,
6149           leveldir_current->graphics_set);
6150 #endif
6151
6152     InitImages();
6153     print_timestamp_time("InitImages");
6154   }
6155
6156   if (snd_new_identifier != NULL || force_reload_snd)
6157   {
6158     InitSound(snd_new_identifier);
6159     print_timestamp_time("InitSound");
6160   }
6161
6162   if (mus_new_identifier != NULL || force_reload_mus)
6163   {
6164     InitMusic(mus_new_identifier);
6165     print_timestamp_time("InitMusic");
6166   }
6167
6168   InitArtworkDone();
6169
6170   SetGameStatus(last_game_status);      // restore current game status
6171
6172   init_last = init;                     // switch to new busy animation
6173
6174   FadeOut(REDRAW_ALL);
6175
6176   RedrawGlobalBorder();
6177
6178   // force redraw of (open or closed) door graphics
6179   SetDoorState(DOOR_OPEN_ALL);
6180   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
6181
6182   FadeSetEnterScreen();
6183   FadeSkipNextFadeOut();
6184
6185   print_timestamp_done("ReloadCustomArtwork");
6186
6187   LimitScreenUpdates(FALSE);
6188 }
6189
6190 void KeyboardAutoRepeatOffUnlessAutoplay(void)
6191 {
6192   if (global.autoplay_leveldir == NULL)
6193     KeyboardAutoRepeatOff();
6194 }
6195
6196 void DisplayExitMessage(char *format, va_list ap)
6197 {
6198   // also check for initialized video (headless flag may be temporarily unset)
6199   if (program.headless || !video.initialized)
6200     return;
6201
6202   // check if draw buffer and fonts for exit message are already available
6203   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
6204     return;
6205
6206   int font_1 = FC_RED;
6207   int font_2 = FC_YELLOW;
6208   int font_3 = FC_BLUE;
6209   int font_width = getFontWidth(font_2);
6210   int font_height = getFontHeight(font_2);
6211   int sx = SX;
6212   int sy = SY;
6213   int sxsize = WIN_XSIZE - 2 * sx;
6214   int sysize = WIN_YSIZE - 2 * sy;
6215   int line_length = sxsize / font_width;
6216   int max_lines = sysize / font_height;
6217   int num_lines_printed;
6218
6219   gfx.sx = sx;
6220   gfx.sy = sy;
6221   gfx.sxsize = sxsize;
6222   gfx.sysize = sysize;
6223
6224   sy = 20;
6225
6226   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6227
6228   DrawTextSCentered(sy, font_1, "Fatal error:");
6229   sy += 3 * font_height;;
6230
6231   num_lines_printed =
6232     DrawTextBufferVA(sx, sy, format, ap, font_2,
6233                      line_length, line_length, max_lines,
6234                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6235   sy += (num_lines_printed + 3) * font_height;
6236
6237   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6238   sy += 3 * font_height;
6239
6240   num_lines_printed =
6241     DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6242                    line_length, line_length, max_lines,
6243                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6244
6245   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6246
6247   redraw_mask = REDRAW_ALL;
6248
6249   // force drawing exit message even if screen updates are currently limited
6250   LimitScreenUpdates(FALSE);
6251
6252   BackToFront();
6253
6254   // deactivate toons on error message screen
6255   setup.toons = FALSE;
6256
6257   WaitForEventToContinue();
6258 }
6259
6260
6261 // ============================================================================
6262 // OpenAll()
6263 // ============================================================================
6264
6265 void OpenAll(void)
6266 {
6267   print_timestamp_init("OpenAll");
6268
6269   SetGameStatus(GAME_MODE_LOADING);
6270
6271   InitCounter();
6272
6273   InitGlobal();                 // initialize some global variables
6274
6275   InitRND(NEW_RANDOMIZE);
6276   InitSimpleRandom(NEW_RANDOMIZE);
6277   InitBetterRandom(NEW_RANDOMIZE);
6278
6279   print_timestamp_time("[init global stuff]");
6280
6281   InitSetup();
6282
6283   print_timestamp_time("[init setup/config stuff (1)]");
6284
6285   if (options.execute_command)
6286     Execute_Command(options.execute_command);
6287
6288   InitNetworkSettings();
6289
6290   InitRuntimeInfo();
6291
6292   if (network.serveronly)
6293   {
6294 #if defined(PLATFORM_UNIX)
6295     NetworkServer(network.server_port, TRUE);
6296 #else
6297     Warn("networking only supported in Unix version");
6298 #endif
6299
6300     exit(0);                    // never reached, server loops forever
6301   }
6302
6303   InitGameInfo();
6304   print_timestamp_time("[init setup/config stuff (2)]");
6305   InitPlayerInfo();
6306   print_timestamp_time("[init setup/config stuff (3)]");
6307   InitArtworkInfo();            // needed before loading gfx, sound & music
6308   print_timestamp_time("[init setup/config stuff (4)]");
6309   InitArtworkConfig();          // needed before forking sound child process
6310   print_timestamp_time("[init setup/config stuff (5)]");
6311   InitMixer();
6312   print_timestamp_time("[init setup/config stuff (6)]");
6313
6314   InitJoysticks();
6315
6316   print_timestamp_time("[init setup/config stuff]");
6317
6318   InitVideoDefaults();
6319   InitVideoDisplay();
6320   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6321   InitVideoOverlay();
6322
6323   InitEventFilter(FilterMouseMotionEvents);
6324
6325   print_timestamp_time("[init video stuff]");
6326
6327   InitElementPropertiesStatic();
6328   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6329   InitElementPropertiesGfxElement();
6330
6331   print_timestamp_time("[init element properties stuff]");
6332
6333   InitGfx();
6334
6335   print_timestamp_time("InitGfx");
6336
6337   InitLevelInfo();
6338   print_timestamp_time("InitLevelInfo");
6339
6340   InitLevelArtworkInfo();
6341   print_timestamp_time("InitLevelArtworkInfo");
6342
6343   InitOverrideArtwork();        // needs to know current level directory
6344   print_timestamp_time("InitOverrideArtwork");
6345
6346   InitImages();                 // needs to know current level directory
6347   print_timestamp_time("InitImages");
6348
6349   InitSound(NULL);              // needs to know current level directory
6350   print_timestamp_time("InitSound");
6351
6352   InitMusic(NULL);              // needs to know current level directory
6353   print_timestamp_time("InitMusic");
6354
6355   InitArtworkDone();
6356
6357   InitGfxBackground();
6358
6359   em_open_all();
6360   sp_open_all();
6361   mm_open_all();
6362
6363   if (global.autoplay_leveldir)
6364   {
6365     AutoPlayTapes();
6366     return;
6367   }
6368   else if (global.patchtapes_leveldir)
6369   {
6370     PatchTapes();
6371     return;
6372   }
6373   else if (global.convert_leveldir)
6374   {
6375     ConvertLevels();
6376     return;
6377   }
6378   else if (global.dumplevel_leveldir)
6379   {
6380     DumpLevels();
6381     return;
6382   }
6383   else if (global.dumptape_leveldir)
6384   {
6385     DumpTapes();
6386     return;
6387   }
6388   else if (global.create_sketch_images_dir)
6389   {
6390     CreateLevelSketchImages();
6391     return;
6392   }
6393   else if (global.create_collect_images_dir)
6394   {
6395     CreateCollectElementImages();
6396     return;
6397   }
6398
6399   InitNetworkServer();
6400
6401   SetGameStatus(GAME_MODE_MAIN);
6402
6403   FadeSetEnterScreen();
6404   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6405     FadeSkipNextFadeOut();
6406
6407   print_timestamp_time("[post-artwork]");
6408
6409   print_timestamp_done("OpenAll");
6410
6411   if (setup.ask_for_remaining_tapes)
6412     setup.ask_for_uploading_tapes = TRUE;
6413
6414   DrawMainMenu();
6415
6416 #if 0
6417   Debug("internal:path", "SDL_GetBasePath() == '%s'",
6418         SDL_GetBasePath());
6419   Debug("internal:path", "SDL_GetPrefPath() == '%s'",
6420         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6421 #if defined(PLATFORM_ANDROID)
6422   Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
6423         SDL_AndroidGetInternalStoragePath());
6424   Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
6425         SDL_AndroidGetExternalStoragePath());
6426   Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
6427         (SDL_AndroidGetExternalStorageState() &
6428          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6429          SDL_AndroidGetExternalStorageState() &
6430          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6431 #endif
6432 #endif
6433 }
6434
6435 static boolean WaitForApiThreads(void)
6436 {
6437   unsigned int thread_delay = 0;
6438   unsigned int thread_delay_value = 10000;
6439
6440   if (program.api_thread_count == 0)
6441     return TRUE;
6442
6443   // deactivate global animations (not accessible in game state "loading")
6444   setup.toons = FALSE;
6445
6446   // set game state to "loading" to be able to show busy animation
6447   SetGameStatus(GAME_MODE_LOADING);
6448
6449   ResetDelayCounter(&thread_delay);
6450
6451   // wait for threads to finish (and fail on timeout)
6452   while (program.api_thread_count > 0)
6453   {
6454     if (DelayReached(&thread_delay, thread_delay_value))
6455     {
6456       Error("failed waiting for threads - TIMEOUT");
6457
6458       return FALSE;
6459     }
6460
6461     UPDATE_BUSY_STATE();
6462
6463     Delay(20);
6464   }
6465
6466   return TRUE;
6467 }
6468
6469 void CloseAllAndExit(int exit_value)
6470 {
6471   WaitForApiThreads();
6472
6473   StopSounds();
6474   FreeAllSounds();
6475   FreeAllMusic();
6476   CloseAudio();         // called after freeing sounds (needed for SDL)
6477
6478   em_close_all();
6479   sp_close_all();
6480
6481   FreeAllImages();
6482
6483   // !!! TODO !!!
6484   // set a flag to tell the network server thread to quit and wait for it
6485   // using SDL_WaitThread()
6486   //
6487   // Code used with SDL 1.2:
6488   // if (network.server_thread) // terminate network server
6489   //   SDL_KillThread(network.server_thread);
6490
6491   CloseVideoDisplay();
6492   ClosePlatformDependentStuff();
6493
6494   if (exit_value != 0 && !options.execute_command)
6495   {
6496     // fall back to default level set (current set may have caused an error)
6497     SaveLevelSetup_LastSeries_Deactivate();
6498
6499     // tell user where to find error log file which may contain more details
6500     // (error notification now directly displayed on screen inside R'n'D
6501     // NotifyUserAboutErrorFile();      // currently only works for Windows
6502   }
6503
6504   exit(exit_value);
6505 }