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