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