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