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