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