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