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