version number set to 4.2.0.0
[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_AMOEBA_DROPPING,
2866     EL_QUICKSAND_FULL,
2867     EL_QUICKSAND_FAST_FULL,
2868     EL_MAGIC_WALL_FULL,
2869     EL_BD_MAGIC_WALL_FULL,
2870     EL_DC_MAGIC_WALL_FULL,
2871     EL_TIME_ORB_FULL,
2872     EL_TIME_ORB_EMPTY,
2873     EL_SP_ZONK,
2874     EL_SP_INFOTRON,
2875     EL_SP_DISK_ORANGE,
2876     EL_PEARL,
2877     EL_CRYSTAL,
2878     EL_SPRING,
2879     EL_DX_SUPABOMB,
2880
2881     -1
2882   };
2883
2884   static int ep_can_smash_player[] =
2885   {
2886     EL_ROCK,
2887     EL_BD_ROCK,
2888     EL_EMERALD,
2889     EL_BD_DIAMOND,
2890     EL_EMERALD_YELLOW,
2891     EL_EMERALD_RED,
2892     EL_EMERALD_PURPLE,
2893     EL_DIAMOND,
2894     EL_BOMB,
2895     EL_NUT,
2896     EL_AMOEBA_DROP,
2897     EL_TIME_ORB_FULL,
2898     EL_TIME_ORB_EMPTY,
2899     EL_SP_ZONK,
2900     EL_SP_INFOTRON,
2901     EL_SP_DISK_ORANGE,
2902     EL_PEARL,
2903     EL_CRYSTAL,
2904     EL_SPRING,
2905     EL_DX_SUPABOMB,
2906
2907     -1
2908   };
2909
2910   static int ep_can_smash_enemies[] =
2911   {
2912     EL_ROCK,
2913     EL_BD_ROCK,
2914     EL_SP_ZONK,
2915
2916     -1
2917   };
2918
2919   static int ep_can_smash_everything[] =
2920   {
2921     EL_ROCK,
2922     EL_BD_ROCK,
2923     EL_SP_ZONK,
2924
2925     -1
2926   };
2927
2928   static int ep_explodes_by_fire[] =
2929   {
2930     // same elements as in 'ep_explodes_impact'
2931     EL_BOMB,
2932     EL_SP_DISK_ORANGE,
2933     EL_DX_SUPABOMB,
2934
2935     // same elements as in 'ep_explodes_smashed'
2936     EL_SATELLITE,
2937     EL_PIG,
2938     EL_DRAGON,
2939     EL_MOLE,
2940
2941     // new elements
2942     EL_DYNAMITE,
2943     EL_DYNAMITE_ACTIVE,
2944     EL_EM_DYNAMITE,
2945     EL_EM_DYNAMITE_ACTIVE,
2946     EL_DYNABOMB_PLAYER_1_ACTIVE,
2947     EL_DYNABOMB_PLAYER_2_ACTIVE,
2948     EL_DYNABOMB_PLAYER_3_ACTIVE,
2949     EL_DYNABOMB_PLAYER_4_ACTIVE,
2950     EL_DYNABOMB_INCREASE_NUMBER,
2951     EL_DYNABOMB_INCREASE_SIZE,
2952     EL_DYNABOMB_INCREASE_POWER,
2953     EL_SP_DISK_RED_ACTIVE,
2954     EL_BUG,
2955     EL_PENGUIN,
2956     EL_SP_DISK_RED,
2957     EL_SP_DISK_YELLOW,
2958     EL_SP_SNIKSNAK,
2959     EL_SP_ELECTRON,
2960 #if 0
2961     EL_BLACK_ORB,
2962 #endif
2963
2964     -1
2965   };
2966
2967   static int ep_explodes_smashed[] =
2968   {
2969     // same elements as in 'ep_explodes_impact'
2970     EL_BOMB,
2971     EL_SP_DISK_ORANGE,
2972     EL_DX_SUPABOMB,
2973
2974     // new elements
2975     EL_SATELLITE,
2976     EL_PIG,
2977     EL_DRAGON,
2978     EL_MOLE,
2979
2980     -1
2981   };
2982
2983   static int ep_explodes_impact[] =
2984   {
2985     EL_BOMB,
2986     EL_SP_DISK_ORANGE,
2987     EL_DX_SUPABOMB,
2988
2989     -1
2990   };
2991
2992   static int ep_walkable_over[] =
2993   {
2994     EL_EMPTY_SPACE,
2995     EL_SP_EMPTY_SPACE,
2996     EL_SOKOBAN_FIELD_EMPTY,
2997     EL_EXIT_OPEN,
2998     EL_EM_EXIT_OPEN,
2999     EL_EM_EXIT_OPENING,
3000     EL_SP_EXIT_OPEN,
3001     EL_SP_EXIT_OPENING,
3002     EL_STEEL_EXIT_OPEN,
3003     EL_EM_STEEL_EXIT_OPEN,
3004     EL_EM_STEEL_EXIT_OPENING,
3005     EL_GATE_1,
3006     EL_GATE_2,
3007     EL_GATE_3,
3008     EL_GATE_4,
3009     EL_GATE_1_GRAY,
3010     EL_GATE_2_GRAY,
3011     EL_GATE_3_GRAY,
3012     EL_GATE_4_GRAY,
3013     EL_GATE_1_GRAY_ACTIVE,
3014     EL_GATE_2_GRAY_ACTIVE,
3015     EL_GATE_3_GRAY_ACTIVE,
3016     EL_GATE_4_GRAY_ACTIVE,
3017     EL_PENGUIN,
3018     EL_PIG,
3019     EL_DRAGON,
3020
3021     -1
3022   };
3023
3024   static int ep_walkable_inside[] =
3025   {
3026     EL_TUBE_ANY,
3027     EL_TUBE_VERTICAL,
3028     EL_TUBE_HORIZONTAL,
3029     EL_TUBE_VERTICAL_LEFT,
3030     EL_TUBE_VERTICAL_RIGHT,
3031     EL_TUBE_HORIZONTAL_UP,
3032     EL_TUBE_HORIZONTAL_DOWN,
3033     EL_TUBE_LEFT_UP,
3034     EL_TUBE_LEFT_DOWN,
3035     EL_TUBE_RIGHT_UP,
3036     EL_TUBE_RIGHT_DOWN,
3037
3038     -1
3039   };
3040
3041   static int ep_walkable_under[] =
3042   {
3043     -1
3044   };
3045
3046   static int ep_passable_over[] =
3047   {
3048     EL_EM_GATE_1,
3049     EL_EM_GATE_2,
3050     EL_EM_GATE_3,
3051     EL_EM_GATE_4,
3052     EL_EM_GATE_1_GRAY,
3053     EL_EM_GATE_2_GRAY,
3054     EL_EM_GATE_3_GRAY,
3055     EL_EM_GATE_4_GRAY,
3056     EL_EM_GATE_1_GRAY_ACTIVE,
3057     EL_EM_GATE_2_GRAY_ACTIVE,
3058     EL_EM_GATE_3_GRAY_ACTIVE,
3059     EL_EM_GATE_4_GRAY_ACTIVE,
3060     EL_EMC_GATE_5,
3061     EL_EMC_GATE_6,
3062     EL_EMC_GATE_7,
3063     EL_EMC_GATE_8,
3064     EL_EMC_GATE_5_GRAY,
3065     EL_EMC_GATE_6_GRAY,
3066     EL_EMC_GATE_7_GRAY,
3067     EL_EMC_GATE_8_GRAY,
3068     EL_EMC_GATE_5_GRAY_ACTIVE,
3069     EL_EMC_GATE_6_GRAY_ACTIVE,
3070     EL_EMC_GATE_7_GRAY_ACTIVE,
3071     EL_EMC_GATE_8_GRAY_ACTIVE,
3072     EL_DC_GATE_WHITE,
3073     EL_DC_GATE_WHITE_GRAY,
3074     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3075     EL_SWITCHGATE_OPEN,
3076     EL_TIMEGATE_OPEN,
3077
3078     -1
3079   };
3080
3081   static int ep_passable_inside[] =
3082   {
3083     EL_SP_PORT_LEFT,
3084     EL_SP_PORT_RIGHT,
3085     EL_SP_PORT_UP,
3086     EL_SP_PORT_DOWN,
3087     EL_SP_PORT_HORIZONTAL,
3088     EL_SP_PORT_VERTICAL,
3089     EL_SP_PORT_ANY,
3090     EL_SP_GRAVITY_PORT_LEFT,
3091     EL_SP_GRAVITY_PORT_RIGHT,
3092     EL_SP_GRAVITY_PORT_UP,
3093     EL_SP_GRAVITY_PORT_DOWN,
3094     EL_SP_GRAVITY_ON_PORT_LEFT,
3095     EL_SP_GRAVITY_ON_PORT_RIGHT,
3096     EL_SP_GRAVITY_ON_PORT_UP,
3097     EL_SP_GRAVITY_ON_PORT_DOWN,
3098     EL_SP_GRAVITY_OFF_PORT_LEFT,
3099     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3100     EL_SP_GRAVITY_OFF_PORT_UP,
3101     EL_SP_GRAVITY_OFF_PORT_DOWN,
3102
3103     -1
3104   };
3105
3106   static int ep_passable_under[] =
3107   {
3108     -1
3109   };
3110
3111   static int ep_droppable[] =
3112   {
3113     -1
3114   };
3115
3116   static int ep_explodes_1x1_old[] =
3117   {
3118     -1
3119   };
3120
3121   static int ep_pushable[] =
3122   {
3123     EL_ROCK,
3124     EL_BOMB,
3125     EL_DX_SUPABOMB,
3126     EL_NUT,
3127     EL_TIME_ORB_EMPTY,
3128     EL_SP_ZONK,
3129     EL_SP_DISK_ORANGE,
3130     EL_SPRING,
3131     EL_BD_ROCK,
3132     EL_SOKOBAN_OBJECT,
3133     EL_SOKOBAN_FIELD_FULL,
3134     EL_SATELLITE,
3135     EL_SP_DISK_YELLOW,
3136     EL_BALLOON,
3137     EL_EMC_ANDROID,
3138
3139     -1
3140   };
3141
3142   static int ep_explodes_cross_old[] =
3143   {
3144     -1
3145   };
3146
3147   static int ep_protected[] =
3148   {
3149     // same elements as in 'ep_walkable_inside'
3150     EL_TUBE_ANY,
3151     EL_TUBE_VERTICAL,
3152     EL_TUBE_HORIZONTAL,
3153     EL_TUBE_VERTICAL_LEFT,
3154     EL_TUBE_VERTICAL_RIGHT,
3155     EL_TUBE_HORIZONTAL_UP,
3156     EL_TUBE_HORIZONTAL_DOWN,
3157     EL_TUBE_LEFT_UP,
3158     EL_TUBE_LEFT_DOWN,
3159     EL_TUBE_RIGHT_UP,
3160     EL_TUBE_RIGHT_DOWN,
3161
3162     // same elements as in 'ep_passable_over'
3163     EL_EM_GATE_1,
3164     EL_EM_GATE_2,
3165     EL_EM_GATE_3,
3166     EL_EM_GATE_4,
3167     EL_EM_GATE_1_GRAY,
3168     EL_EM_GATE_2_GRAY,
3169     EL_EM_GATE_3_GRAY,
3170     EL_EM_GATE_4_GRAY,
3171     EL_EM_GATE_1_GRAY_ACTIVE,
3172     EL_EM_GATE_2_GRAY_ACTIVE,
3173     EL_EM_GATE_3_GRAY_ACTIVE,
3174     EL_EM_GATE_4_GRAY_ACTIVE,
3175     EL_EMC_GATE_5,
3176     EL_EMC_GATE_6,
3177     EL_EMC_GATE_7,
3178     EL_EMC_GATE_8,
3179     EL_EMC_GATE_5_GRAY,
3180     EL_EMC_GATE_6_GRAY,
3181     EL_EMC_GATE_7_GRAY,
3182     EL_EMC_GATE_8_GRAY,
3183     EL_EMC_GATE_5_GRAY_ACTIVE,
3184     EL_EMC_GATE_6_GRAY_ACTIVE,
3185     EL_EMC_GATE_7_GRAY_ACTIVE,
3186     EL_EMC_GATE_8_GRAY_ACTIVE,
3187     EL_DC_GATE_WHITE,
3188     EL_DC_GATE_WHITE_GRAY,
3189     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3190     EL_SWITCHGATE_OPEN,
3191     EL_TIMEGATE_OPEN,
3192
3193     // same elements as in 'ep_passable_inside'
3194     EL_SP_PORT_LEFT,
3195     EL_SP_PORT_RIGHT,
3196     EL_SP_PORT_UP,
3197     EL_SP_PORT_DOWN,
3198     EL_SP_PORT_HORIZONTAL,
3199     EL_SP_PORT_VERTICAL,
3200     EL_SP_PORT_ANY,
3201     EL_SP_GRAVITY_PORT_LEFT,
3202     EL_SP_GRAVITY_PORT_RIGHT,
3203     EL_SP_GRAVITY_PORT_UP,
3204     EL_SP_GRAVITY_PORT_DOWN,
3205     EL_SP_GRAVITY_ON_PORT_LEFT,
3206     EL_SP_GRAVITY_ON_PORT_RIGHT,
3207     EL_SP_GRAVITY_ON_PORT_UP,
3208     EL_SP_GRAVITY_ON_PORT_DOWN,
3209     EL_SP_GRAVITY_OFF_PORT_LEFT,
3210     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3211     EL_SP_GRAVITY_OFF_PORT_UP,
3212     EL_SP_GRAVITY_OFF_PORT_DOWN,
3213
3214     -1
3215   };
3216
3217   static int ep_throwable[] =
3218   {
3219     -1
3220   };
3221
3222   static int ep_can_explode[] =
3223   {
3224     // same elements as in 'ep_explodes_impact'
3225     EL_BOMB,
3226     EL_SP_DISK_ORANGE,
3227     EL_DX_SUPABOMB,
3228
3229     // same elements as in 'ep_explodes_smashed'
3230     EL_SATELLITE,
3231     EL_PIG,
3232     EL_DRAGON,
3233     EL_MOLE,
3234
3235     // elements that can explode by explosion or by dragonfire
3236     EL_DYNAMITE,
3237     EL_DYNAMITE_ACTIVE,
3238     EL_EM_DYNAMITE,
3239     EL_EM_DYNAMITE_ACTIVE,
3240     EL_DYNABOMB_PLAYER_1_ACTIVE,
3241     EL_DYNABOMB_PLAYER_2_ACTIVE,
3242     EL_DYNABOMB_PLAYER_3_ACTIVE,
3243     EL_DYNABOMB_PLAYER_4_ACTIVE,
3244     EL_DYNABOMB_INCREASE_NUMBER,
3245     EL_DYNABOMB_INCREASE_SIZE,
3246     EL_DYNABOMB_INCREASE_POWER,
3247     EL_SP_DISK_RED_ACTIVE,
3248     EL_BUG,
3249     EL_PENGUIN,
3250     EL_SP_DISK_RED,
3251     EL_SP_DISK_YELLOW,
3252     EL_SP_SNIKSNAK,
3253     EL_SP_ELECTRON,
3254
3255     // elements that can explode only by explosion
3256     EL_BLACK_ORB,
3257
3258     -1
3259   };
3260
3261   static int ep_gravity_reachable[] =
3262   {
3263     EL_SAND,
3264     EL_SP_BASE,
3265     EL_TRAP,
3266     EL_INVISIBLE_SAND,
3267     EL_INVISIBLE_SAND_ACTIVE,
3268     EL_SP_PORT_LEFT,
3269     EL_SP_PORT_RIGHT,
3270     EL_SP_PORT_UP,
3271     EL_SP_PORT_DOWN,
3272     EL_SP_PORT_HORIZONTAL,
3273     EL_SP_PORT_VERTICAL,
3274     EL_SP_PORT_ANY,
3275     EL_SP_GRAVITY_PORT_LEFT,
3276     EL_SP_GRAVITY_PORT_RIGHT,
3277     EL_SP_GRAVITY_PORT_UP,
3278     EL_SP_GRAVITY_PORT_DOWN,
3279     EL_SP_GRAVITY_ON_PORT_LEFT,
3280     EL_SP_GRAVITY_ON_PORT_RIGHT,
3281     EL_SP_GRAVITY_ON_PORT_UP,
3282     EL_SP_GRAVITY_ON_PORT_DOWN,
3283     EL_SP_GRAVITY_OFF_PORT_LEFT,
3284     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3285     EL_SP_GRAVITY_OFF_PORT_UP,
3286     EL_SP_GRAVITY_OFF_PORT_DOWN,
3287     EL_EMC_GRASS,
3288
3289     -1
3290   };
3291
3292   static int ep_player[] =
3293   {
3294     EL_PLAYER_1,
3295     EL_PLAYER_2,
3296     EL_PLAYER_3,
3297     EL_PLAYER_4,
3298     EL_SP_MURPHY,
3299     EL_SOKOBAN_FIELD_PLAYER,
3300     EL_TRIGGER_PLAYER,
3301
3302     -1
3303   };
3304
3305   static int ep_can_pass_magic_wall[] =
3306   {
3307     EL_ROCK,
3308     EL_BD_ROCK,
3309     EL_EMERALD,
3310     EL_BD_DIAMOND,
3311     EL_EMERALD_YELLOW,
3312     EL_EMERALD_RED,
3313     EL_EMERALD_PURPLE,
3314     EL_DIAMOND,
3315
3316     -1
3317   };
3318
3319   static int ep_can_pass_dc_magic_wall[] =
3320   {
3321     EL_ROCK,
3322     EL_BD_ROCK,
3323     EL_EMERALD,
3324     EL_BD_DIAMOND,
3325     EL_EMERALD_YELLOW,
3326     EL_EMERALD_RED,
3327     EL_EMERALD_PURPLE,
3328     EL_DIAMOND,
3329     EL_PEARL,
3330     EL_CRYSTAL,
3331
3332     -1
3333   };
3334
3335   static int ep_switchable[] =
3336   {
3337     EL_ROBOT_WHEEL,
3338     EL_SP_TERMINAL,
3339     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3340     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3341     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3342     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3343     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3344     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3345     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3346     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3347     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3348     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3349     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3350     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3351     EL_SWITCHGATE_SWITCH_UP,
3352     EL_SWITCHGATE_SWITCH_DOWN,
3353     EL_DC_SWITCHGATE_SWITCH_UP,
3354     EL_DC_SWITCHGATE_SWITCH_DOWN,
3355     EL_LIGHT_SWITCH,
3356     EL_LIGHT_SWITCH_ACTIVE,
3357     EL_TIMEGATE_SWITCH,
3358     EL_DC_TIMEGATE_SWITCH,
3359     EL_BALLOON_SWITCH_LEFT,
3360     EL_BALLOON_SWITCH_RIGHT,
3361     EL_BALLOON_SWITCH_UP,
3362     EL_BALLOON_SWITCH_DOWN,
3363     EL_BALLOON_SWITCH_ANY,
3364     EL_BALLOON_SWITCH_NONE,
3365     EL_LAMP,
3366     EL_TIME_ORB_FULL,
3367     EL_EMC_MAGIC_BALL_SWITCH,
3368     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3369
3370     -1
3371   };
3372
3373   static int ep_bd_element[] =
3374   {
3375     EL_EMPTY,
3376     EL_SAND,
3377     EL_WALL_SLIPPERY,
3378     EL_BD_WALL,
3379     EL_ROCK,
3380     EL_BD_ROCK,
3381     EL_BD_DIAMOND,
3382     EL_BD_MAGIC_WALL,
3383     EL_EXIT_CLOSED,
3384     EL_EXIT_OPEN,
3385     EL_STEELWALL,
3386     EL_PLAYER_1,
3387     EL_PLAYER_2,
3388     EL_PLAYER_3,
3389     EL_PLAYER_4,
3390     EL_BD_FIREFLY,
3391     EL_BD_FIREFLY_1,
3392     EL_BD_FIREFLY_2,
3393     EL_BD_FIREFLY_3,
3394     EL_BD_FIREFLY_4,
3395     EL_BD_BUTTERFLY,
3396     EL_BD_BUTTERFLY_1,
3397     EL_BD_BUTTERFLY_2,
3398     EL_BD_BUTTERFLY_3,
3399     EL_BD_BUTTERFLY_4,
3400     EL_BD_AMOEBA,
3401     EL_CHAR_QUESTION,
3402     EL_UNKNOWN,
3403
3404     -1
3405   };
3406
3407   static int ep_sp_element[] =
3408   {
3409     // should always be valid
3410     EL_EMPTY,
3411
3412     // standard classic Supaplex elements
3413     EL_SP_EMPTY,
3414     EL_SP_ZONK,
3415     EL_SP_BASE,
3416     EL_SP_MURPHY,
3417     EL_SP_INFOTRON,
3418     EL_SP_CHIP_SINGLE,
3419     EL_SP_HARDWARE_GRAY,
3420     EL_SP_EXIT_CLOSED,
3421     EL_SP_EXIT_OPEN,
3422     EL_SP_DISK_ORANGE,
3423     EL_SP_PORT_RIGHT,
3424     EL_SP_PORT_DOWN,
3425     EL_SP_PORT_LEFT,
3426     EL_SP_PORT_UP,
3427     EL_SP_GRAVITY_PORT_RIGHT,
3428     EL_SP_GRAVITY_PORT_DOWN,
3429     EL_SP_GRAVITY_PORT_LEFT,
3430     EL_SP_GRAVITY_PORT_UP,
3431     EL_SP_SNIKSNAK,
3432     EL_SP_DISK_YELLOW,
3433     EL_SP_TERMINAL,
3434     EL_SP_DISK_RED,
3435     EL_SP_PORT_VERTICAL,
3436     EL_SP_PORT_HORIZONTAL,
3437     EL_SP_PORT_ANY,
3438     EL_SP_ELECTRON,
3439     EL_SP_BUGGY_BASE,
3440     EL_SP_CHIP_LEFT,
3441     EL_SP_CHIP_RIGHT,
3442     EL_SP_HARDWARE_BASE_1,
3443     EL_SP_HARDWARE_GREEN,
3444     EL_SP_HARDWARE_BLUE,
3445     EL_SP_HARDWARE_RED,
3446     EL_SP_HARDWARE_YELLOW,
3447     EL_SP_HARDWARE_BASE_2,
3448     EL_SP_HARDWARE_BASE_3,
3449     EL_SP_HARDWARE_BASE_4,
3450     EL_SP_HARDWARE_BASE_5,
3451     EL_SP_HARDWARE_BASE_6,
3452     EL_SP_CHIP_TOP,
3453     EL_SP_CHIP_BOTTOM,
3454
3455     // additional elements that appeared in newer Supaplex levels
3456     EL_INVISIBLE_WALL,
3457
3458     // additional gravity port elements (not switching, but setting gravity)
3459     EL_SP_GRAVITY_ON_PORT_LEFT,
3460     EL_SP_GRAVITY_ON_PORT_RIGHT,
3461     EL_SP_GRAVITY_ON_PORT_UP,
3462     EL_SP_GRAVITY_ON_PORT_DOWN,
3463     EL_SP_GRAVITY_OFF_PORT_LEFT,
3464     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3465     EL_SP_GRAVITY_OFF_PORT_UP,
3466     EL_SP_GRAVITY_OFF_PORT_DOWN,
3467
3468     // more than one Murphy in a level results in an inactive clone
3469     EL_SP_MURPHY_CLONE,
3470
3471     // runtime Supaplex elements
3472     EL_SP_DISK_RED_ACTIVE,
3473     EL_SP_TERMINAL_ACTIVE,
3474     EL_SP_BUGGY_BASE_ACTIVATING,
3475     EL_SP_BUGGY_BASE_ACTIVE,
3476     EL_SP_EXIT_OPENING,
3477     EL_SP_EXIT_CLOSING,
3478
3479     -1
3480   };
3481
3482   static int ep_sb_element[] =
3483   {
3484     EL_EMPTY,
3485     EL_STEELWALL,
3486     EL_SOKOBAN_OBJECT,
3487     EL_SOKOBAN_FIELD_EMPTY,
3488     EL_SOKOBAN_FIELD_FULL,
3489     EL_SOKOBAN_FIELD_PLAYER,
3490     EL_PLAYER_1,
3491     EL_PLAYER_2,
3492     EL_PLAYER_3,
3493     EL_PLAYER_4,
3494     EL_INVISIBLE_STEELWALL,
3495
3496     -1
3497   };
3498
3499   static int ep_gem[] =
3500   {
3501     EL_BD_DIAMOND,
3502     EL_EMERALD,
3503     EL_EMERALD_YELLOW,
3504     EL_EMERALD_RED,
3505     EL_EMERALD_PURPLE,
3506     EL_DIAMOND,
3507
3508     -1
3509   };
3510
3511   static int ep_food_dark_yamyam[] =
3512   {
3513     EL_SAND,
3514     EL_BUG,
3515     EL_SPACESHIP,
3516     EL_BD_BUTTERFLY,
3517     EL_BD_FIREFLY,
3518     EL_YAMYAM,
3519     EL_ROBOT,
3520     EL_PACMAN,
3521     EL_AMOEBA_DROP,
3522     EL_AMOEBA_DEAD,
3523     EL_AMOEBA_WET,
3524     EL_AMOEBA_DRY,
3525     EL_AMOEBA_FULL,
3526     EL_BD_AMOEBA,
3527     EL_EMERALD,
3528     EL_BD_DIAMOND,
3529     EL_EMERALD_YELLOW,
3530     EL_EMERALD_RED,
3531     EL_EMERALD_PURPLE,
3532     EL_DIAMOND,
3533     EL_PEARL,
3534     EL_CRYSTAL,
3535
3536     -1
3537   };
3538
3539   static int ep_food_penguin[] =
3540   {
3541     EL_EMERALD,
3542     EL_BD_DIAMOND,
3543     EL_EMERALD_YELLOW,
3544     EL_EMERALD_RED,
3545     EL_EMERALD_PURPLE,
3546     EL_DIAMOND,
3547     EL_PEARL,
3548     EL_CRYSTAL,
3549
3550     -1
3551   };
3552
3553   static int ep_food_pig[] =
3554   {
3555     EL_EMERALD,
3556     EL_BD_DIAMOND,
3557     EL_EMERALD_YELLOW,
3558     EL_EMERALD_RED,
3559     EL_EMERALD_PURPLE,
3560     EL_DIAMOND,
3561
3562     -1
3563   };
3564
3565   static int ep_historic_wall[] =
3566   {
3567     EL_STEELWALL,
3568     EL_GATE_1,
3569     EL_GATE_2,
3570     EL_GATE_3,
3571     EL_GATE_4,
3572     EL_GATE_1_GRAY,
3573     EL_GATE_2_GRAY,
3574     EL_GATE_3_GRAY,
3575     EL_GATE_4_GRAY,
3576     EL_GATE_1_GRAY_ACTIVE,
3577     EL_GATE_2_GRAY_ACTIVE,
3578     EL_GATE_3_GRAY_ACTIVE,
3579     EL_GATE_4_GRAY_ACTIVE,
3580     EL_EM_GATE_1,
3581     EL_EM_GATE_2,
3582     EL_EM_GATE_3,
3583     EL_EM_GATE_4,
3584     EL_EM_GATE_1_GRAY,
3585     EL_EM_GATE_2_GRAY,
3586     EL_EM_GATE_3_GRAY,
3587     EL_EM_GATE_4_GRAY,
3588     EL_EM_GATE_1_GRAY_ACTIVE,
3589     EL_EM_GATE_2_GRAY_ACTIVE,
3590     EL_EM_GATE_3_GRAY_ACTIVE,
3591     EL_EM_GATE_4_GRAY_ACTIVE,
3592     EL_EXIT_CLOSED,
3593     EL_EXIT_OPENING,
3594     EL_EXIT_OPEN,
3595     EL_WALL,
3596     EL_WALL_SLIPPERY,
3597     EL_EXPANDABLE_WALL,
3598     EL_EXPANDABLE_WALL_HORIZONTAL,
3599     EL_EXPANDABLE_WALL_VERTICAL,
3600     EL_EXPANDABLE_WALL_ANY,
3601     EL_EXPANDABLE_WALL_GROWING,
3602     EL_BD_EXPANDABLE_WALL,
3603     EL_BD_WALL,
3604     EL_SP_CHIP_SINGLE,
3605     EL_SP_CHIP_LEFT,
3606     EL_SP_CHIP_RIGHT,
3607     EL_SP_CHIP_TOP,
3608     EL_SP_CHIP_BOTTOM,
3609     EL_SP_HARDWARE_GRAY,
3610     EL_SP_HARDWARE_GREEN,
3611     EL_SP_HARDWARE_BLUE,
3612     EL_SP_HARDWARE_RED,
3613     EL_SP_HARDWARE_YELLOW,
3614     EL_SP_HARDWARE_BASE_1,
3615     EL_SP_HARDWARE_BASE_2,
3616     EL_SP_HARDWARE_BASE_3,
3617     EL_SP_HARDWARE_BASE_4,
3618     EL_SP_HARDWARE_BASE_5,
3619     EL_SP_HARDWARE_BASE_6,
3620     EL_SP_TERMINAL,
3621     EL_SP_TERMINAL_ACTIVE,
3622     EL_SP_EXIT_CLOSED,
3623     EL_SP_EXIT_OPEN,
3624     EL_INVISIBLE_STEELWALL,
3625     EL_INVISIBLE_STEELWALL_ACTIVE,
3626     EL_INVISIBLE_WALL,
3627     EL_INVISIBLE_WALL_ACTIVE,
3628     EL_STEELWALL_SLIPPERY,
3629     EL_EMC_STEELWALL_1,
3630     EL_EMC_STEELWALL_2,
3631     EL_EMC_STEELWALL_3,
3632     EL_EMC_STEELWALL_4,
3633     EL_EMC_WALL_1,
3634     EL_EMC_WALL_2,
3635     EL_EMC_WALL_3,
3636     EL_EMC_WALL_4,
3637     EL_EMC_WALL_5,
3638     EL_EMC_WALL_6,
3639     EL_EMC_WALL_7,
3640     EL_EMC_WALL_8,
3641
3642     -1
3643   };
3644
3645   static int ep_historic_solid[] =
3646   {
3647     EL_WALL,
3648     EL_EXPANDABLE_WALL,
3649     EL_EXPANDABLE_WALL_HORIZONTAL,
3650     EL_EXPANDABLE_WALL_VERTICAL,
3651     EL_EXPANDABLE_WALL_ANY,
3652     EL_BD_EXPANDABLE_WALL,
3653     EL_BD_WALL,
3654     EL_WALL_SLIPPERY,
3655     EL_EXIT_CLOSED,
3656     EL_EXIT_OPENING,
3657     EL_EXIT_OPEN,
3658     EL_AMOEBA_DEAD,
3659     EL_AMOEBA_WET,
3660     EL_AMOEBA_DRY,
3661     EL_AMOEBA_FULL,
3662     EL_BD_AMOEBA,
3663     EL_QUICKSAND_EMPTY,
3664     EL_QUICKSAND_FULL,
3665     EL_QUICKSAND_FILLING,
3666     EL_QUICKSAND_EMPTYING,
3667     EL_MAGIC_WALL,
3668     EL_MAGIC_WALL_ACTIVE,
3669     EL_MAGIC_WALL_EMPTYING,
3670     EL_MAGIC_WALL_FILLING,
3671     EL_MAGIC_WALL_FULL,
3672     EL_MAGIC_WALL_DEAD,
3673     EL_BD_MAGIC_WALL,
3674     EL_BD_MAGIC_WALL_ACTIVE,
3675     EL_BD_MAGIC_WALL_EMPTYING,
3676     EL_BD_MAGIC_WALL_FULL,
3677     EL_BD_MAGIC_WALL_FILLING,
3678     EL_BD_MAGIC_WALL_DEAD,
3679     EL_GAME_OF_LIFE,
3680     EL_BIOMAZE,
3681     EL_SP_CHIP_SINGLE,
3682     EL_SP_CHIP_LEFT,
3683     EL_SP_CHIP_RIGHT,
3684     EL_SP_CHIP_TOP,
3685     EL_SP_CHIP_BOTTOM,
3686     EL_SP_TERMINAL,
3687     EL_SP_TERMINAL_ACTIVE,
3688     EL_SP_EXIT_CLOSED,
3689     EL_SP_EXIT_OPEN,
3690     EL_INVISIBLE_WALL,
3691     EL_INVISIBLE_WALL_ACTIVE,
3692     EL_SWITCHGATE_SWITCH_UP,
3693     EL_SWITCHGATE_SWITCH_DOWN,
3694     EL_TIMEGATE_SWITCH,
3695     EL_TIMEGATE_SWITCH_ACTIVE,
3696     EL_EMC_WALL_1,
3697     EL_EMC_WALL_2,
3698     EL_EMC_WALL_3,
3699     EL_EMC_WALL_4,
3700     EL_EMC_WALL_5,
3701     EL_EMC_WALL_6,
3702     EL_EMC_WALL_7,
3703     EL_EMC_WALL_8,
3704     EL_WALL_PEARL,
3705     EL_WALL_CRYSTAL,
3706
3707     // the following elements are a direct copy of "indestructible" elements,
3708     // except "EL_ACID", which is "indestructible", but not "solid"!
3709 #if 0
3710     EL_ACID,
3711 #endif
3712     EL_STEELWALL,
3713     EL_ACID_POOL_TOPLEFT,
3714     EL_ACID_POOL_TOPRIGHT,
3715     EL_ACID_POOL_BOTTOMLEFT,
3716     EL_ACID_POOL_BOTTOM,
3717     EL_ACID_POOL_BOTTOMRIGHT,
3718     EL_SP_HARDWARE_GRAY,
3719     EL_SP_HARDWARE_GREEN,
3720     EL_SP_HARDWARE_BLUE,
3721     EL_SP_HARDWARE_RED,
3722     EL_SP_HARDWARE_YELLOW,
3723     EL_SP_HARDWARE_BASE_1,
3724     EL_SP_HARDWARE_BASE_2,
3725     EL_SP_HARDWARE_BASE_3,
3726     EL_SP_HARDWARE_BASE_4,
3727     EL_SP_HARDWARE_BASE_5,
3728     EL_SP_HARDWARE_BASE_6,
3729     EL_INVISIBLE_STEELWALL,
3730     EL_INVISIBLE_STEELWALL_ACTIVE,
3731     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3732     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3733     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3734     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3735     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3736     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3737     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3738     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3739     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3740     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3741     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3742     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3743     EL_LIGHT_SWITCH,
3744     EL_LIGHT_SWITCH_ACTIVE,
3745     EL_SIGN_EXCLAMATION,
3746     EL_SIGN_RADIOACTIVITY,
3747     EL_SIGN_STOP,
3748     EL_SIGN_WHEELCHAIR,
3749     EL_SIGN_PARKING,
3750     EL_SIGN_NO_ENTRY,
3751     EL_SIGN_UNUSED_1,
3752     EL_SIGN_GIVE_WAY,
3753     EL_SIGN_ENTRY_FORBIDDEN,
3754     EL_SIGN_EMERGENCY_EXIT,
3755     EL_SIGN_YIN_YANG,
3756     EL_SIGN_UNUSED_2,
3757     EL_SIGN_SPERMS,
3758     EL_SIGN_BULLET,
3759     EL_SIGN_HEART,
3760     EL_SIGN_CROSS,
3761     EL_SIGN_FRANKIE,
3762     EL_STEEL_EXIT_CLOSED,
3763     EL_STEEL_EXIT_OPEN,
3764     EL_STEEL_EXIT_OPENING,
3765     EL_STEEL_EXIT_CLOSING,
3766     EL_EM_STEEL_EXIT_CLOSED,
3767     EL_EM_STEEL_EXIT_OPEN,
3768     EL_EM_STEEL_EXIT_OPENING,
3769     EL_EM_STEEL_EXIT_CLOSING,
3770     EL_DC_STEELWALL_1_LEFT,
3771     EL_DC_STEELWALL_1_RIGHT,
3772     EL_DC_STEELWALL_1_TOP,
3773     EL_DC_STEELWALL_1_BOTTOM,
3774     EL_DC_STEELWALL_1_HORIZONTAL,
3775     EL_DC_STEELWALL_1_VERTICAL,
3776     EL_DC_STEELWALL_1_TOPLEFT,
3777     EL_DC_STEELWALL_1_TOPRIGHT,
3778     EL_DC_STEELWALL_1_BOTTOMLEFT,
3779     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3780     EL_DC_STEELWALL_1_TOPLEFT_2,
3781     EL_DC_STEELWALL_1_TOPRIGHT_2,
3782     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3783     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3784     EL_DC_STEELWALL_2_LEFT,
3785     EL_DC_STEELWALL_2_RIGHT,
3786     EL_DC_STEELWALL_2_TOP,
3787     EL_DC_STEELWALL_2_BOTTOM,
3788     EL_DC_STEELWALL_2_HORIZONTAL,
3789     EL_DC_STEELWALL_2_VERTICAL,
3790     EL_DC_STEELWALL_2_MIDDLE,
3791     EL_DC_STEELWALL_2_SINGLE,
3792     EL_STEELWALL_SLIPPERY,
3793     EL_EMC_STEELWALL_1,
3794     EL_EMC_STEELWALL_2,
3795     EL_EMC_STEELWALL_3,
3796     EL_EMC_STEELWALL_4,
3797     EL_CRYSTAL,
3798     EL_GATE_1,
3799     EL_GATE_2,
3800     EL_GATE_3,
3801     EL_GATE_4,
3802     EL_GATE_1_GRAY,
3803     EL_GATE_2_GRAY,
3804     EL_GATE_3_GRAY,
3805     EL_GATE_4_GRAY,
3806     EL_GATE_1_GRAY_ACTIVE,
3807     EL_GATE_2_GRAY_ACTIVE,
3808     EL_GATE_3_GRAY_ACTIVE,
3809     EL_GATE_4_GRAY_ACTIVE,
3810     EL_EM_GATE_1,
3811     EL_EM_GATE_2,
3812     EL_EM_GATE_3,
3813     EL_EM_GATE_4,
3814     EL_EM_GATE_1_GRAY,
3815     EL_EM_GATE_2_GRAY,
3816     EL_EM_GATE_3_GRAY,
3817     EL_EM_GATE_4_GRAY,
3818     EL_EM_GATE_1_GRAY_ACTIVE,
3819     EL_EM_GATE_2_GRAY_ACTIVE,
3820     EL_EM_GATE_3_GRAY_ACTIVE,
3821     EL_EM_GATE_4_GRAY_ACTIVE,
3822     EL_EMC_GATE_5,
3823     EL_EMC_GATE_6,
3824     EL_EMC_GATE_7,
3825     EL_EMC_GATE_8,
3826     EL_EMC_GATE_5_GRAY,
3827     EL_EMC_GATE_6_GRAY,
3828     EL_EMC_GATE_7_GRAY,
3829     EL_EMC_GATE_8_GRAY,
3830     EL_EMC_GATE_5_GRAY_ACTIVE,
3831     EL_EMC_GATE_6_GRAY_ACTIVE,
3832     EL_EMC_GATE_7_GRAY_ACTIVE,
3833     EL_EMC_GATE_8_GRAY_ACTIVE,
3834     EL_DC_GATE_WHITE,
3835     EL_DC_GATE_WHITE_GRAY,
3836     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3837     EL_DC_GATE_FAKE_GRAY,
3838     EL_SWITCHGATE_OPEN,
3839     EL_SWITCHGATE_OPENING,
3840     EL_SWITCHGATE_CLOSED,
3841     EL_SWITCHGATE_CLOSING,
3842     EL_DC_SWITCHGATE_SWITCH_UP,
3843     EL_DC_SWITCHGATE_SWITCH_DOWN,
3844     EL_TIMEGATE_OPEN,
3845     EL_TIMEGATE_OPENING,
3846     EL_TIMEGATE_CLOSED,
3847     EL_TIMEGATE_CLOSING,
3848     EL_DC_TIMEGATE_SWITCH,
3849     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3850     EL_TUBE_ANY,
3851     EL_TUBE_VERTICAL,
3852     EL_TUBE_HORIZONTAL,
3853     EL_TUBE_VERTICAL_LEFT,
3854     EL_TUBE_VERTICAL_RIGHT,
3855     EL_TUBE_HORIZONTAL_UP,
3856     EL_TUBE_HORIZONTAL_DOWN,
3857     EL_TUBE_LEFT_UP,
3858     EL_TUBE_LEFT_DOWN,
3859     EL_TUBE_RIGHT_UP,
3860     EL_TUBE_RIGHT_DOWN,
3861     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
3862     EL_EXPANDABLE_STEELWALL_VERTICAL,
3863     EL_EXPANDABLE_STEELWALL_ANY,
3864
3865     -1
3866   };
3867
3868   static int ep_classic_enemy[] =
3869   {
3870     EL_BUG,
3871     EL_SPACESHIP,
3872     EL_BD_BUTTERFLY,
3873     EL_BD_FIREFLY,
3874
3875     EL_YAMYAM,
3876     EL_DARK_YAMYAM,
3877     EL_ROBOT,
3878     EL_PACMAN,
3879     EL_SP_SNIKSNAK,
3880     EL_SP_ELECTRON,
3881
3882     -1
3883   };
3884
3885   static int ep_belt[] =
3886   {
3887     EL_CONVEYOR_BELT_1_LEFT,
3888     EL_CONVEYOR_BELT_1_MIDDLE,
3889     EL_CONVEYOR_BELT_1_RIGHT,
3890     EL_CONVEYOR_BELT_2_LEFT,
3891     EL_CONVEYOR_BELT_2_MIDDLE,
3892     EL_CONVEYOR_BELT_2_RIGHT,
3893     EL_CONVEYOR_BELT_3_LEFT,
3894     EL_CONVEYOR_BELT_3_MIDDLE,
3895     EL_CONVEYOR_BELT_3_RIGHT,
3896     EL_CONVEYOR_BELT_4_LEFT,
3897     EL_CONVEYOR_BELT_4_MIDDLE,
3898     EL_CONVEYOR_BELT_4_RIGHT,
3899
3900     -1
3901   };
3902
3903   static int ep_belt_active[] =
3904   {
3905     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3906     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3907     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3908     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3909     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3910     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3911     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3912     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3913     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3914     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3915     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3916     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3917
3918     -1
3919   };
3920
3921   static int ep_belt_switch[] =
3922   {
3923     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3924     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3925     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3926     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3927     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3928     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3929     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3930     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3931     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3932     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3933     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3934     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3935
3936     -1
3937   };
3938
3939   static int ep_tube[] =
3940   {
3941     EL_TUBE_LEFT_UP,
3942     EL_TUBE_LEFT_DOWN,
3943     EL_TUBE_RIGHT_UP,
3944     EL_TUBE_RIGHT_DOWN,
3945     EL_TUBE_HORIZONTAL,
3946     EL_TUBE_HORIZONTAL_UP,
3947     EL_TUBE_HORIZONTAL_DOWN,
3948     EL_TUBE_VERTICAL,
3949     EL_TUBE_VERTICAL_LEFT,
3950     EL_TUBE_VERTICAL_RIGHT,
3951     EL_TUBE_ANY,
3952
3953     -1
3954   };
3955
3956   static int ep_acid_pool[] =
3957   {
3958     EL_ACID_POOL_TOPLEFT,
3959     EL_ACID_POOL_TOPRIGHT,
3960     EL_ACID_POOL_BOTTOMLEFT,
3961     EL_ACID_POOL_BOTTOM,
3962     EL_ACID_POOL_BOTTOMRIGHT,
3963
3964     -1
3965   };
3966
3967   static int ep_keygate[] =
3968   {
3969     EL_GATE_1,
3970     EL_GATE_2,
3971     EL_GATE_3,
3972     EL_GATE_4,
3973     EL_GATE_1_GRAY,
3974     EL_GATE_2_GRAY,
3975     EL_GATE_3_GRAY,
3976     EL_GATE_4_GRAY,
3977     EL_GATE_1_GRAY_ACTIVE,
3978     EL_GATE_2_GRAY_ACTIVE,
3979     EL_GATE_3_GRAY_ACTIVE,
3980     EL_GATE_4_GRAY_ACTIVE,
3981     EL_EM_GATE_1,
3982     EL_EM_GATE_2,
3983     EL_EM_GATE_3,
3984     EL_EM_GATE_4,
3985     EL_EM_GATE_1_GRAY,
3986     EL_EM_GATE_2_GRAY,
3987     EL_EM_GATE_3_GRAY,
3988     EL_EM_GATE_4_GRAY,
3989     EL_EM_GATE_1_GRAY_ACTIVE,
3990     EL_EM_GATE_2_GRAY_ACTIVE,
3991     EL_EM_GATE_3_GRAY_ACTIVE,
3992     EL_EM_GATE_4_GRAY_ACTIVE,
3993     EL_EMC_GATE_5,
3994     EL_EMC_GATE_6,
3995     EL_EMC_GATE_7,
3996     EL_EMC_GATE_8,
3997     EL_EMC_GATE_5_GRAY,
3998     EL_EMC_GATE_6_GRAY,
3999     EL_EMC_GATE_7_GRAY,
4000     EL_EMC_GATE_8_GRAY,
4001     EL_EMC_GATE_5_GRAY_ACTIVE,
4002     EL_EMC_GATE_6_GRAY_ACTIVE,
4003     EL_EMC_GATE_7_GRAY_ACTIVE,
4004     EL_EMC_GATE_8_GRAY_ACTIVE,
4005     EL_DC_GATE_WHITE,
4006     EL_DC_GATE_WHITE_GRAY,
4007     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4008
4009     -1
4010   };
4011
4012   static int ep_amoeboid[] =
4013   {
4014     EL_AMOEBA_DEAD,
4015     EL_AMOEBA_WET,
4016     EL_AMOEBA_DRY,
4017     EL_AMOEBA_FULL,
4018     EL_BD_AMOEBA,
4019     EL_EMC_DRIPPER,
4020
4021     -1
4022   };
4023
4024   static int ep_amoebalive[] =
4025   {
4026     EL_AMOEBA_WET,
4027     EL_AMOEBA_DRY,
4028     EL_AMOEBA_FULL,
4029     EL_BD_AMOEBA,
4030     EL_EMC_DRIPPER,
4031
4032     -1
4033   };
4034
4035   static int ep_has_editor_content[] =
4036   {
4037     EL_PLAYER_1,
4038     EL_PLAYER_2,
4039     EL_PLAYER_3,
4040     EL_PLAYER_4,
4041     EL_SOKOBAN_FIELD_PLAYER,
4042     EL_SP_MURPHY,
4043     EL_YAMYAM,
4044     EL_YAMYAM_LEFT,
4045     EL_YAMYAM_RIGHT,
4046     EL_YAMYAM_UP,
4047     EL_YAMYAM_DOWN,
4048     EL_AMOEBA_WET,
4049     EL_AMOEBA_DRY,
4050     EL_AMOEBA_FULL,
4051     EL_BD_AMOEBA,
4052     EL_EMC_MAGIC_BALL,
4053     EL_EMC_ANDROID,
4054
4055     -1
4056   };
4057
4058   static int ep_can_turn_each_move[] =
4059   {
4060     // !!! do something with this one !!!
4061     -1
4062   };
4063
4064   static int ep_can_grow[] =
4065   {
4066     EL_BD_AMOEBA,
4067     EL_AMOEBA_DROP,
4068     EL_AMOEBA_WET,
4069     EL_AMOEBA_DRY,
4070     EL_AMOEBA_FULL,
4071     EL_GAME_OF_LIFE,
4072     EL_BIOMAZE,
4073     EL_EMC_DRIPPER,
4074
4075     -1
4076   };
4077
4078   static int ep_active_bomb[] =
4079   {
4080     EL_DYNAMITE_ACTIVE,
4081     EL_EM_DYNAMITE_ACTIVE,
4082     EL_DYNABOMB_PLAYER_1_ACTIVE,
4083     EL_DYNABOMB_PLAYER_2_ACTIVE,
4084     EL_DYNABOMB_PLAYER_3_ACTIVE,
4085     EL_DYNABOMB_PLAYER_4_ACTIVE,
4086     EL_SP_DISK_RED_ACTIVE,
4087
4088     -1
4089   };
4090
4091   static int ep_inactive[] =
4092   {
4093     EL_EMPTY,
4094     EL_SAND,
4095     EL_WALL,
4096     EL_BD_WALL,
4097     EL_WALL_SLIPPERY,
4098     EL_STEELWALL,
4099     EL_AMOEBA_DEAD,
4100     EL_QUICKSAND_EMPTY,
4101     EL_QUICKSAND_FAST_EMPTY,
4102     EL_STONEBLOCK,
4103     EL_ROBOT_WHEEL,
4104     EL_KEY_1,
4105     EL_KEY_2,
4106     EL_KEY_3,
4107     EL_KEY_4,
4108     EL_EM_KEY_1,
4109     EL_EM_KEY_2,
4110     EL_EM_KEY_3,
4111     EL_EM_KEY_4,
4112     EL_EMC_KEY_5,
4113     EL_EMC_KEY_6,
4114     EL_EMC_KEY_7,
4115     EL_EMC_KEY_8,
4116     EL_GATE_1,
4117     EL_GATE_2,
4118     EL_GATE_3,
4119     EL_GATE_4,
4120     EL_GATE_1_GRAY,
4121     EL_GATE_2_GRAY,
4122     EL_GATE_3_GRAY,
4123     EL_GATE_4_GRAY,
4124     EL_GATE_1_GRAY_ACTIVE,
4125     EL_GATE_2_GRAY_ACTIVE,
4126     EL_GATE_3_GRAY_ACTIVE,
4127     EL_GATE_4_GRAY_ACTIVE,
4128     EL_EM_GATE_1,
4129     EL_EM_GATE_2,
4130     EL_EM_GATE_3,
4131     EL_EM_GATE_4,
4132     EL_EM_GATE_1_GRAY,
4133     EL_EM_GATE_2_GRAY,
4134     EL_EM_GATE_3_GRAY,
4135     EL_EM_GATE_4_GRAY,
4136     EL_EM_GATE_1_GRAY_ACTIVE,
4137     EL_EM_GATE_2_GRAY_ACTIVE,
4138     EL_EM_GATE_3_GRAY_ACTIVE,
4139     EL_EM_GATE_4_GRAY_ACTIVE,
4140     EL_EMC_GATE_5,
4141     EL_EMC_GATE_6,
4142     EL_EMC_GATE_7,
4143     EL_EMC_GATE_8,
4144     EL_EMC_GATE_5_GRAY,
4145     EL_EMC_GATE_6_GRAY,
4146     EL_EMC_GATE_7_GRAY,
4147     EL_EMC_GATE_8_GRAY,
4148     EL_EMC_GATE_5_GRAY_ACTIVE,
4149     EL_EMC_GATE_6_GRAY_ACTIVE,
4150     EL_EMC_GATE_7_GRAY_ACTIVE,
4151     EL_EMC_GATE_8_GRAY_ACTIVE,
4152     EL_DC_GATE_WHITE,
4153     EL_DC_GATE_WHITE_GRAY,
4154     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4155     EL_DC_GATE_FAKE_GRAY,
4156     EL_DYNAMITE,
4157     EL_EM_DYNAMITE,
4158     EL_INVISIBLE_STEELWALL,
4159     EL_INVISIBLE_WALL,
4160     EL_INVISIBLE_SAND,
4161     EL_LAMP,
4162     EL_LAMP_ACTIVE,
4163     EL_WALL_EMERALD,
4164     EL_WALL_DIAMOND,
4165     EL_WALL_BD_DIAMOND,
4166     EL_WALL_EMERALD_YELLOW,
4167     EL_DYNABOMB_INCREASE_NUMBER,
4168     EL_DYNABOMB_INCREASE_SIZE,
4169     EL_DYNABOMB_INCREASE_POWER,
4170 #if 0
4171     EL_SOKOBAN_OBJECT,
4172 #endif
4173     EL_SOKOBAN_FIELD_EMPTY,
4174     EL_SOKOBAN_FIELD_FULL,
4175     EL_WALL_EMERALD_RED,
4176     EL_WALL_EMERALD_PURPLE,
4177     EL_ACID_POOL_TOPLEFT,
4178     EL_ACID_POOL_TOPRIGHT,
4179     EL_ACID_POOL_BOTTOMLEFT,
4180     EL_ACID_POOL_BOTTOM,
4181     EL_ACID_POOL_BOTTOMRIGHT,
4182     EL_MAGIC_WALL,
4183     EL_MAGIC_WALL_DEAD,
4184     EL_BD_MAGIC_WALL,
4185     EL_BD_MAGIC_WALL_DEAD,
4186     EL_DC_MAGIC_WALL,
4187     EL_DC_MAGIC_WALL_DEAD,
4188     EL_AMOEBA_TO_DIAMOND,
4189     EL_BLOCKED,
4190     EL_SP_EMPTY,
4191     EL_SP_BASE,
4192     EL_SP_PORT_RIGHT,
4193     EL_SP_PORT_DOWN,
4194     EL_SP_PORT_LEFT,
4195     EL_SP_PORT_UP,
4196     EL_SP_GRAVITY_PORT_RIGHT,
4197     EL_SP_GRAVITY_PORT_DOWN,
4198     EL_SP_GRAVITY_PORT_LEFT,
4199     EL_SP_GRAVITY_PORT_UP,
4200     EL_SP_PORT_HORIZONTAL,
4201     EL_SP_PORT_VERTICAL,
4202     EL_SP_PORT_ANY,
4203     EL_SP_DISK_RED,
4204 #if 0
4205     EL_SP_DISK_YELLOW,
4206 #endif
4207     EL_SP_CHIP_SINGLE,
4208     EL_SP_CHIP_LEFT,
4209     EL_SP_CHIP_RIGHT,
4210     EL_SP_CHIP_TOP,
4211     EL_SP_CHIP_BOTTOM,
4212     EL_SP_HARDWARE_GRAY,
4213     EL_SP_HARDWARE_GREEN,
4214     EL_SP_HARDWARE_BLUE,
4215     EL_SP_HARDWARE_RED,
4216     EL_SP_HARDWARE_YELLOW,
4217     EL_SP_HARDWARE_BASE_1,
4218     EL_SP_HARDWARE_BASE_2,
4219     EL_SP_HARDWARE_BASE_3,
4220     EL_SP_HARDWARE_BASE_4,
4221     EL_SP_HARDWARE_BASE_5,
4222     EL_SP_HARDWARE_BASE_6,
4223     EL_SP_GRAVITY_ON_PORT_LEFT,
4224     EL_SP_GRAVITY_ON_PORT_RIGHT,
4225     EL_SP_GRAVITY_ON_PORT_UP,
4226     EL_SP_GRAVITY_ON_PORT_DOWN,
4227     EL_SP_GRAVITY_OFF_PORT_LEFT,
4228     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4229     EL_SP_GRAVITY_OFF_PORT_UP,
4230     EL_SP_GRAVITY_OFF_PORT_DOWN,
4231     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4232     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4233     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4234     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4235     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4236     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4237     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4238     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4239     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4240     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4241     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4242     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4243     EL_SIGN_EXCLAMATION,
4244     EL_SIGN_RADIOACTIVITY,
4245     EL_SIGN_STOP,
4246     EL_SIGN_WHEELCHAIR,
4247     EL_SIGN_PARKING,
4248     EL_SIGN_NO_ENTRY,
4249     EL_SIGN_UNUSED_1,
4250     EL_SIGN_GIVE_WAY,
4251     EL_SIGN_ENTRY_FORBIDDEN,
4252     EL_SIGN_EMERGENCY_EXIT,
4253     EL_SIGN_YIN_YANG,
4254     EL_SIGN_UNUSED_2,
4255     EL_SIGN_SPERMS,
4256     EL_SIGN_BULLET,
4257     EL_SIGN_HEART,
4258     EL_SIGN_CROSS,
4259     EL_SIGN_FRANKIE,
4260     EL_DC_STEELWALL_1_LEFT,
4261     EL_DC_STEELWALL_1_RIGHT,
4262     EL_DC_STEELWALL_1_TOP,
4263     EL_DC_STEELWALL_1_BOTTOM,
4264     EL_DC_STEELWALL_1_HORIZONTAL,
4265     EL_DC_STEELWALL_1_VERTICAL,
4266     EL_DC_STEELWALL_1_TOPLEFT,
4267     EL_DC_STEELWALL_1_TOPRIGHT,
4268     EL_DC_STEELWALL_1_BOTTOMLEFT,
4269     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4270     EL_DC_STEELWALL_1_TOPLEFT_2,
4271     EL_DC_STEELWALL_1_TOPRIGHT_2,
4272     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4273     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4274     EL_DC_STEELWALL_2_LEFT,
4275     EL_DC_STEELWALL_2_RIGHT,
4276     EL_DC_STEELWALL_2_TOP,
4277     EL_DC_STEELWALL_2_BOTTOM,
4278     EL_DC_STEELWALL_2_HORIZONTAL,
4279     EL_DC_STEELWALL_2_VERTICAL,
4280     EL_DC_STEELWALL_2_MIDDLE,
4281     EL_DC_STEELWALL_2_SINGLE,
4282     EL_STEELWALL_SLIPPERY,
4283     EL_EMC_STEELWALL_1,
4284     EL_EMC_STEELWALL_2,
4285     EL_EMC_STEELWALL_3,
4286     EL_EMC_STEELWALL_4,
4287     EL_EMC_WALL_SLIPPERY_1,
4288     EL_EMC_WALL_SLIPPERY_2,
4289     EL_EMC_WALL_SLIPPERY_3,
4290     EL_EMC_WALL_SLIPPERY_4,
4291     EL_EMC_WALL_1,
4292     EL_EMC_WALL_2,
4293     EL_EMC_WALL_3,
4294     EL_EMC_WALL_4,
4295     EL_EMC_WALL_5,
4296     EL_EMC_WALL_6,
4297     EL_EMC_WALL_7,
4298     EL_EMC_WALL_8,
4299     EL_EMC_WALL_9,
4300     EL_EMC_WALL_10,
4301     EL_EMC_WALL_11,
4302     EL_EMC_WALL_12,
4303     EL_EMC_WALL_13,
4304     EL_EMC_WALL_14,
4305     EL_EMC_WALL_15,
4306     EL_EMC_WALL_16,
4307
4308     -1
4309   };
4310
4311   static int ep_em_slippery_wall[] =
4312   {
4313     -1
4314   };
4315
4316   static int ep_gfx_crumbled[] =
4317   {
4318     EL_SAND,
4319     EL_LANDMINE,
4320     EL_DC_LANDMINE,
4321     EL_TRAP,
4322     EL_TRAP_ACTIVE,
4323
4324     -1
4325   };
4326
4327   static int ep_editor_cascade_active[] =
4328   {
4329     EL_INTERNAL_CASCADE_BD_ACTIVE,
4330     EL_INTERNAL_CASCADE_EM_ACTIVE,
4331     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4332     EL_INTERNAL_CASCADE_RND_ACTIVE,
4333     EL_INTERNAL_CASCADE_SB_ACTIVE,
4334     EL_INTERNAL_CASCADE_SP_ACTIVE,
4335     EL_INTERNAL_CASCADE_DC_ACTIVE,
4336     EL_INTERNAL_CASCADE_DX_ACTIVE,
4337     EL_INTERNAL_CASCADE_MM_ACTIVE,
4338     EL_INTERNAL_CASCADE_DF_ACTIVE,
4339     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4340     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4341     EL_INTERNAL_CASCADE_CE_ACTIVE,
4342     EL_INTERNAL_CASCADE_GE_ACTIVE,
4343     EL_INTERNAL_CASCADE_REF_ACTIVE,
4344     EL_INTERNAL_CASCADE_USER_ACTIVE,
4345     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4346
4347     -1
4348   };
4349
4350   static int ep_editor_cascade_inactive[] =
4351   {
4352     EL_INTERNAL_CASCADE_BD,
4353     EL_INTERNAL_CASCADE_EM,
4354     EL_INTERNAL_CASCADE_EMC,
4355     EL_INTERNAL_CASCADE_RND,
4356     EL_INTERNAL_CASCADE_SB,
4357     EL_INTERNAL_CASCADE_SP,
4358     EL_INTERNAL_CASCADE_DC,
4359     EL_INTERNAL_CASCADE_DX,
4360     EL_INTERNAL_CASCADE_MM,
4361     EL_INTERNAL_CASCADE_DF,
4362     EL_INTERNAL_CASCADE_CHARS,
4363     EL_INTERNAL_CASCADE_STEEL_CHARS,
4364     EL_INTERNAL_CASCADE_CE,
4365     EL_INTERNAL_CASCADE_GE,
4366     EL_INTERNAL_CASCADE_REF,
4367     EL_INTERNAL_CASCADE_USER,
4368     EL_INTERNAL_CASCADE_DYNAMIC,
4369
4370     -1
4371   };
4372
4373   static int ep_obsolete[] =
4374   {
4375     EL_PLAYER_OBSOLETE,
4376     EL_KEY_OBSOLETE,
4377     EL_EM_KEY_1_FILE_OBSOLETE,
4378     EL_EM_KEY_2_FILE_OBSOLETE,
4379     EL_EM_KEY_3_FILE_OBSOLETE,
4380     EL_EM_KEY_4_FILE_OBSOLETE,
4381     EL_ENVELOPE_OBSOLETE,
4382
4383     -1
4384   };
4385
4386   static struct
4387   {
4388     int *elements;
4389     int property;
4390   } element_properties[] =
4391   {
4392     { ep_diggable,                      EP_DIGGABLE                     },
4393     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4394     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4395     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4396     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4397     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4398     { ep_slippery,                      EP_SLIPPERY                     },
4399     { ep_can_change,                    EP_CAN_CHANGE                   },
4400     { ep_can_move,                      EP_CAN_MOVE                     },
4401     { ep_can_fall,                      EP_CAN_FALL                     },
4402     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4403     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4404     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4405     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4406     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4407     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4408     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4409     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4410     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4411     { ep_passable_over,                 EP_PASSABLE_OVER                },
4412     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4413     { ep_passable_under,                EP_PASSABLE_UNDER               },
4414     { ep_droppable,                     EP_DROPPABLE                    },
4415     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4416     { ep_pushable,                      EP_PUSHABLE                     },
4417     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4418     { ep_protected,                     EP_PROTECTED                    },
4419     { ep_throwable,                     EP_THROWABLE                    },
4420     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4421     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4422
4423     { ep_player,                        EP_PLAYER                       },
4424     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4425     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4426     { ep_switchable,                    EP_SWITCHABLE                   },
4427     { ep_bd_element,                    EP_BD_ELEMENT                   },
4428     { ep_sp_element,                    EP_SP_ELEMENT                   },
4429     { ep_sb_element,                    EP_SB_ELEMENT                   },
4430     { ep_gem,                           EP_GEM                          },
4431     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4432     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4433     { ep_food_pig,                      EP_FOOD_PIG                     },
4434     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4435     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4436     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4437     { ep_belt,                          EP_BELT                         },
4438     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4439     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4440     { ep_tube,                          EP_TUBE                         },
4441     { ep_acid_pool,                     EP_ACID_POOL                    },
4442     { ep_keygate,                       EP_KEYGATE                      },
4443     { ep_amoeboid,                      EP_AMOEBOID                     },
4444     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4445     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4446     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4447     { ep_can_grow,                      EP_CAN_GROW                     },
4448     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4449     { ep_inactive,                      EP_INACTIVE                     },
4450
4451     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4452
4453     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4454
4455     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4456     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4457
4458     { ep_obsolete,                      EP_OBSOLETE                     },
4459
4460     { NULL,                             -1                              }
4461   };
4462
4463   int i, j, k;
4464
4465   // always start with reliable default values (element has no properties)
4466   // (but never initialize clipboard elements after the very first time)
4467   // (to be able to use clipboard elements between several levels)
4468   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4469     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4470       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4471         SET_PROPERTY(i, j, FALSE);
4472
4473   // set all base element properties from above array definitions
4474   for (i = 0; element_properties[i].elements != NULL; i++)
4475     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4476       SET_PROPERTY((element_properties[i].elements)[j],
4477                    element_properties[i].property, TRUE);
4478
4479   // copy properties to some elements that are only stored in level file
4480   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4481     for (j = 0; copy_properties[j][0] != -1; j++)
4482       if (HAS_PROPERTY(copy_properties[j][0], i))
4483         for (k = 1; k <= 4; k++)
4484           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4485
4486   // set static element properties that are not listed in array definitions
4487   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4488     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4489
4490   clipboard_elements_initialized = TRUE;
4491 }
4492
4493 void InitElementPropertiesEngine(int engine_version)
4494 {
4495   static int no_wall_properties[] =
4496   {
4497     EP_DIGGABLE,
4498     EP_COLLECTIBLE_ONLY,
4499     EP_DONT_RUN_INTO,
4500     EP_DONT_COLLIDE_WITH,
4501     EP_CAN_MOVE,
4502     EP_CAN_FALL,
4503     EP_CAN_SMASH_PLAYER,
4504     EP_CAN_SMASH_ENEMIES,
4505     EP_CAN_SMASH_EVERYTHING,
4506     EP_PUSHABLE,
4507
4508     EP_PLAYER,
4509     EP_GEM,
4510     EP_FOOD_DARK_YAMYAM,
4511     EP_FOOD_PENGUIN,
4512     EP_BELT,
4513     EP_BELT_ACTIVE,
4514     EP_TUBE,
4515     EP_AMOEBOID,
4516     EP_AMOEBALIVE,
4517     EP_ACTIVE_BOMB,
4518
4519     EP_ACCESSIBLE,
4520
4521     -1
4522   };
4523
4524   int i, j;
4525
4526   /* important: after initialization in InitElementPropertiesStatic(), the
4527      elements are not again initialized to a default value; therefore all
4528      changes have to make sure that they leave the element with a defined
4529      property (which means that conditional property changes must be set to
4530      a reliable default value before) */
4531
4532   // resolve group elements
4533   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4534     ResolveGroupElement(EL_GROUP_START + i);
4535
4536   // set all special, combined or engine dependent element properties
4537   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4538   {
4539     // do not change (already initialized) clipboard elements here
4540     if (IS_CLIPBOARD_ELEMENT(i))
4541       continue;
4542
4543     // ---------- INACTIVE ----------------------------------------------------
4544     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4545                                    i <= EL_CHAR_END) ||
4546                                   (i >= EL_STEEL_CHAR_START &&
4547                                    i <= EL_STEEL_CHAR_END)));
4548
4549     // ---------- WALKABLE, PASSABLE, ACCESSIBLE ------------------------------
4550     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4551                                   IS_WALKABLE_INSIDE(i) ||
4552                                   IS_WALKABLE_UNDER(i)));
4553
4554     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4555                                   IS_PASSABLE_INSIDE(i) ||
4556                                   IS_PASSABLE_UNDER(i)));
4557
4558     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4559                                          IS_PASSABLE_OVER(i)));
4560
4561     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4562                                            IS_PASSABLE_INSIDE(i)));
4563
4564     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4565                                           IS_PASSABLE_UNDER(i)));
4566
4567     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4568                                     IS_PASSABLE(i)));
4569
4570     // ---------- COLLECTIBLE -------------------------------------------------
4571     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4572                                      IS_DROPPABLE(i) ||
4573                                      IS_THROWABLE(i)));
4574
4575     // ---------- SNAPPABLE ---------------------------------------------------
4576     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4577                                    IS_COLLECTIBLE(i) ||
4578                                    IS_SWITCHABLE(i) ||
4579                                    i == EL_BD_ROCK));
4580
4581     // ---------- WALL --------------------------------------------------------
4582     SET_PROPERTY(i, EP_WALL, TRUE);     // default: element is wall
4583
4584     for (j = 0; no_wall_properties[j] != -1; j++)
4585       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4586           i >= EL_FIRST_RUNTIME_UNREAL)
4587         SET_PROPERTY(i, EP_WALL, FALSE);
4588
4589     if (IS_HISTORIC_WALL(i))
4590       SET_PROPERTY(i, EP_WALL, TRUE);
4591
4592     // ---------- SOLID_FOR_PUSHING -------------------------------------------
4593     if (engine_version < VERSION_IDENT(2,2,0,0))
4594       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4595     else
4596       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4597                                              !IS_DIGGABLE(i) &&
4598                                              !IS_COLLECTIBLE(i)));
4599
4600     // ---------- DRAGONFIRE_PROOF --------------------------------------------
4601     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4602       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4603     else
4604       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_INDESTRUCTIBLE(i) &&
4605                                             i != EL_ACID));
4606
4607     // ---------- EXPLOSION_PROOF ---------------------------------------------
4608     if (i == EL_FLAMES)
4609       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4610     else if (engine_version < VERSION_IDENT(2,2,0,0))
4611       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4612     else
4613       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4614                                            (!IS_WALKABLE(i) ||
4615                                             IS_PROTECTED(i))));
4616
4617     if (IS_CUSTOM_ELEMENT(i))
4618     {
4619       // these are additional properties which are initially false when set
4620
4621       // ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO -------------------------
4622       if (DONT_TOUCH(i))
4623         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4624       if (DONT_COLLIDE_WITH(i))
4625         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4626
4627       // ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ----------------------
4628       if (CAN_SMASH_EVERYTHING(i))
4629         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4630       if (CAN_SMASH_ENEMIES(i))
4631         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4632     }
4633
4634     // ---------- CAN_SMASH ---------------------------------------------------
4635     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4636                                    CAN_SMASH_ENEMIES(i) ||
4637                                    CAN_SMASH_EVERYTHING(i)));
4638
4639     // ---------- CAN_EXPLODE_BY_FIRE -----------------------------------------
4640     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4641                                              EXPLODES_BY_FIRE(i)));
4642
4643     // ---------- CAN_EXPLODE_SMASHED -----------------------------------------
4644     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4645                                              EXPLODES_SMASHED(i)));
4646
4647     // ---------- CAN_EXPLODE_IMPACT ------------------------------------------
4648     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4649                                             EXPLODES_IMPACT(i)));
4650
4651     // ---------- CAN_EXPLODE_BY_DRAGONFIRE -----------------------------------
4652     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4653
4654     // ---------- CAN_EXPLODE_BY_EXPLOSION ------------------------------------
4655     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4656                                                   i == EL_BLACK_ORB));
4657
4658     // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
4659     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4660                                               CAN_MOVE(i) ||
4661                                               IS_CUSTOM_ELEMENT(i)));
4662
4663     // ---------- MAYBE_DONT_COLLIDE_WITH -------------------------------------
4664     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4665                                                  i == EL_SP_ELECTRON));
4666
4667     // ---------- CAN_MOVE_INTO_ACID ------------------------------------------
4668     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4669       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4670                    getMoveIntoAcidProperty(&level, i));
4671
4672     // ---------- DONT_COLLIDE_WITH -------------------------------------------
4673     if (MAYBE_DONT_COLLIDE_WITH(i))
4674       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4675                    getDontCollideWithProperty(&level, i));
4676
4677     // ---------- SP_PORT -----------------------------------------------------
4678     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4679                                  IS_PASSABLE_INSIDE(i)));
4680
4681     // ---------- CAN_BE_CLONED_BY_ANDROID ------------------------------------
4682     for (j = 0; j < level.num_android_clone_elements; j++)
4683       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4684                    (i != EL_EMPTY &&
4685                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4686
4687     // ---------- CAN_CHANGE --------------------------------------------------
4688     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      // default: cannot change
4689     for (j = 0; j < element_info[i].num_change_pages; j++)
4690       if (element_info[i].change_page[j].can_change)
4691         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4692
4693     // ---------- HAS_ACTION --------------------------------------------------
4694     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      // default: has no action
4695     for (j = 0; j < element_info[i].num_change_pages; j++)
4696       if (element_info[i].change_page[j].has_action)
4697         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4698
4699     // ---------- CAN_CHANGE_OR_HAS_ACTION ------------------------------------
4700     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4701                                                   HAS_ACTION(i)));
4702
4703     // ---------- GFX_CRUMBLED ------------------------------------------------
4704     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4705                  element_info[i].crumbled[ACTION_DEFAULT] !=
4706                  element_info[i].graphic[ACTION_DEFAULT]);
4707
4708     // ---------- EDITOR_CASCADE ----------------------------------------------
4709     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4710                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4711   }
4712
4713   // dynamically adjust element properties according to game engine version
4714   {
4715     static int ep_em_slippery_wall[] =
4716     {
4717       EL_WALL,
4718       EL_STEELWALL,
4719       EL_EXPANDABLE_WALL,
4720       EL_EXPANDABLE_WALL_HORIZONTAL,
4721       EL_EXPANDABLE_WALL_VERTICAL,
4722       EL_EXPANDABLE_WALL_ANY,
4723       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4724       EL_EXPANDABLE_STEELWALL_VERTICAL,
4725       EL_EXPANDABLE_STEELWALL_ANY,
4726       EL_EXPANDABLE_STEELWALL_GROWING,
4727       -1
4728     };
4729
4730     static int ep_em_explodes_by_fire[] =
4731     {
4732       EL_EM_DYNAMITE,
4733       EL_EM_DYNAMITE_ACTIVE,
4734       EL_MOLE,
4735       -1
4736     };
4737
4738     // special EM style gems behaviour
4739     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4740       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4741                    level.em_slippery_gems);
4742
4743     // "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1
4744     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4745                  (level.em_slippery_gems &&
4746                   engine_version > VERSION_IDENT(2,0,1,0)));
4747
4748     // special EM style explosion behaviour regarding chain reactions
4749     for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4750       SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4751                    level.em_explodes_by_fire);
4752   }
4753
4754   // this is needed because some graphics depend on element properties
4755   if (game_status == GAME_MODE_PLAYING)
4756     InitElementGraphicInfo();
4757 }
4758
4759 void InitElementPropertiesGfxElement(void)
4760 {
4761   int i;
4762
4763   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4764   {
4765     struct ElementInfo *ei = &element_info[i];
4766
4767     ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4768   }
4769 }
4770
4771 static void InitGlobal(void)
4772 {
4773   int graphic;
4774   int i;
4775
4776   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4777   {
4778     // check if element_name_info entry defined for each element in "main.h"
4779     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4780       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4781
4782     element_info[i].token_name = element_name_info[i].token_name;
4783     element_info[i].class_name = element_name_info[i].class_name;
4784     element_info[i].editor_description= element_name_info[i].editor_description;
4785   }
4786
4787   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS + 1; i++)
4788   {
4789     // check if global_anim_name_info defined for each entry in "main.h"
4790     if (i < NUM_GLOBAL_ANIM_TOKENS &&
4791         global_anim_name_info[i].token_name == NULL)
4792       Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
4793
4794     global_anim_info[i].token_name = global_anim_name_info[i].token_name;
4795   }
4796
4797   // create hash from image config list
4798   image_config_hash = newSetupFileHash();
4799   for (i = 0; image_config[i].token != NULL; i++)
4800     setHashEntry(image_config_hash,
4801                  image_config[i].token,
4802                  image_config[i].value);
4803
4804   // create hash from element token list
4805   element_token_hash = newSetupFileHash();
4806   for (i = 0; element_name_info[i].token_name != NULL; i++)
4807     setHashEntry(element_token_hash,
4808                  element_name_info[i].token_name,
4809                  int2str(i, 0));
4810
4811   // create hash from graphic token list
4812   graphic_token_hash = newSetupFileHash();
4813   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4814     if (strSuffix(image_config[i].value, ".png") ||
4815         strSuffix(image_config[i].value, ".pcx") ||
4816         strSuffix(image_config[i].value, ".wav") ||
4817         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4818       setHashEntry(graphic_token_hash,
4819                    image_config[i].token,
4820                    int2str(graphic++, 0));
4821
4822   // create hash from font token list
4823   font_token_hash = newSetupFileHash();
4824   for (i = 0; font_info[i].token_name != NULL; i++)
4825     setHashEntry(font_token_hash,
4826                  font_info[i].token_name,
4827                  int2str(i, 0));
4828
4829   // set default filenames for all cloned graphics in static configuration
4830   for (i = 0; image_config[i].token != NULL; i++)
4831   {
4832     if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4833     {
4834       char *token = image_config[i].token;
4835       char *token_clone_from = getStringCat2(token, ".clone_from");
4836       char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4837
4838       if (token_cloned != NULL)
4839       {
4840         char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4841
4842         if (value_cloned != NULL)
4843         {
4844           // set default filename in static configuration
4845           image_config[i].value = value_cloned;
4846
4847           // set default filename in image config hash
4848           setHashEntry(image_config_hash, token, value_cloned);
4849         }
4850       }
4851
4852       free(token_clone_from);
4853     }
4854   }
4855
4856   // always start with reliable default values (all elements)
4857   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4858     ActiveElement[i] = i;
4859
4860   // now add all entries that have an active state (active elements)
4861   for (i = 0; element_with_active_state[i].element != -1; i++)
4862   {
4863     int element = element_with_active_state[i].element;
4864     int element_active = element_with_active_state[i].element_active;
4865
4866     ActiveElement[element] = element_active;
4867   }
4868
4869   // always start with reliable default values (all buttons)
4870   for (i = 0; i < NUM_IMAGE_FILES; i++)
4871     ActiveButton[i] = i;
4872
4873   // now add all entries that have an active state (active buttons)
4874   for (i = 0; button_with_active_state[i].button != -1; i++)
4875   {
4876     int button = button_with_active_state[i].button;
4877     int button_active = button_with_active_state[i].button_active;
4878
4879     ActiveButton[button] = button_active;
4880   }
4881
4882   // always start with reliable default values (all fonts)
4883   for (i = 0; i < NUM_FONTS; i++)
4884     ActiveFont[i] = i;
4885
4886   // now add all entries that have an active state (active fonts)
4887   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4888   {
4889     int font = font_with_active_state[i].font_nr;
4890     int font_active = font_with_active_state[i].font_nr_active;
4891
4892     ActiveFont[font] = font_active;
4893   }
4894
4895   global.autoplay_leveldir = NULL;
4896   global.convert_leveldir = NULL;
4897   global.create_images_dir = NULL;
4898
4899   global.frames_per_second = 0;
4900   global.show_frames_per_second = FALSE;
4901
4902   global.border_status = GAME_MODE_LOADING;
4903   global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4904
4905   global.use_envelope_request = FALSE;
4906 }
4907
4908 static void Execute_Command(char *command)
4909 {
4910   int i;
4911
4912   if (strEqual(command, "print graphicsinfo.conf"))
4913   {
4914     Print("# You can configure additional/alternative image files here.\n");
4915     Print("# (The entries below are default and therefore commented out.)\n");
4916     Print("\n");
4917     Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4918     Print("\n");
4919     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4920     Print("\n");
4921
4922     for (i = 0; image_config[i].token != NULL; i++)
4923       Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4924                                              image_config[i].value));
4925
4926     exit(0);
4927   }
4928   else if (strEqual(command, "print soundsinfo.conf"))
4929   {
4930     Print("# You can configure additional/alternative sound files here.\n");
4931     Print("# (The entries below are default and therefore commented out.)\n");
4932     Print("\n");
4933     Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4934     Print("\n");
4935     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4936     Print("\n");
4937
4938     for (i = 0; sound_config[i].token != NULL; i++)
4939       Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4940                                              sound_config[i].value));
4941
4942     exit(0);
4943   }
4944   else if (strEqual(command, "print musicinfo.conf"))
4945   {
4946     Print("# You can configure additional/alternative music files here.\n");
4947     Print("# (The entries below are default and therefore commented out.)\n");
4948     Print("\n");
4949     Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4950     Print("\n");
4951     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4952     Print("\n");
4953
4954     for (i = 0; music_config[i].token != NULL; i++)
4955       Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4956                                              music_config[i].value));
4957
4958     exit(0);
4959   }
4960   else if (strEqual(command, "print editorsetup.conf"))
4961   {
4962     Print("# You can configure your personal editor element list here.\n");
4963     Print("# (The entries below are default and therefore commented out.)\n");
4964     Print("\n");
4965
4966     // this is needed to be able to check element list for cascade elements
4967     InitElementPropertiesStatic();
4968     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4969
4970     PrintEditorElementList();
4971
4972     exit(0);
4973   }
4974   else if (strEqual(command, "print helpanim.conf"))
4975   {
4976     Print("# You can configure different element help animations here.\n");
4977     Print("# (The entries below are default and therefore commented out.)\n");
4978     Print("\n");
4979
4980     for (i = 0; helpanim_config[i].token != NULL; i++)
4981     {
4982       Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4983                                              helpanim_config[i].value));
4984
4985       if (strEqual(helpanim_config[i].token, "end"))
4986         Print("#\n");
4987     }
4988
4989     exit(0);
4990   }
4991   else if (strEqual(command, "print helptext.conf"))
4992   {
4993     Print("# You can configure different element help text here.\n");
4994     Print("# (The entries below are default and therefore commented out.)\n");
4995     Print("\n");
4996
4997     for (i = 0; helptext_config[i].token != NULL; i++)
4998       Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4999                                              helptext_config[i].value));
5000
5001     exit(0);
5002   }
5003   else if (strPrefix(command, "dump level "))
5004   {
5005     char *filename = &command[11];
5006
5007     if (!fileExists(filename))
5008       Error(ERR_EXIT, "cannot open file '%s'", filename);
5009
5010     LoadLevelFromFilename(&level, filename);
5011     DumpLevel(&level);
5012
5013     exit(0);
5014   }
5015   else if (strPrefix(command, "dump tape "))
5016   {
5017     char *filename = &command[10];
5018
5019     if (!fileExists(filename))
5020       Error(ERR_EXIT, "cannot open file '%s'", filename);
5021
5022     LoadTapeFromFilename(filename);
5023     DumpTape(&tape);
5024
5025     exit(0);
5026   }
5027   else if (strPrefix(command, "autotest ") ||
5028            strPrefix(command, "autoplay ") ||
5029            strPrefix(command, "autoffwd ") ||
5030            strPrefix(command, "autowarp "))
5031   {
5032     char *str_ptr = getStringCopy(&command[9]); // read command parameters
5033
5034     global.autoplay_mode =
5035       (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
5036        strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
5037        strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
5038        strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
5039        AUTOPLAY_MODE_NONE);
5040
5041     while (*str_ptr != '\0')                    // continue parsing string
5042     {
5043       // cut leading whitespace from string, replace it by string terminator
5044       while (*str_ptr == ' ' || *str_ptr == '\t')
5045         *str_ptr++ = '\0';
5046
5047       if (*str_ptr == '\0')                     // end of string reached
5048         break;
5049
5050       if (global.autoplay_leveldir == NULL)     // read level set string
5051       {
5052         global.autoplay_leveldir = str_ptr;
5053         global.autoplay_all = TRUE;             // default: play all tapes
5054
5055         for (i = 0; i < MAX_TAPES_PER_SET; i++)
5056           global.autoplay_level[i] = FALSE;
5057       }
5058       else                                      // read level number string
5059       {
5060         int level_nr = atoi(str_ptr);           // get level_nr value
5061
5062         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
5063           global.autoplay_level[level_nr] = TRUE;
5064
5065         global.autoplay_all = FALSE;
5066       }
5067
5068       // advance string pointer to the next whitespace (or end of string)
5069       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
5070         str_ptr++;
5071     }
5072
5073     if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
5074       program.headless = TRUE;
5075   }
5076   else if (strPrefix(command, "convert "))
5077   {
5078     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
5079     char *str_ptr = strchr(str_copy, ' ');
5080
5081     global.convert_leveldir = str_copy;
5082     global.convert_level_nr = -1;
5083
5084     if (str_ptr != NULL)                        // level number follows
5085     {
5086       *str_ptr++ = '\0';                        // terminate leveldir string
5087       global.convert_level_nr = atoi(str_ptr);  // get level_nr value
5088     }
5089
5090     program.headless = TRUE;
5091   }
5092   else if (strPrefix(command, "create images "))
5093   {
5094     global.create_images_dir = getStringCopy(&command[14]);
5095
5096     if (access(global.create_images_dir, W_OK) != 0)
5097       Error(ERR_EXIT, "image target directory '%s' not found or not writable",
5098             global.create_images_dir);
5099   }
5100   else if (strPrefix(command, "create CE image "))
5101   {
5102     CreateCustomElementImages(&command[16]);
5103
5104     exit(0);
5105   }
5106   else
5107   {
5108     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
5109   }
5110
5111   // disable networking if any valid command was recognized
5112   options.network = setup.network_mode = FALSE;
5113 }
5114
5115 static void InitSetup(void)
5116 {
5117   LoadSetup();                                  // global setup info
5118   LoadSetup_AutoSetup();                        // global auto setup info
5119
5120   // set some options from setup file
5121
5122   if (setup.options.verbose)
5123     options.verbose = TRUE;
5124
5125   if (setup.debug.show_frames_per_second)
5126     global.show_frames_per_second = TRUE;
5127 }
5128
5129 static void InitGameInfo(void)
5130 {
5131   game.restart_level = FALSE;
5132   game.restart_game_message = NULL;
5133   game.request_active = FALSE;
5134 }
5135
5136 static void InitPlayerInfo(void)
5137 {
5138   int i;
5139
5140   // choose default local player
5141   local_player = &stored_player[0];
5142
5143   for (i = 0; i < MAX_PLAYERS; i++)
5144   {
5145     stored_player[i].connected_locally = FALSE;
5146     stored_player[i].connected_network = FALSE;
5147   }
5148
5149   local_player->connected_locally = TRUE;
5150 }
5151
5152 static void InitArtworkInfo(void)
5153 {
5154   LoadArtworkInfo();
5155 }
5156
5157 static char *get_string_in_brackets(char *string)
5158 {
5159   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5160
5161   sprintf(string_in_brackets, "[%s]", string);
5162
5163   return string_in_brackets;
5164 }
5165
5166 static char *get_level_id_suffix(int id_nr)
5167 {
5168   char *id_suffix = checked_malloc(1 + 3 + 1);
5169
5170   if (id_nr < 0 || id_nr > 999)
5171     id_nr = 0;
5172
5173   sprintf(id_suffix, ".%03d", id_nr);
5174
5175   return id_suffix;
5176 }
5177
5178 static void InitArtworkConfig(void)
5179 {
5180   static char *image_id_prefix[MAX_NUM_ELEMENTS +
5181                                NUM_FONTS +
5182                                NUM_GLOBAL_ANIM_TOKENS + 1];
5183   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5184                                NUM_GLOBAL_ANIM_TOKENS + 1];
5185   static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5186                                NUM_GLOBAL_ANIM_TOKENS + 1];
5187   static char *action_id_suffix[NUM_ACTIONS + 1];
5188   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5189   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5190   static char *level_id_suffix[MAX_LEVELS + 1];
5191   static char *dummy[1] = { NULL };
5192   static char *ignore_generic_tokens[] =
5193   {
5194     "name",
5195     "sort_priority",
5196     "program_title",
5197     "program_copyright",
5198     "program_company",
5199
5200     NULL
5201   };
5202   static char **ignore_image_tokens;
5203   static char **ignore_sound_tokens;
5204   static char **ignore_music_tokens;
5205   int num_ignore_generic_tokens;
5206   int num_ignore_image_tokens;
5207   int num_ignore_sound_tokens;
5208   int num_ignore_music_tokens;
5209   int i;
5210
5211   // dynamically determine list of generic tokens to be ignored
5212   num_ignore_generic_tokens = 0;
5213   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5214     num_ignore_generic_tokens++;
5215
5216   // dynamically determine list of image tokens to be ignored
5217   num_ignore_image_tokens = num_ignore_generic_tokens;
5218   for (i = 0; image_config_vars[i].token != NULL; i++)
5219     num_ignore_image_tokens++;
5220   ignore_image_tokens =
5221     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5222   for (i = 0; i < num_ignore_generic_tokens; i++)
5223     ignore_image_tokens[i] = ignore_generic_tokens[i];
5224   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5225     ignore_image_tokens[num_ignore_generic_tokens + i] =
5226       image_config_vars[i].token;
5227   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5228
5229   // dynamically determine list of sound tokens to be ignored
5230   num_ignore_sound_tokens = num_ignore_generic_tokens;
5231   ignore_sound_tokens =
5232     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5233   for (i = 0; i < num_ignore_generic_tokens; i++)
5234     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5235   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5236
5237   // dynamically determine list of music tokens to be ignored
5238   num_ignore_music_tokens = num_ignore_generic_tokens;
5239   ignore_music_tokens =
5240     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5241   for (i = 0; i < num_ignore_generic_tokens; i++)
5242     ignore_music_tokens[i] = ignore_generic_tokens[i];
5243   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5244
5245   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5246     image_id_prefix[i] = element_info[i].token_name;
5247   for (i = 0; i < NUM_FONTS; i++)
5248     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5249   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5250     image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5251       global_anim_info[i].token_name;
5252   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5253
5254   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5255     sound_id_prefix[i] = element_info[i].token_name;
5256   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5257     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5258       get_string_in_brackets(element_info[i].class_name);
5259   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5260     sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5261       global_anim_info[i].token_name;
5262   sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5263
5264   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5265     music_id_prefix[i] = music_prefix_info[i].prefix;
5266   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5267     music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5268       global_anim_info[i].token_name;
5269   music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5270
5271   for (i = 0; i < NUM_ACTIONS; i++)
5272     action_id_suffix[i] = element_action_info[i].suffix;
5273   action_id_suffix[NUM_ACTIONS] = NULL;
5274
5275   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5276     direction_id_suffix[i] = element_direction_info[i].suffix;
5277   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5278
5279   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5280     special_id_suffix[i] = special_suffix_info[i].suffix;
5281   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5282
5283   for (i = 0; i < MAX_LEVELS; i++)
5284     level_id_suffix[i] = get_level_id_suffix(i);
5285   level_id_suffix[MAX_LEVELS] = NULL;
5286
5287   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5288                 image_id_prefix, action_id_suffix, direction_id_suffix,
5289                 special_id_suffix, ignore_image_tokens);
5290   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5291                 sound_id_prefix, action_id_suffix, dummy,
5292                 special_id_suffix, ignore_sound_tokens);
5293   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5294                 music_id_prefix, action_id_suffix, special_id_suffix,
5295                 level_id_suffix, ignore_music_tokens);
5296 }
5297
5298 static void InitMixer(void)
5299 {
5300   OpenAudio();
5301
5302   StartMixer();
5303 }
5304
5305 static void InitVideoOverlay(void)
5306 {
5307   // if virtual buttons are not loaded from setup file, repeat initializing
5308   // virtual buttons grid with default values now that video is initialized
5309   if (!setup.touch.grid_initialized)
5310     InitSetup();
5311
5312   InitTileCursorInfo();
5313   InitOverlayInfo();
5314 }
5315
5316 void InitGfxBuffers(void)
5317 {
5318   static int win_xsize_last = -1;
5319   static int win_ysize_last = -1;
5320
5321   // create additional image buffers for double-buffering and cross-fading
5322
5323   if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5324   {
5325     // used to temporarily store the backbuffer -- only re-create if changed
5326     ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5327     ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5328
5329     win_xsize_last = WIN_XSIZE;
5330     win_ysize_last = WIN_YSIZE;
5331   }
5332
5333   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5334   ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5335   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5336   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5337
5338   // initialize screen properties
5339   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5340                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5341                    bitmap_db_field);
5342   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5343   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5344   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5345   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5346   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5347   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5348
5349   // required if door size definitions have changed
5350   InitGraphicCompatibilityInfo_Doors();
5351
5352   InitGfxBuffers_EM();
5353   InitGfxBuffers_SP();
5354 }
5355
5356 static void InitGfx(void)
5357 {
5358   struct GraphicInfo *graphic_info_last = graphic_info;
5359   char *filename_font_initial = NULL;
5360   char *filename_anim_initial = NULL;
5361   Bitmap *bitmap_font_initial = NULL;
5362   int i, j;
5363
5364   // determine settings for initial font (for displaying startup messages)
5365   for (i = 0; image_config[i].token != NULL; i++)
5366   {
5367     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5368     {
5369       char font_token[128];
5370       int len_font_token;
5371
5372       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5373       len_font_token = strlen(font_token);
5374
5375       if (strEqual(image_config[i].token, font_token))
5376         filename_font_initial = image_config[i].value;
5377       else if (strlen(image_config[i].token) > len_font_token &&
5378                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5379       {
5380         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5381           font_initial[j].src_x = atoi(image_config[i].value);
5382         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5383           font_initial[j].src_y = atoi(image_config[i].value);
5384         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5385           font_initial[j].width = atoi(image_config[i].value);
5386         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5387           font_initial[j].height = atoi(image_config[i].value);
5388       }
5389     }
5390   }
5391
5392   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5393   {
5394     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5395     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5396   }
5397
5398   if (filename_font_initial == NULL)    // should not happen
5399     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5400
5401   InitGfxBuffers();
5402   InitGfxCustomArtworkInfo();
5403   InitGfxOtherSettings();
5404
5405   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5406
5407   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5408     font_initial[j].bitmap = bitmap_font_initial;
5409
5410   InitFontGraphicInfo();
5411
5412   DrawProgramInfo();
5413
5414   DrawInitText("Loading graphics", 120, FC_GREEN);
5415
5416   // initialize settings for busy animation with default values
5417   int parameter[NUM_GFX_ARGS];
5418   for (i = 0; i < NUM_GFX_ARGS; i++)
5419     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5420                                                image_config_suffix[i].token,
5421                                                image_config_suffix[i].type);
5422
5423   char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5424   int len_anim_token = strlen(anim_token);
5425
5426   // read settings for busy animation from default custom artwork config
5427   char *gfx_config_filename = getPath3(options.graphics_directory,
5428                                        GFX_DEFAULT_SUBDIR,
5429                                        GRAPHICSINFO_FILENAME);
5430
5431   if (fileExists(gfx_config_filename))
5432   {
5433     SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5434
5435     if (setup_file_hash)
5436     {
5437       char *filename = getHashEntry(setup_file_hash, anim_token);
5438
5439       if (filename)
5440       {
5441         filename_anim_initial = getStringCopy(filename);
5442
5443         for (j = 0; image_config_suffix[j].token != NULL; j++)
5444         {
5445           int type = image_config_suffix[j].type;
5446           char *suffix = image_config_suffix[j].token;
5447           char *token = getStringCat2(anim_token, suffix);
5448           char *value = getHashEntry(setup_file_hash, token);
5449
5450           checked_free(token);
5451
5452           if (value)
5453             parameter[j] = get_graphic_parameter_value(value, suffix, type);
5454         }
5455       }
5456
5457       freeSetupFileHash(setup_file_hash);
5458     }
5459   }
5460
5461   if (filename_anim_initial == NULL)
5462   {
5463     // read settings for busy animation from static default artwork config
5464     for (i = 0; image_config[i].token != NULL; i++)
5465     {
5466       if (strEqual(image_config[i].token, anim_token))
5467         filename_anim_initial = getStringCopy(image_config[i].value);
5468       else if (strlen(image_config[i].token) > len_anim_token &&
5469                strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5470       {
5471         for (j = 0; image_config_suffix[j].token != NULL; j++)
5472         {
5473           if (strEqual(&image_config[i].token[len_anim_token],
5474                        image_config_suffix[j].token))
5475             parameter[j] =
5476               get_graphic_parameter_value(image_config[i].value,
5477                                           image_config_suffix[j].token,
5478                                           image_config_suffix[j].type);
5479         }
5480       }
5481     }
5482   }
5483
5484   if (filename_anim_initial == NULL)    // should not happen
5485     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5486
5487   anim_initial.bitmaps =
5488     checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5489
5490   anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5491     LoadCustomImage(filename_anim_initial);
5492
5493   checked_free(filename_anim_initial);
5494
5495   graphic_info = &anim_initial;         // graphic == 0 => anim_initial
5496
5497   set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5498
5499   graphic_info = graphic_info_last;
5500
5501   init.busy.width  = anim_initial.width;
5502   init.busy.height = anim_initial.height;
5503
5504   InitMenuDesignSettings_Static();
5505
5506   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5507   InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5508   InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5509   InitGfxDrawTileCursorFunction(DrawTileCursor);
5510
5511   gfx.fade_border_source_status = global.border_status;
5512   gfx.fade_border_target_status = global.border_status;
5513   gfx.masked_border_bitmap_ptr = backbuffer;
5514
5515   // use copy of busy animation to prevent change while reloading artwork
5516   init_last = init;
5517 }
5518
5519 static void InitGfxBackground(void)
5520 {
5521   fieldbuffer = bitmap_db_field;
5522   SetDrawtoField(DRAW_TO_BACKBUFFER);
5523
5524   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5525
5526   redraw_mask = REDRAW_ALL;
5527 }
5528
5529 static void InitLevelInfo(void)
5530 {
5531   LoadLevelInfo();                              // global level info
5532   LoadLevelSetup_LastSeries();                  // last played series info
5533   LoadLevelSetup_SeriesInfo();                  // last played level info
5534
5535   if (global.autoplay_leveldir &&
5536       global.autoplay_mode != AUTOPLAY_MODE_TEST)
5537   {
5538     leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5539                                                  global.autoplay_leveldir);
5540     if (leveldir_current == NULL)
5541       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5542   }
5543
5544   SetLevelSetInfo(leveldir_current->identifier, level_nr);
5545 }
5546
5547 static void InitLevelArtworkInfo(void)
5548 {
5549   LoadLevelArtworkInfo();
5550 }
5551
5552 static void InitImages(void)
5553 {
5554   print_timestamp_init("InitImages");
5555
5556 #if 0
5557   printf("::: leveldir_current->identifier == '%s'\n",
5558          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5559   printf("::: leveldir_current->graphics_path == '%s'\n",
5560          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5561   printf("::: leveldir_current->graphics_set == '%s'\n",
5562          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5563   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5564          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5565 #endif
5566
5567   setLevelArtworkDir(artwork.gfx_first);
5568
5569 #if 0
5570   printf("::: leveldir_current->identifier == '%s'\n",
5571          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5572   printf("::: leveldir_current->graphics_path == '%s'\n",
5573          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5574   printf("::: leveldir_current->graphics_set == '%s'\n",
5575          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5576   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5577          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5578 #endif
5579
5580 #if 0
5581   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5582          leveldir_current->identifier,
5583          artwork.gfx_current_identifier,
5584          artwork.gfx_current->identifier,
5585          leveldir_current->graphics_set,
5586          leveldir_current->graphics_path);
5587 #endif
5588
5589   UPDATE_BUSY_STATE();
5590
5591   ReloadCustomImages();
5592   print_timestamp_time("ReloadCustomImages");
5593
5594   UPDATE_BUSY_STATE();
5595
5596   LoadCustomElementDescriptions();
5597   print_timestamp_time("LoadCustomElementDescriptions");
5598
5599   UPDATE_BUSY_STATE();
5600
5601   LoadMenuDesignSettings();
5602   print_timestamp_time("LoadMenuDesignSettings");
5603
5604   UPDATE_BUSY_STATE();
5605
5606   ReinitializeGraphics();
5607   print_timestamp_time("ReinitializeGraphics");
5608
5609   LoadMenuDesignSettings_AfterGraphics();
5610   print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5611
5612   UPDATE_BUSY_STATE();
5613
5614   print_timestamp_done("InitImages");
5615 }
5616
5617 static void InitSound(char *identifier)
5618 {
5619   print_timestamp_init("InitSound");
5620
5621   if (identifier == NULL)
5622     identifier = artwork.snd_current->identifier;
5623
5624   // set artwork path to send it to the sound server process
5625   setLevelArtworkDir(artwork.snd_first);
5626
5627   InitReloadCustomSounds(identifier);
5628   print_timestamp_time("InitReloadCustomSounds");
5629
5630   ReinitializeSounds();
5631   print_timestamp_time("ReinitializeSounds");
5632
5633   print_timestamp_done("InitSound");
5634 }
5635
5636 static void InitMusic(char *identifier)
5637 {
5638   print_timestamp_init("InitMusic");
5639
5640   if (identifier == NULL)
5641     identifier = artwork.mus_current->identifier;
5642
5643   // set artwork path to send it to the sound server process
5644   setLevelArtworkDir(artwork.mus_first);
5645
5646   InitReloadCustomMusic(identifier);
5647   print_timestamp_time("InitReloadCustomMusic");
5648
5649   ReinitializeMusic();
5650   print_timestamp_time("ReinitializeMusic");
5651
5652   print_timestamp_done("InitMusic");
5653 }
5654
5655 static void InitArtworkDone(void)
5656 {
5657   if (program.headless)
5658     return;
5659
5660   InitGlobalAnimations();
5661 }
5662
5663 static void InitNetworkSettings(void)
5664 {
5665   boolean network_enabled = (options.network || setup.network_mode);
5666   char *network_server = (options.server_host != NULL ? options.server_host :
5667                           setup.network_server_hostname);
5668
5669   if (strEqual(network_server, STR_NETWORK_AUTO_DETECT))
5670     network_server = NULL;
5671
5672   InitNetworkInfo(network_enabled,
5673                   FALSE,
5674                   options.serveronly,
5675                   network_server,
5676                   options.server_port);
5677 }
5678
5679 void InitNetworkServer(void)
5680 {
5681   if (!network.enabled || network.connected)
5682     return;
5683
5684   LimitScreenUpdates(FALSE);
5685
5686   if (game_status == GAME_MODE_LOADING)
5687     DrawProgramInfo();
5688
5689   if (!ConnectToServer(network.server_host, network.server_port))
5690   {
5691     network.enabled = FALSE;
5692
5693     setup.network_mode = FALSE;
5694   }
5695   else
5696   {
5697     SendToServer_ProtocolVersion();
5698     SendToServer_PlayerName(setup.player_name);
5699     SendToServer_NrWanted(setup.network_player_nr + 1);
5700
5701     network.connected = TRUE;
5702   }
5703
5704   // short time to recognize result of network initialization
5705   if (game_status == GAME_MODE_LOADING)
5706     Delay_WithScreenUpdates(1000);
5707 }
5708
5709 static boolean CheckArtworkConfigForCustomElements(char *filename)
5710 {
5711   SetupFileHash *setup_file_hash;
5712   boolean redefined_ce_found = FALSE;
5713
5714   // !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!!
5715
5716   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5717   {
5718     BEGIN_HASH_ITERATION(setup_file_hash, itr)
5719     {
5720       char *token = HASH_ITERATION_TOKEN(itr);
5721
5722       if (strPrefix(token, "custom_"))
5723       {
5724         redefined_ce_found = TRUE;
5725
5726         break;
5727       }
5728     }
5729     END_HASH_ITERATION(setup_file_hash, itr)
5730
5731     freeSetupFileHash(setup_file_hash);
5732   }
5733
5734   return redefined_ce_found;
5735 }
5736
5737 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5738 {
5739   char *filename_base, *filename_local;
5740   boolean redefined_ce_found = FALSE;
5741
5742   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5743
5744 #if 0
5745   printf("::: leveldir_current->identifier == '%s'\n",
5746          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5747   printf("::: leveldir_current->graphics_path == '%s'\n",
5748          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5749   printf("::: leveldir_current->graphics_set == '%s'\n",
5750          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5751   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5752          leveldir_current == NULL ? "[NULL]" :
5753          LEVELDIR_ARTWORK_SET(leveldir_current, type));
5754 #endif
5755
5756   // first look for special artwork configured in level series config
5757   filename_base = getCustomArtworkLevelConfigFilename(type);
5758
5759 #if 0
5760   printf("::: filename_base == '%s'\n", filename_base);
5761 #endif
5762
5763   if (fileExists(filename_base))
5764     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5765
5766   filename_local = getCustomArtworkConfigFilename(type);
5767
5768 #if 0
5769   printf("::: filename_local == '%s'\n", filename_local);
5770 #endif
5771
5772   if (filename_local != NULL && !strEqual(filename_base, filename_local))
5773     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5774
5775 #if 0
5776   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5777 #endif
5778
5779   return redefined_ce_found;
5780 }
5781
5782 static void InitOverrideArtwork(void)
5783 {
5784   boolean redefined_ce_found = FALSE;
5785
5786   // to check if this level set redefines any CEs, do not use overriding
5787   gfx.override_level_graphics = FALSE;
5788   gfx.override_level_sounds   = FALSE;
5789   gfx.override_level_music    = FALSE;
5790
5791   // now check if this level set has definitions for custom elements
5792   if (setup.override_level_graphics == AUTO ||
5793       setup.override_level_sounds   == AUTO ||
5794       setup.override_level_music    == AUTO)
5795     redefined_ce_found =
5796       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5797        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5798        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5799
5800 #if 0
5801   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5802 #endif
5803
5804   if (redefined_ce_found)
5805   {
5806     // this level set has CE definitions: change "AUTO" to "FALSE"
5807     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5808     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
5809     gfx.override_level_music    = (setup.override_level_music    == TRUE);
5810   }
5811   else
5812   {
5813     // this level set has no CE definitions: change "AUTO" to "TRUE"
5814     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5815     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
5816     gfx.override_level_music    = (setup.override_level_music    != FALSE);
5817   }
5818
5819 #if 0
5820   printf("::: => %d, %d, %d\n",
5821          gfx.override_level_graphics,
5822          gfx.override_level_sounds,
5823          gfx.override_level_music);
5824 #endif
5825 }
5826
5827 static char *getNewArtworkIdentifier(int type)
5828 {
5829   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5830   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5831   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5832   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5833   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5834   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5835   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5836   char *leveldir_identifier = leveldir_current->identifier;
5837   // !!! setLevelArtworkDir() should be moved to an earlier stage !!!
5838   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5839   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5840   char *artwork_current_identifier;
5841   char *artwork_new_identifier = NULL;  // default: nothing has changed
5842
5843   // leveldir_current may be invalid (level group, parent link)
5844   if (!validLevelSeries(leveldir_current))
5845     return NULL;
5846
5847   /* 1st step: determine artwork set to be activated in descending order:
5848      --------------------------------------------------------------------
5849      1. setup artwork (when configured to override everything else)
5850      2. artwork set configured in "levelinfo.conf" of current level set
5851         (artwork in level directory will have priority when loading later)
5852      3. artwork in level directory (stored in artwork sub-directory)
5853      4. setup artwork (currently configured in setup menu) */
5854
5855   if (setup_override_artwork)
5856     artwork_current_identifier = setup_artwork_set;
5857   else if (leveldir_artwork_set != NULL)
5858     artwork_current_identifier = leveldir_artwork_set;
5859   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5860     artwork_current_identifier = leveldir_identifier;
5861   else
5862     artwork_current_identifier = setup_artwork_set;
5863
5864
5865   /* 2nd step: check if it is really needed to reload artwork set
5866      ------------------------------------------------------------ */
5867
5868   // ---------- reload if level set and also artwork set has changed ----------
5869   if (leveldir_current_identifier[type] != leveldir_identifier &&
5870       (last_has_level_artwork_set[type] || has_level_artwork_set))
5871     artwork_new_identifier = artwork_current_identifier;
5872
5873   leveldir_current_identifier[type] = leveldir_identifier;
5874   last_has_level_artwork_set[type] = has_level_artwork_set;
5875
5876   // ---------- reload if "override artwork" setting has changed --------------
5877   if (last_override_level_artwork[type] != setup_override_artwork)
5878     artwork_new_identifier = artwork_current_identifier;
5879
5880   last_override_level_artwork[type] = setup_override_artwork;
5881
5882   // ---------- reload if current artwork identifier has changed --------------
5883   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5884                 artwork_current_identifier))
5885     artwork_new_identifier = artwork_current_identifier;
5886
5887   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5888
5889   // ---------- do not reload directly after starting -------------------------
5890   if (!initialized[type])
5891     artwork_new_identifier = NULL;
5892
5893   initialized[type] = TRUE;
5894
5895   return artwork_new_identifier;
5896 }
5897
5898 void ReloadCustomArtwork(int force_reload)
5899 {
5900   int last_game_status = game_status;   // save current game status
5901   char *gfx_new_identifier;
5902   char *snd_new_identifier;
5903   char *mus_new_identifier;
5904   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5905   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5906   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5907   boolean reload_needed;
5908
5909   InitOverrideArtwork();
5910
5911   force_reload_gfx |= AdjustGraphicsForEMC();
5912   force_reload_snd |= AdjustSoundsForEMC();
5913
5914   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5915   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5916   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5917
5918   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5919                    snd_new_identifier != NULL || force_reload_snd ||
5920                    mus_new_identifier != NULL || force_reload_mus);
5921
5922   if (!reload_needed)
5923     return;
5924
5925   print_timestamp_init("ReloadCustomArtwork");
5926
5927   SetGameStatus(GAME_MODE_LOADING);
5928
5929   FadeOut(REDRAW_ALL);
5930
5931   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5932   print_timestamp_time("ClearRectangle");
5933
5934   FadeIn(REDRAW_ALL);
5935
5936   if (gfx_new_identifier != NULL || force_reload_gfx)
5937   {
5938 #if 0
5939     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5940            artwork.gfx_current_identifier,
5941            gfx_new_identifier,
5942            artwork.gfx_current->identifier,
5943            leveldir_current->graphics_set);
5944 #endif
5945
5946     InitImages();
5947     print_timestamp_time("InitImages");
5948   }
5949
5950   if (snd_new_identifier != NULL || force_reload_snd)
5951   {
5952     InitSound(snd_new_identifier);
5953     print_timestamp_time("InitSound");
5954   }
5955
5956   if (mus_new_identifier != NULL || force_reload_mus)
5957   {
5958     InitMusic(mus_new_identifier);
5959     print_timestamp_time("InitMusic");
5960   }
5961
5962   InitArtworkDone();
5963
5964   SetGameStatus(last_game_status);      // restore current game status
5965
5966   init_last = init;                     // switch to new busy animation
5967
5968   FadeOut(REDRAW_ALL);
5969
5970   RedrawGlobalBorder();
5971
5972   // force redraw of (open or closed) door graphics
5973   SetDoorState(DOOR_OPEN_ALL);
5974   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5975
5976   FadeSetEnterScreen();
5977   FadeSkipNextFadeOut();
5978
5979   print_timestamp_done("ReloadCustomArtwork");
5980
5981   LimitScreenUpdates(FALSE);
5982 }
5983
5984 void KeyboardAutoRepeatOffUnlessAutoplay(void)
5985 {
5986   if (global.autoplay_leveldir == NULL)
5987     KeyboardAutoRepeatOff();
5988 }
5989
5990 void DisplayExitMessage(char *format, va_list ap)
5991 {
5992   // also check for initialized video (headless flag may be temporarily unset)
5993   if (program.headless || !video.initialized)
5994     return;
5995
5996   // check if draw buffer and fonts for exit message are already available
5997   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5998     return;
5999
6000   int font_1 = FC_RED;
6001   int font_2 = FC_YELLOW;
6002   int font_3 = FC_BLUE;
6003   int font_width = getFontWidth(font_2);
6004   int font_height = getFontHeight(font_2);
6005   int sx = SX;
6006   int sy = SY;
6007   int sxsize = WIN_XSIZE - 2 * sx;
6008   int sysize = WIN_YSIZE - 2 * sy;
6009   int line_length = sxsize / font_width;
6010   int max_lines = sysize / font_height;
6011   int num_lines_printed;
6012
6013   gfx.sx = sx;
6014   gfx.sy = sy;
6015   gfx.sxsize = sxsize;
6016   gfx.sysize = sysize;
6017
6018   sy = 20;
6019
6020   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
6021
6022   DrawTextSCentered(sy, font_1, "Fatal error:");
6023   sy += 3 * font_height;;
6024
6025   num_lines_printed =
6026     DrawTextBufferVA(sx, sy, format, ap, font_2,
6027                      line_length, line_length, max_lines,
6028                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6029   sy += (num_lines_printed + 3) * font_height;
6030
6031   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
6032   sy += 3 * font_height;
6033
6034   num_lines_printed =
6035     DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
6036                    line_length, line_length, max_lines,
6037                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
6038
6039   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
6040
6041   redraw_mask = REDRAW_ALL;
6042
6043   // force drawing exit message even if screen updates are currently limited
6044   LimitScreenUpdates(FALSE);
6045
6046   BackToFront();
6047
6048   // deactivate toons on error message screen
6049   setup.toons = FALSE;
6050
6051   WaitForEventToContinue();
6052 }
6053
6054
6055 // ============================================================================
6056 // OpenAll()
6057 // ============================================================================
6058
6059 void OpenAll(void)
6060 {
6061   print_timestamp_init("OpenAll");
6062
6063   SetGameStatus(GAME_MODE_LOADING);
6064
6065   InitCounter();
6066
6067   InitGlobal();                 // initialize some global variables
6068
6069   print_timestamp_time("[init global stuff]");
6070
6071   InitSetup();
6072
6073   print_timestamp_time("[init setup/config stuff (1)]");
6074
6075   InitScoresInfo();
6076
6077   if (options.execute_command)
6078     Execute_Command(options.execute_command);
6079
6080   InitNetworkSettings();
6081
6082   InitRuntimeInfo();
6083
6084   if (network.serveronly)
6085   {
6086 #if defined(PLATFORM_UNIX)
6087     NetworkServer(network.server_port, TRUE);
6088 #else
6089     Error(ERR_WARN, "networking only supported in Unix version");
6090 #endif
6091
6092     exit(0);                    // never reached, server loops forever
6093   }
6094
6095   InitGameInfo();
6096   print_timestamp_time("[init setup/config stuff (2)]");
6097   InitPlayerInfo();
6098   print_timestamp_time("[init setup/config stuff (3)]");
6099   InitArtworkInfo();            // needed before loading gfx, sound & music
6100   print_timestamp_time("[init setup/config stuff (4)]");
6101   InitArtworkConfig();          // needed before forking sound child process
6102   print_timestamp_time("[init setup/config stuff (5)]");
6103   InitMixer();
6104   print_timestamp_time("[init setup/config stuff (6)]");
6105
6106   InitRND(NEW_RANDOMIZE);
6107   InitSimpleRandom(NEW_RANDOMIZE);
6108
6109   InitJoysticks();
6110
6111   print_timestamp_time("[init setup/config stuff]");
6112
6113   InitVideoDefaults();
6114   InitVideoDisplay();
6115   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
6116   InitVideoOverlay();
6117
6118   InitEventFilter(FilterMouseMotionEvents);
6119
6120   print_timestamp_time("[init video stuff]");
6121
6122   InitElementPropertiesStatic();
6123   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
6124   InitElementPropertiesGfxElement();
6125
6126   print_timestamp_time("[init element properties stuff]");
6127
6128   InitGfx();
6129
6130   print_timestamp_time("InitGfx");
6131
6132   InitLevelInfo();
6133   print_timestamp_time("InitLevelInfo");
6134
6135   InitLevelArtworkInfo();
6136   print_timestamp_time("InitLevelArtworkInfo");
6137
6138   InitOverrideArtwork();        // needs to know current level directory
6139   print_timestamp_time("InitOverrideArtwork");
6140
6141   InitImages();                 // needs to know current level directory
6142   print_timestamp_time("InitImages");
6143
6144   InitSound(NULL);              // needs to know current level directory
6145   print_timestamp_time("InitSound");
6146
6147   InitMusic(NULL);              // needs to know current level directory
6148   print_timestamp_time("InitMusic");
6149
6150   InitArtworkDone();
6151
6152   InitGfxBackground();
6153
6154   em_open_all();
6155   sp_open_all();
6156   mm_open_all();
6157
6158   if (global.autoplay_leveldir)
6159   {
6160     AutoPlayTape();
6161     return;
6162   }
6163   else if (global.convert_leveldir)
6164   {
6165     ConvertLevels();
6166     return;
6167   }
6168   else if (global.create_images_dir)
6169   {
6170     CreateLevelSketchImages();
6171     return;
6172   }
6173
6174   InitNetworkServer();
6175
6176   SetGameStatus(GAME_MODE_MAIN);
6177
6178   FadeSetEnterScreen();
6179   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6180     FadeSkipNextFadeOut();
6181
6182   print_timestamp_time("[post-artwork]");
6183
6184   print_timestamp_done("OpenAll");
6185
6186   DrawMainMenu();
6187
6188 #if 0
6189   Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6190         SDL_GetBasePath());
6191   Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6192         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6193 #if defined(PLATFORM_ANDROID)
6194   Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6195         SDL_AndroidGetInternalStoragePath());
6196   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6197         SDL_AndroidGetExternalStoragePath());
6198   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6199         (SDL_AndroidGetExternalStorageState() &
6200          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
6201          SDL_AndroidGetExternalStorageState() &
6202          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "readable" : "not available"));
6203 #endif
6204 #endif
6205 }
6206
6207 void CloseAllAndExit(int exit_value)
6208 {
6209   StopSounds();
6210   FreeAllSounds();
6211   FreeAllMusic();
6212   CloseAudio();         // called after freeing sounds (needed for SDL)
6213
6214   em_close_all();
6215   sp_close_all();
6216
6217   FreeAllImages();
6218
6219   // !!! TODO !!!
6220   // set a flag to tell the network server thread to quit and wait for it
6221   // using SDL_WaitThread()
6222   //
6223   // Code used with SDL 1.2:
6224   // if (network_server)        // terminate network server
6225   //   SDL_KillThread(server_thread);
6226
6227   CloseVideoDisplay();
6228   ClosePlatformDependentStuff();
6229
6230   if (exit_value != 0 && !options.execute_command)
6231   {
6232     // fall back to default level set (current set may have caused an error)
6233     SaveLevelSetup_LastSeries_Deactivate();
6234
6235     // tell user where to find error log file which may contain more details
6236     // (error notification now directly displayed on screen inside R'n'D
6237     // NotifyUserAboutErrorFile();      // currently only works for Windows
6238   }
6239
6240   exit(exit_value);
6241 }