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