fixed bug with non-element images from dynamic configuration _not_ being scaled by...
[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 (src_x < 0 || src_y < 0 ||
1714         src_x + width  > src_bitmap_width ||
1715         src_y + height > src_bitmap_height)
1716     {
1717       Error(ERR_INFO_LINE, "-");
1718       Error(ERR_INFO, "warning: error found in config file:");
1719       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1720       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1721       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1722       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1723       Error(ERR_INFO,
1724             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1725             src_x, src_y, src_bitmap_width, src_bitmap_height);
1726       Error(ERR_INFO, "custom graphic rejected for this element/action");
1727
1728       if (i == fallback_graphic)
1729         Error(ERR_EXIT, "no fallback graphic available");
1730
1731       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1732       Error(ERR_INFO_LINE, "-");
1733
1734       graphic_info[i] = graphic_info[fallback_graphic];
1735     }
1736
1737     /* check if last animation frame is inside specified bitmap */
1738
1739     last_frame = graphic_info[i].anim_frames - 1;
1740     getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1741
1742     if (src_x < 0 || src_y < 0 ||
1743         src_x + width  > src_bitmap_width ||
1744         src_y + height > src_bitmap_height)
1745     {
1746       Error(ERR_INFO_LINE, "-");
1747       Error(ERR_INFO, "warning: error found in config file:");
1748       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1749       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1750       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1751       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1752       Error(ERR_INFO,
1753             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1754             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1755       Error(ERR_INFO, "custom graphic rejected for this element/action");
1756
1757       if (i == fallback_graphic)
1758         Error(ERR_EXIT, "no fallback graphic available");
1759
1760       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1761       Error(ERR_INFO_LINE, "-");
1762
1763       graphic_info[i] = graphic_info[fallback_graphic];
1764     }
1765   }
1766 }
1767
1768 static void InitGraphicCompatibilityInfo()
1769 {
1770   struct FileInfo *fi_global_door =
1771     getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1772   int num_images = getImageListSize();
1773   int i;
1774
1775   /* the following compatibility handling is needed for the following case:
1776      versions up to 3.3.0.0 used one large bitmap "global.door" for various
1777      graphics mainly used for door and panel graphics, like editor, tape and
1778      in-game buttons with hard-coded bitmap positions and button sizes; as
1779      these graphics now have individual definitions, redefining "global.door"
1780      to change all these graphics at once like before does not work anymore
1781      (because all those individual definitions still have their default values);
1782      to solve this, remap all those individual definitions that are not
1783      redefined to the new bitmap of "global.door" if it was redefined */
1784
1785   /* special compatibility handling if image "global.door" was redefined */
1786   if (fi_global_door->redefined)
1787   {
1788     for (i = 0; i < num_images; i++)
1789     {
1790       struct FileInfo *fi = getImageListEntryFromImageID(i);
1791
1792       /* process only those images that still use the default settings */
1793       if (!fi->redefined)
1794       {
1795         /* process all images which default to same image as "global.door" */
1796         if (strEqual(fi->default_filename, fi_global_door->default_filename))
1797         {
1798           // printf("::: special treatment needed for token '%s'\n", fi->token);
1799
1800           graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1801           graphic_info[i].bitmap  = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1802         }
1803       }
1804     }
1805   }
1806
1807   InitGraphicCompatibilityInfo_Doors();
1808 }
1809
1810 static void InitElementSoundInfo()
1811 {
1812   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1813   int num_property_mappings = getSoundListPropertyMappingSize();
1814   int i, j, act;
1815
1816   /* set values to -1 to identify later as "uninitialized" values */
1817   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1818     for (act = 0; act < NUM_ACTIONS; act++)
1819       element_info[i].sound[act] = -1;
1820
1821   /* initialize element/sound mapping from static configuration */
1822   for (i = 0; element_to_sound[i].element > -1; i++)
1823   {
1824     int element      = element_to_sound[i].element;
1825     int action       = element_to_sound[i].action;
1826     int sound        = element_to_sound[i].sound;
1827     boolean is_class = element_to_sound[i].is_class;
1828
1829     if (action < 0)
1830       action = ACTION_DEFAULT;
1831
1832     if (!is_class)
1833       element_info[element].sound[action] = sound;
1834     else
1835       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1836         if (strEqual(element_info[j].class_name,
1837                      element_info[element].class_name))
1838           element_info[j].sound[action] = sound;
1839   }
1840
1841   /* initialize element class/sound mapping from dynamic configuration */
1842   for (i = 0; i < num_property_mappings; i++)
1843   {
1844     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1845     int action        = property_mapping[i].ext1_index;
1846     int sound         = property_mapping[i].artwork_index;
1847
1848     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1849       continue;
1850
1851     if (action < 0)
1852       action = ACTION_DEFAULT;
1853
1854     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1855       if (strEqual(element_info[j].class_name,
1856                    element_info[element_class].class_name))
1857         element_info[j].sound[action] = sound;
1858   }
1859
1860   /* initialize element/sound mapping from dynamic configuration */
1861   for (i = 0; i < num_property_mappings; i++)
1862   {
1863     int element = property_mapping[i].base_index;
1864     int action  = property_mapping[i].ext1_index;
1865     int sound   = property_mapping[i].artwork_index;
1866
1867     if (element >= MAX_NUM_ELEMENTS)
1868       continue;
1869
1870     if (action < 0)
1871       action = ACTION_DEFAULT;
1872
1873     element_info[element].sound[action] = sound;
1874   }
1875
1876   /* now set all '-1' values to element specific default values */
1877   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1878   {
1879     for (act = 0; act < NUM_ACTIONS; act++)
1880     {
1881       /* generic default action sound (defined by "[default]" directive) */
1882       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1883
1884       /* look for special default action sound (classic game specific) */
1885       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1886         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1887       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1888         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1889       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1890         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1891
1892       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1893       /* !!! make this better !!! */
1894       if (i == EL_EMPTY_SPACE)
1895         default_action_sound = element_info[EL_DEFAULT].sound[act];
1896
1897       /* no sound for this specific action -- use default action sound */
1898       if (element_info[i].sound[act] == -1)
1899         element_info[i].sound[act] = default_action_sound;
1900     }
1901   }
1902
1903   /* copy sound settings to some elements that are only stored in level file
1904      in native R'n'D levels, but are used by game engine in native EM levels */
1905   for (i = 0; copy_properties[i][0] != -1; i++)
1906     for (j = 1; j <= 4; j++)
1907       for (act = 0; act < NUM_ACTIONS; act++)
1908         element_info[copy_properties[i][j]].sound[act] =
1909           element_info[copy_properties[i][0]].sound[act];
1910 }
1911
1912 static void InitGameModeSoundInfo()
1913 {
1914   int i;
1915
1916   /* set values to -1 to identify later as "uninitialized" values */
1917   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1918     menu.sound[i] = -1;
1919
1920   /* initialize gamemode/sound mapping from static configuration */
1921   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1922   {
1923     int gamemode = gamemode_to_sound[i].gamemode;
1924     int sound    = gamemode_to_sound[i].sound;
1925
1926     if (gamemode < 0)
1927       gamemode = GAME_MODE_DEFAULT;
1928
1929     menu.sound[gamemode] = sound;
1930   }
1931
1932   /* now set all '-1' values to levelset specific default values */
1933   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1934     if (menu.sound[i] == -1)
1935       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1936 }
1937
1938 static void set_sound_parameters(int sound, char **parameter_raw)
1939 {
1940   int parameter[NUM_SND_ARGS];
1941   int i;
1942
1943   /* get integer values from string parameters */
1944   for (i = 0; i < NUM_SND_ARGS; i++)
1945     parameter[i] =
1946       get_parameter_value(parameter_raw[i],
1947                           sound_config_suffix[i].token,
1948                           sound_config_suffix[i].type);
1949
1950   /* explicit loop mode setting in configuration overrides default value */
1951   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1952     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1953
1954   /* sound volume to change the original volume when loading the sound file */
1955   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1956
1957   /* sound priority to give certain sounds a higher or lower priority */
1958   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1959 }
1960
1961 static void InitSoundInfo()
1962 {
1963   int *sound_effect_properties;
1964   int num_sounds = getSoundListSize();
1965   int i, j;
1966
1967   checked_free(sound_info);
1968
1969   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1970   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1971
1972   /* initialize sound effect for all elements to "no sound" */
1973   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1974     for (j = 0; j < NUM_ACTIONS; j++)
1975       element_info[i].sound[j] = SND_UNDEFINED;
1976
1977   for (i = 0; i < num_sounds; i++)
1978   {
1979     struct FileInfo *sound = getSoundListEntry(i);
1980     int len_effect_text = strlen(sound->token);
1981
1982     sound_effect_properties[i] = ACTION_OTHER;
1983     sound_info[i].loop = FALSE;         /* default: play sound only once */
1984
1985     /* determine all loop sounds and identify certain sound classes */
1986
1987     for (j = 0; element_action_info[j].suffix; j++)
1988     {
1989       int len_action_text = strlen(element_action_info[j].suffix);
1990
1991       if (len_action_text < len_effect_text &&
1992           strEqual(&sound->token[len_effect_text - len_action_text],
1993                    element_action_info[j].suffix))
1994       {
1995         sound_effect_properties[i] = element_action_info[j].value;
1996         sound_info[i].loop = element_action_info[j].is_loop_sound;
1997
1998         break;
1999       }
2000     }
2001
2002     /* associate elements and some selected sound actions */
2003
2004     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2005     {
2006       if (element_info[j].class_name)
2007       {
2008         int len_class_text = strlen(element_info[j].class_name);
2009
2010         if (len_class_text + 1 < len_effect_text &&
2011             strncmp(sound->token,
2012                     element_info[j].class_name, len_class_text) == 0 &&
2013             sound->token[len_class_text] == '.')
2014         {
2015           int sound_action_value = sound_effect_properties[i];
2016
2017           element_info[j].sound[sound_action_value] = i;
2018         }
2019       }
2020     }
2021
2022     set_sound_parameters(i, sound->parameter);
2023   }
2024
2025   free(sound_effect_properties);
2026 }
2027
2028 static void InitGameModeMusicInfo()
2029 {
2030   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2031   int num_property_mappings = getMusicListPropertyMappingSize();
2032   int default_levelset_music = -1;
2033   int i;
2034
2035   /* set values to -1 to identify later as "uninitialized" values */
2036   for (i = 0; i < MAX_LEVELS; i++)
2037     levelset.music[i] = -1;
2038   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2039     menu.music[i] = -1;
2040
2041   /* initialize gamemode/music mapping from static configuration */
2042   for (i = 0; gamemode_to_music[i].music > -1; i++)
2043   {
2044     int gamemode = gamemode_to_music[i].gamemode;
2045     int music    = gamemode_to_music[i].music;
2046
2047     if (gamemode < 0)
2048       gamemode = GAME_MODE_DEFAULT;
2049
2050     menu.music[gamemode] = music;
2051   }
2052
2053   /* initialize gamemode/music mapping from dynamic configuration */
2054   for (i = 0; i < num_property_mappings; i++)
2055   {
2056     int prefix   = property_mapping[i].base_index;
2057     int gamemode = property_mapping[i].ext2_index;
2058     int level    = property_mapping[i].ext3_index;
2059     int music    = property_mapping[i].artwork_index;
2060
2061     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2062       continue;
2063
2064     if (gamemode < 0)
2065       gamemode = GAME_MODE_DEFAULT;
2066
2067     /* level specific music only allowed for in-game music */
2068     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2069       gamemode = GAME_MODE_PLAYING;
2070
2071     if (level == -1)
2072     {
2073       level = 0;
2074       default_levelset_music = music;
2075     }
2076
2077     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2078       levelset.music[level] = music;
2079     if (gamemode != GAME_MODE_PLAYING)
2080       menu.music[gamemode] = music;
2081   }
2082
2083   /* now set all '-1' values to menu specific default values */
2084   /* (undefined values of "levelset.music[]" might stay at "-1" to
2085      allow dynamic selection of music files from music directory!) */
2086   for (i = 0; i < MAX_LEVELS; i++)
2087     if (levelset.music[i] == -1)
2088       levelset.music[i] = default_levelset_music;
2089   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2090     if (menu.music[i] == -1)
2091       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2092 }
2093
2094 static void set_music_parameters(int music, char **parameter_raw)
2095 {
2096   int parameter[NUM_MUS_ARGS];
2097   int i;
2098
2099   /* get integer values from string parameters */
2100   for (i = 0; i < NUM_MUS_ARGS; i++)
2101     parameter[i] =
2102       get_parameter_value(parameter_raw[i],
2103                           music_config_suffix[i].token,
2104                           music_config_suffix[i].type);
2105
2106   /* explicit loop mode setting in configuration overrides default value */
2107   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2108     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2109 }
2110
2111 static void InitMusicInfo()
2112 {
2113   int num_music = getMusicListSize();
2114   int i, j;
2115
2116   checked_free(music_info);
2117
2118   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2119
2120   for (i = 0; i < num_music; i++)
2121   {
2122     struct FileInfo *music = getMusicListEntry(i);
2123     int len_music_text = strlen(music->token);
2124
2125     music_info[i].loop = TRUE;          /* default: play music in loop mode */
2126
2127     /* determine all loop music */
2128
2129     for (j = 0; music_prefix_info[j].prefix; j++)
2130     {
2131       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2132
2133       if (len_prefix_text < len_music_text &&
2134           strncmp(music->token,
2135                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2136       {
2137         music_info[i].loop = music_prefix_info[j].is_loop_music;
2138
2139         break;
2140       }
2141     }
2142
2143     set_music_parameters(i, music->parameter);
2144   }
2145 }
2146
2147 static void ReinitializeGraphics()
2148 {
2149   print_timestamp_init("ReinitializeGraphics");
2150
2151   InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2152
2153   InitGraphicInfo();                    /* graphic properties mapping */
2154   print_timestamp_time("InitGraphicInfo");
2155   InitElementGraphicInfo();             /* element game graphic mapping */
2156   print_timestamp_time("InitElementGraphicInfo");
2157   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
2158   print_timestamp_time("InitElementSpecialGraphicInfo");
2159
2160   InitElementSmallImages();             /* scale elements to all needed sizes */
2161   print_timestamp_time("InitElementSmallImages");
2162   InitScaledImages();                   /* scale all other images, if needed */
2163   print_timestamp_time("InitScaledImages");
2164   InitBitmapPointers();                 /* set standard size bitmap pointers */
2165   print_timestamp_time("InitBitmapPointers");
2166   InitFontGraphicInfo();                /* initialize text drawing functions */
2167   print_timestamp_time("InitFontGraphicInfo");
2168   InitGlobalAnimGraphicInfo();          /* initialize global animation config */
2169   print_timestamp_time("InitGlobalAnimGraphicInfo");
2170
2171   InitImageTextures();                  /* create textures for certain images */
2172   print_timestamp_time("InitImageTextures");
2173
2174   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
2175   print_timestamp_time("InitGraphicInfo_EM");
2176
2177   InitGraphicCompatibilityInfo();
2178   print_timestamp_time("InitGraphicCompatibilityInfo");
2179
2180   SetMainBackgroundImage(IMG_BACKGROUND);
2181   print_timestamp_time("SetMainBackgroundImage");
2182   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2183   print_timestamp_time("SetDoorBackgroundImage");
2184
2185   InitGadgets();
2186   print_timestamp_time("InitGadgets");
2187   InitDoors();
2188   print_timestamp_time("InitDoors");
2189
2190   print_timestamp_done("ReinitializeGraphics");
2191 }
2192
2193 static void ReinitializeSounds()
2194 {
2195   InitSoundInfo();              /* sound properties mapping */
2196   InitElementSoundInfo();       /* element game sound mapping */
2197   InitGameModeSoundInfo();      /* game mode sound mapping */
2198   InitGlobalAnimSoundInfo();    /* global animation sound settings */
2199
2200   InitPlayLevelSound();         /* internal game sound settings */
2201 }
2202
2203 static void ReinitializeMusic()
2204 {
2205   InitMusicInfo();              /* music properties mapping */
2206   InitGameModeMusicInfo();      /* game mode music mapping */
2207   InitGlobalAnimMusicInfo();    /* global animation music settings */
2208 }
2209
2210 static int get_special_property_bit(int element, int property_bit_nr)
2211 {
2212   struct PropertyBitInfo
2213   {
2214     int element;
2215     int bit_nr;
2216   };
2217
2218   static struct PropertyBitInfo pb_can_move_into_acid[] =
2219   {
2220     /* the player may be able fall into acid when gravity is activated */
2221     { EL_PLAYER_1,              0       },
2222     { EL_PLAYER_2,              0       },
2223     { EL_PLAYER_3,              0       },
2224     { EL_PLAYER_4,              0       },
2225     { EL_SP_MURPHY,             0       },
2226     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2227
2228     /* all elements that can move may be able to also move into acid */
2229     { EL_BUG,                   1       },
2230     { EL_BUG_LEFT,              1       },
2231     { EL_BUG_RIGHT,             1       },
2232     { EL_BUG_UP,                1       },
2233     { EL_BUG_DOWN,              1       },
2234     { EL_SPACESHIP,             2       },
2235     { EL_SPACESHIP_LEFT,        2       },
2236     { EL_SPACESHIP_RIGHT,       2       },
2237     { EL_SPACESHIP_UP,          2       },
2238     { EL_SPACESHIP_DOWN,        2       },
2239     { EL_BD_BUTTERFLY,          3       },
2240     { EL_BD_BUTTERFLY_LEFT,     3       },
2241     { EL_BD_BUTTERFLY_RIGHT,    3       },
2242     { EL_BD_BUTTERFLY_UP,       3       },
2243     { EL_BD_BUTTERFLY_DOWN,     3       },
2244     { EL_BD_FIREFLY,            4       },
2245     { EL_BD_FIREFLY_LEFT,       4       },
2246     { EL_BD_FIREFLY_RIGHT,      4       },
2247     { EL_BD_FIREFLY_UP,         4       },
2248     { EL_BD_FIREFLY_DOWN,       4       },
2249     { EL_YAMYAM,                5       },
2250     { EL_YAMYAM_LEFT,           5       },
2251     { EL_YAMYAM_RIGHT,          5       },
2252     { EL_YAMYAM_UP,             5       },
2253     { EL_YAMYAM_DOWN,           5       },
2254     { EL_DARK_YAMYAM,           6       },
2255     { EL_ROBOT,                 7       },
2256     { EL_PACMAN,                8       },
2257     { EL_PACMAN_LEFT,           8       },
2258     { EL_PACMAN_RIGHT,          8       },
2259     { EL_PACMAN_UP,             8       },
2260     { EL_PACMAN_DOWN,           8       },
2261     { EL_MOLE,                  9       },
2262     { EL_MOLE_LEFT,             9       },
2263     { EL_MOLE_RIGHT,            9       },
2264     { EL_MOLE_UP,               9       },
2265     { EL_MOLE_DOWN,             9       },
2266     { EL_PENGUIN,               10      },
2267     { EL_PIG,                   11      },
2268     { EL_DRAGON,                12      },
2269     { EL_SATELLITE,             13      },
2270     { EL_SP_SNIKSNAK,           14      },
2271     { EL_SP_ELECTRON,           15      },
2272     { EL_BALLOON,               16      },
2273     { EL_SPRING,                17      },
2274     { EL_EMC_ANDROID,           18      },
2275
2276     { -1,                       -1      },
2277   };
2278
2279   static struct PropertyBitInfo pb_dont_collide_with[] =
2280   {
2281     { EL_SP_SNIKSNAK,           0       },
2282     { EL_SP_ELECTRON,           1       },
2283
2284     { -1,                       -1      },
2285   };
2286
2287   static struct
2288   {
2289     int bit_nr;
2290     struct PropertyBitInfo *pb_info;
2291   } pb_definition[] =
2292   {
2293     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2294     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2295
2296     { -1,                       NULL                    },
2297   };
2298
2299   struct PropertyBitInfo *pb_info = NULL;
2300   int i;
2301
2302   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2303     if (pb_definition[i].bit_nr == property_bit_nr)
2304       pb_info = pb_definition[i].pb_info;
2305
2306   if (pb_info == NULL)
2307     return -1;
2308
2309   for (i = 0; pb_info[i].element != -1; i++)
2310     if (pb_info[i].element == element)
2311       return pb_info[i].bit_nr;
2312
2313   return -1;
2314 }
2315
2316 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2317                          boolean property_value)
2318 {
2319   int bit_nr = get_special_property_bit(element, property_bit_nr);
2320
2321   if (bit_nr > -1)
2322   {
2323     if (property_value)
2324       *bitfield |=  (1 << bit_nr);
2325     else
2326       *bitfield &= ~(1 << bit_nr);
2327   }
2328 }
2329
2330 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2331 {
2332   int bit_nr = get_special_property_bit(element, property_bit_nr);
2333
2334   if (bit_nr > -1)
2335     return ((*bitfield & (1 << bit_nr)) != 0);
2336
2337   return FALSE;
2338 }
2339
2340 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2341 {
2342   static int group_nr;
2343   static struct ElementGroupInfo *group;
2344   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2345   int i;
2346
2347   if (actual_group == NULL)                     /* not yet initialized */
2348     return;
2349
2350   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2351   {
2352     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2353           group_element - EL_GROUP_START + 1);
2354
2355     /* replace element which caused too deep recursion by question mark */
2356     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2357
2358     return;
2359   }
2360
2361   if (recursion_depth == 0)                     /* initialization */
2362   {
2363     group = actual_group;
2364     group_nr = GROUP_NR(group_element);
2365
2366     group->num_elements_resolved = 0;
2367     group->choice_pos = 0;
2368
2369     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2370       element_info[i].in_group[group_nr] = FALSE;
2371   }
2372
2373   for (i = 0; i < actual_group->num_elements; i++)
2374   {
2375     int element = actual_group->element[i];
2376
2377     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2378       break;
2379
2380     if (IS_GROUP_ELEMENT(element))
2381       ResolveGroupElementExt(element, recursion_depth + 1);
2382     else
2383     {
2384       group->element_resolved[group->num_elements_resolved++] = element;
2385       element_info[element].in_group[group_nr] = TRUE;
2386     }
2387   }
2388 }
2389
2390 void ResolveGroupElement(int group_element)
2391 {
2392   ResolveGroupElementExt(group_element, 0);
2393 }
2394
2395 void InitElementPropertiesStatic()
2396 {
2397   static boolean clipboard_elements_initialized = FALSE;
2398
2399   static int ep_diggable[] =
2400   {
2401     EL_SAND,
2402     EL_SP_BASE,
2403     EL_SP_BUGGY_BASE,
2404     EL_SP_BUGGY_BASE_ACTIVATING,
2405     EL_TRAP,
2406     EL_INVISIBLE_SAND,
2407     EL_INVISIBLE_SAND_ACTIVE,
2408     EL_EMC_GRASS,
2409
2410     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2411     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2412 #if 0
2413     EL_LANDMINE,
2414     EL_DC_LANDMINE,
2415     EL_TRAP_ACTIVE,
2416     EL_SP_BUGGY_BASE_ACTIVE,
2417     EL_EMC_PLANT,
2418 #endif
2419
2420     -1
2421   };
2422
2423   static int ep_collectible_only[] =
2424   {
2425     EL_BD_DIAMOND,
2426     EL_EMERALD,
2427     EL_DIAMOND,
2428     EL_EMERALD_YELLOW,
2429     EL_EMERALD_RED,
2430     EL_EMERALD_PURPLE,
2431     EL_KEY_1,
2432     EL_KEY_2,
2433     EL_KEY_3,
2434     EL_KEY_4,
2435     EL_EM_KEY_1,
2436     EL_EM_KEY_2,
2437     EL_EM_KEY_3,
2438     EL_EM_KEY_4,
2439     EL_EMC_KEY_5,
2440     EL_EMC_KEY_6,
2441     EL_EMC_KEY_7,
2442     EL_EMC_KEY_8,
2443     EL_DYNAMITE,
2444     EL_EM_DYNAMITE,
2445     EL_DYNABOMB_INCREASE_NUMBER,
2446     EL_DYNABOMB_INCREASE_SIZE,
2447     EL_DYNABOMB_INCREASE_POWER,
2448     EL_SP_INFOTRON,
2449     EL_SP_DISK_RED,
2450     EL_PEARL,
2451     EL_CRYSTAL,
2452     EL_DC_KEY_WHITE,
2453     EL_SHIELD_NORMAL,
2454     EL_SHIELD_DEADLY,
2455     EL_EXTRA_TIME,
2456     EL_ENVELOPE_1,
2457     EL_ENVELOPE_2,
2458     EL_ENVELOPE_3,
2459     EL_ENVELOPE_4,
2460     EL_SPEED_PILL,
2461     EL_EMC_LENSES,
2462     EL_EMC_MAGNIFIER,
2463
2464 #if 0
2465     /* !!! handle separately !!! */
2466     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2467 #endif
2468
2469     -1
2470   };
2471
2472   static int ep_dont_run_into[] =
2473   {
2474     /* same elements as in 'ep_dont_touch' */
2475     EL_BUG,
2476     EL_SPACESHIP,
2477     EL_BD_BUTTERFLY,
2478     EL_BD_FIREFLY,
2479
2480     /* same elements as in 'ep_dont_collide_with' */
2481     EL_YAMYAM,
2482     EL_DARK_YAMYAM,
2483     EL_ROBOT,
2484     EL_PACMAN,
2485     EL_SP_SNIKSNAK,
2486     EL_SP_ELECTRON,
2487
2488     /* new elements */
2489     EL_AMOEBA_DROP,
2490     EL_ACID,
2491
2492     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2493 #if 1
2494     EL_LANDMINE,
2495     EL_DC_LANDMINE,
2496     EL_TRAP_ACTIVE,
2497     EL_SP_BUGGY_BASE_ACTIVE,
2498     EL_EMC_PLANT,
2499 #endif
2500
2501     -1
2502   };
2503
2504   static int ep_dont_collide_with[] =
2505   {
2506     /* same elements as in 'ep_dont_touch' */
2507     EL_BUG,
2508     EL_SPACESHIP,
2509     EL_BD_BUTTERFLY,
2510     EL_BD_FIREFLY,
2511
2512     /* new elements */
2513     EL_YAMYAM,
2514     EL_DARK_YAMYAM,
2515     EL_ROBOT,
2516     EL_PACMAN,
2517     EL_SP_SNIKSNAK,
2518     EL_SP_ELECTRON,
2519
2520     -1
2521   };
2522
2523   static int ep_dont_touch[] =
2524   {
2525     EL_BUG,
2526     EL_SPACESHIP,
2527     EL_BD_BUTTERFLY,
2528     EL_BD_FIREFLY,
2529
2530     -1
2531   };
2532
2533   static int ep_indestructible[] =
2534   {
2535     EL_STEELWALL,
2536     EL_ACID,
2537     EL_ACID_POOL_TOPLEFT,
2538     EL_ACID_POOL_TOPRIGHT,
2539     EL_ACID_POOL_BOTTOMLEFT,
2540     EL_ACID_POOL_BOTTOM,
2541     EL_ACID_POOL_BOTTOMRIGHT,
2542     EL_SP_HARDWARE_GRAY,
2543     EL_SP_HARDWARE_GREEN,
2544     EL_SP_HARDWARE_BLUE,
2545     EL_SP_HARDWARE_RED,
2546     EL_SP_HARDWARE_YELLOW,
2547     EL_SP_HARDWARE_BASE_1,
2548     EL_SP_HARDWARE_BASE_2,
2549     EL_SP_HARDWARE_BASE_3,
2550     EL_SP_HARDWARE_BASE_4,
2551     EL_SP_HARDWARE_BASE_5,
2552     EL_SP_HARDWARE_BASE_6,
2553     EL_INVISIBLE_STEELWALL,
2554     EL_INVISIBLE_STEELWALL_ACTIVE,
2555     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2556     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2557     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2558     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2559     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2560     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2561     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2562     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2563     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2564     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2565     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2566     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2567     EL_LIGHT_SWITCH,
2568     EL_LIGHT_SWITCH_ACTIVE,
2569     EL_SIGN_EXCLAMATION,
2570     EL_SIGN_RADIOACTIVITY,
2571     EL_SIGN_STOP,
2572     EL_SIGN_WHEELCHAIR,
2573     EL_SIGN_PARKING,
2574     EL_SIGN_NO_ENTRY,
2575     EL_SIGN_UNUSED_1,
2576     EL_SIGN_GIVE_WAY,
2577     EL_SIGN_ENTRY_FORBIDDEN,
2578     EL_SIGN_EMERGENCY_EXIT,
2579     EL_SIGN_YIN_YANG,
2580     EL_SIGN_UNUSED_2,
2581     EL_SIGN_SPERMS,
2582     EL_SIGN_BULLET,
2583     EL_SIGN_HEART,
2584     EL_SIGN_CROSS,
2585     EL_SIGN_FRANKIE,
2586     EL_STEEL_EXIT_CLOSED,
2587     EL_STEEL_EXIT_OPEN,
2588     EL_STEEL_EXIT_OPENING,
2589     EL_STEEL_EXIT_CLOSING,
2590     EL_EM_STEEL_EXIT_CLOSED,
2591     EL_EM_STEEL_EXIT_OPEN,
2592     EL_EM_STEEL_EXIT_OPENING,
2593     EL_EM_STEEL_EXIT_CLOSING,
2594     EL_DC_STEELWALL_1_LEFT,
2595     EL_DC_STEELWALL_1_RIGHT,
2596     EL_DC_STEELWALL_1_TOP,
2597     EL_DC_STEELWALL_1_BOTTOM,
2598     EL_DC_STEELWALL_1_HORIZONTAL,
2599     EL_DC_STEELWALL_1_VERTICAL,
2600     EL_DC_STEELWALL_1_TOPLEFT,
2601     EL_DC_STEELWALL_1_TOPRIGHT,
2602     EL_DC_STEELWALL_1_BOTTOMLEFT,
2603     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2604     EL_DC_STEELWALL_1_TOPLEFT_2,
2605     EL_DC_STEELWALL_1_TOPRIGHT_2,
2606     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2607     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2608     EL_DC_STEELWALL_2_LEFT,
2609     EL_DC_STEELWALL_2_RIGHT,
2610     EL_DC_STEELWALL_2_TOP,
2611     EL_DC_STEELWALL_2_BOTTOM,
2612     EL_DC_STEELWALL_2_HORIZONTAL,
2613     EL_DC_STEELWALL_2_VERTICAL,
2614     EL_DC_STEELWALL_2_MIDDLE,
2615     EL_DC_STEELWALL_2_SINGLE,
2616     EL_STEELWALL_SLIPPERY,
2617     EL_EMC_STEELWALL_1,
2618     EL_EMC_STEELWALL_2,
2619     EL_EMC_STEELWALL_3,
2620     EL_EMC_STEELWALL_4,
2621     EL_CRYSTAL,
2622     EL_GATE_1,
2623     EL_GATE_2,
2624     EL_GATE_3,
2625     EL_GATE_4,
2626     EL_GATE_1_GRAY,
2627     EL_GATE_2_GRAY,
2628     EL_GATE_3_GRAY,
2629     EL_GATE_4_GRAY,
2630     EL_GATE_1_GRAY_ACTIVE,
2631     EL_GATE_2_GRAY_ACTIVE,
2632     EL_GATE_3_GRAY_ACTIVE,
2633     EL_GATE_4_GRAY_ACTIVE,
2634     EL_EM_GATE_1,
2635     EL_EM_GATE_2,
2636     EL_EM_GATE_3,
2637     EL_EM_GATE_4,
2638     EL_EM_GATE_1_GRAY,
2639     EL_EM_GATE_2_GRAY,
2640     EL_EM_GATE_3_GRAY,
2641     EL_EM_GATE_4_GRAY,
2642     EL_EM_GATE_1_GRAY_ACTIVE,
2643     EL_EM_GATE_2_GRAY_ACTIVE,
2644     EL_EM_GATE_3_GRAY_ACTIVE,
2645     EL_EM_GATE_4_GRAY_ACTIVE,
2646     EL_EMC_GATE_5,
2647     EL_EMC_GATE_6,
2648     EL_EMC_GATE_7,
2649     EL_EMC_GATE_8,
2650     EL_EMC_GATE_5_GRAY,
2651     EL_EMC_GATE_6_GRAY,
2652     EL_EMC_GATE_7_GRAY,
2653     EL_EMC_GATE_8_GRAY,
2654     EL_EMC_GATE_5_GRAY_ACTIVE,
2655     EL_EMC_GATE_6_GRAY_ACTIVE,
2656     EL_EMC_GATE_7_GRAY_ACTIVE,
2657     EL_EMC_GATE_8_GRAY_ACTIVE,
2658     EL_DC_GATE_WHITE,
2659     EL_DC_GATE_WHITE_GRAY,
2660     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2661     EL_DC_GATE_FAKE_GRAY,
2662     EL_SWITCHGATE_OPEN,
2663     EL_SWITCHGATE_OPENING,
2664     EL_SWITCHGATE_CLOSED,
2665     EL_SWITCHGATE_CLOSING,
2666     EL_DC_SWITCHGATE_SWITCH_UP,
2667     EL_DC_SWITCHGATE_SWITCH_DOWN,
2668     EL_TIMEGATE_OPEN,
2669     EL_TIMEGATE_OPENING,
2670     EL_TIMEGATE_CLOSED,
2671     EL_TIMEGATE_CLOSING,
2672     EL_DC_TIMEGATE_SWITCH,
2673     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2674     EL_TUBE_ANY,
2675     EL_TUBE_VERTICAL,
2676     EL_TUBE_HORIZONTAL,
2677     EL_TUBE_VERTICAL_LEFT,
2678     EL_TUBE_VERTICAL_RIGHT,
2679     EL_TUBE_HORIZONTAL_UP,
2680     EL_TUBE_HORIZONTAL_DOWN,
2681     EL_TUBE_LEFT_UP,
2682     EL_TUBE_LEFT_DOWN,
2683     EL_TUBE_RIGHT_UP,
2684     EL_TUBE_RIGHT_DOWN,
2685     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2686     EL_EXPANDABLE_STEELWALL_VERTICAL,
2687     EL_EXPANDABLE_STEELWALL_ANY,
2688
2689     -1
2690   };
2691
2692   static int ep_slippery[] =
2693   {
2694     EL_WALL_SLIPPERY,
2695     EL_BD_WALL,
2696     EL_ROCK,
2697     EL_BD_ROCK,
2698     EL_EMERALD,
2699     EL_BD_DIAMOND,
2700     EL_EMERALD_YELLOW,
2701     EL_EMERALD_RED,
2702     EL_EMERALD_PURPLE,
2703     EL_DIAMOND,
2704     EL_BOMB,
2705     EL_NUT,
2706     EL_ROBOT_WHEEL_ACTIVE,
2707     EL_ROBOT_WHEEL,
2708     EL_TIME_ORB_FULL,
2709     EL_TIME_ORB_EMPTY,
2710     EL_LAMP_ACTIVE,
2711     EL_LAMP,
2712     EL_ACID_POOL_TOPLEFT,
2713     EL_ACID_POOL_TOPRIGHT,
2714     EL_SATELLITE,
2715     EL_SP_ZONK,
2716     EL_SP_INFOTRON,
2717     EL_SP_CHIP_SINGLE,
2718     EL_SP_CHIP_LEFT,
2719     EL_SP_CHIP_RIGHT,
2720     EL_SP_CHIP_TOP,
2721     EL_SP_CHIP_BOTTOM,
2722     EL_SPEED_PILL,
2723     EL_STEELWALL_SLIPPERY,
2724     EL_PEARL,
2725     EL_CRYSTAL,
2726     EL_EMC_WALL_SLIPPERY_1,
2727     EL_EMC_WALL_SLIPPERY_2,
2728     EL_EMC_WALL_SLIPPERY_3,
2729     EL_EMC_WALL_SLIPPERY_4,
2730     EL_EMC_MAGIC_BALL,
2731     EL_EMC_MAGIC_BALL_ACTIVE,
2732
2733     -1
2734   };
2735
2736   static int ep_can_change[] =
2737   {
2738     -1
2739   };
2740
2741   static int ep_can_move[] =
2742   {
2743     /* same elements as in 'pb_can_move_into_acid' */
2744     EL_BUG,
2745     EL_SPACESHIP,
2746     EL_BD_BUTTERFLY,
2747     EL_BD_FIREFLY,
2748     EL_YAMYAM,
2749     EL_DARK_YAMYAM,
2750     EL_ROBOT,
2751     EL_PACMAN,
2752     EL_MOLE,
2753     EL_PENGUIN,
2754     EL_PIG,
2755     EL_DRAGON,
2756     EL_SATELLITE,
2757     EL_SP_SNIKSNAK,
2758     EL_SP_ELECTRON,
2759     EL_BALLOON,
2760     EL_SPRING,
2761     EL_EMC_ANDROID,
2762
2763     -1
2764   };
2765
2766   static int ep_can_fall[] =
2767   {
2768     EL_ROCK,
2769     EL_BD_ROCK,
2770     EL_EMERALD,
2771     EL_BD_DIAMOND,
2772     EL_EMERALD_YELLOW,
2773     EL_EMERALD_RED,
2774     EL_EMERALD_PURPLE,
2775     EL_DIAMOND,
2776     EL_BOMB,
2777     EL_NUT,
2778     EL_AMOEBA_DROP,
2779     EL_QUICKSAND_FULL,
2780     EL_QUICKSAND_FAST_FULL,
2781     EL_MAGIC_WALL_FULL,
2782     EL_BD_MAGIC_WALL_FULL,
2783     EL_DC_MAGIC_WALL_FULL,
2784     EL_TIME_ORB_FULL,
2785     EL_TIME_ORB_EMPTY,
2786     EL_SP_ZONK,
2787     EL_SP_INFOTRON,
2788     EL_SP_DISK_ORANGE,
2789     EL_PEARL,
2790     EL_CRYSTAL,
2791     EL_SPRING,
2792     EL_DX_SUPABOMB,
2793
2794     -1
2795   };
2796
2797   static int ep_can_smash_player[] =
2798   {
2799     EL_ROCK,
2800     EL_BD_ROCK,
2801     EL_EMERALD,
2802     EL_BD_DIAMOND,
2803     EL_EMERALD_YELLOW,
2804     EL_EMERALD_RED,
2805     EL_EMERALD_PURPLE,
2806     EL_DIAMOND,
2807     EL_BOMB,
2808     EL_NUT,
2809     EL_AMOEBA_DROP,
2810     EL_TIME_ORB_FULL,
2811     EL_TIME_ORB_EMPTY,
2812     EL_SP_ZONK,
2813     EL_SP_INFOTRON,
2814     EL_SP_DISK_ORANGE,
2815     EL_PEARL,
2816     EL_CRYSTAL,
2817     EL_SPRING,
2818     EL_DX_SUPABOMB,
2819
2820     -1
2821   };
2822
2823   static int ep_can_smash_enemies[] =
2824   {
2825     EL_ROCK,
2826     EL_BD_ROCK,
2827     EL_SP_ZONK,
2828
2829     -1
2830   };
2831
2832   static int ep_can_smash_everything[] =
2833   {
2834     EL_ROCK,
2835     EL_BD_ROCK,
2836     EL_SP_ZONK,
2837
2838     -1
2839   };
2840
2841   static int ep_explodes_by_fire[] =
2842   {
2843     /* same elements as in 'ep_explodes_impact' */
2844     EL_BOMB,
2845     EL_SP_DISK_ORANGE,
2846     EL_DX_SUPABOMB,
2847
2848     /* same elements as in 'ep_explodes_smashed' */
2849     EL_SATELLITE,
2850     EL_PIG,
2851     EL_DRAGON,
2852     EL_MOLE,
2853
2854     /* new elements */
2855     EL_DYNAMITE,
2856     EL_DYNAMITE_ACTIVE,
2857     EL_EM_DYNAMITE,
2858     EL_EM_DYNAMITE_ACTIVE,
2859     EL_DYNABOMB_PLAYER_1_ACTIVE,
2860     EL_DYNABOMB_PLAYER_2_ACTIVE,
2861     EL_DYNABOMB_PLAYER_3_ACTIVE,
2862     EL_DYNABOMB_PLAYER_4_ACTIVE,
2863     EL_DYNABOMB_INCREASE_NUMBER,
2864     EL_DYNABOMB_INCREASE_SIZE,
2865     EL_DYNABOMB_INCREASE_POWER,
2866     EL_SP_DISK_RED_ACTIVE,
2867     EL_BUG,
2868     EL_PENGUIN,
2869     EL_SP_DISK_RED,
2870     EL_SP_DISK_YELLOW,
2871     EL_SP_SNIKSNAK,
2872     EL_SP_ELECTRON,
2873 #if 0
2874     EL_BLACK_ORB,
2875 #endif
2876
2877     -1
2878   };
2879
2880   static int ep_explodes_smashed[] =
2881   {
2882     /* same elements as in 'ep_explodes_impact' */
2883     EL_BOMB,
2884     EL_SP_DISK_ORANGE,
2885     EL_DX_SUPABOMB,
2886
2887     /* new elements */
2888     EL_SATELLITE,
2889     EL_PIG,
2890     EL_DRAGON,
2891     EL_MOLE,
2892
2893     -1
2894   };
2895
2896   static int ep_explodes_impact[] =
2897   {
2898     EL_BOMB,
2899     EL_SP_DISK_ORANGE,
2900     EL_DX_SUPABOMB,
2901
2902     -1
2903   };
2904
2905   static int ep_walkable_over[] =
2906   {
2907     EL_EMPTY_SPACE,
2908     EL_SP_EMPTY_SPACE,
2909     EL_SOKOBAN_FIELD_EMPTY,
2910     EL_EXIT_OPEN,
2911     EL_EM_EXIT_OPEN,
2912     EL_EM_EXIT_OPENING,
2913     EL_SP_EXIT_OPEN,
2914     EL_SP_EXIT_OPENING,
2915     EL_STEEL_EXIT_OPEN,
2916     EL_EM_STEEL_EXIT_OPEN,
2917     EL_EM_STEEL_EXIT_OPENING,
2918     EL_GATE_1,
2919     EL_GATE_2,
2920     EL_GATE_3,
2921     EL_GATE_4,
2922     EL_GATE_1_GRAY,
2923     EL_GATE_2_GRAY,
2924     EL_GATE_3_GRAY,
2925     EL_GATE_4_GRAY,
2926     EL_GATE_1_GRAY_ACTIVE,
2927     EL_GATE_2_GRAY_ACTIVE,
2928     EL_GATE_3_GRAY_ACTIVE,
2929     EL_GATE_4_GRAY_ACTIVE,
2930     EL_PENGUIN,
2931     EL_PIG,
2932     EL_DRAGON,
2933
2934     -1
2935   };
2936
2937   static int ep_walkable_inside[] =
2938   {
2939     EL_TUBE_ANY,
2940     EL_TUBE_VERTICAL,
2941     EL_TUBE_HORIZONTAL,
2942     EL_TUBE_VERTICAL_LEFT,
2943     EL_TUBE_VERTICAL_RIGHT,
2944     EL_TUBE_HORIZONTAL_UP,
2945     EL_TUBE_HORIZONTAL_DOWN,
2946     EL_TUBE_LEFT_UP,
2947     EL_TUBE_LEFT_DOWN,
2948     EL_TUBE_RIGHT_UP,
2949     EL_TUBE_RIGHT_DOWN,
2950
2951     -1
2952   };
2953
2954   static int ep_walkable_under[] =
2955   {
2956     -1
2957   };
2958
2959   static int ep_passable_over[] =
2960   {
2961     EL_EM_GATE_1,
2962     EL_EM_GATE_2,
2963     EL_EM_GATE_3,
2964     EL_EM_GATE_4,
2965     EL_EM_GATE_1_GRAY,
2966     EL_EM_GATE_2_GRAY,
2967     EL_EM_GATE_3_GRAY,
2968     EL_EM_GATE_4_GRAY,
2969     EL_EM_GATE_1_GRAY_ACTIVE,
2970     EL_EM_GATE_2_GRAY_ACTIVE,
2971     EL_EM_GATE_3_GRAY_ACTIVE,
2972     EL_EM_GATE_4_GRAY_ACTIVE,
2973     EL_EMC_GATE_5,
2974     EL_EMC_GATE_6,
2975     EL_EMC_GATE_7,
2976     EL_EMC_GATE_8,
2977     EL_EMC_GATE_5_GRAY,
2978     EL_EMC_GATE_6_GRAY,
2979     EL_EMC_GATE_7_GRAY,
2980     EL_EMC_GATE_8_GRAY,
2981     EL_EMC_GATE_5_GRAY_ACTIVE,
2982     EL_EMC_GATE_6_GRAY_ACTIVE,
2983     EL_EMC_GATE_7_GRAY_ACTIVE,
2984     EL_EMC_GATE_8_GRAY_ACTIVE,
2985     EL_DC_GATE_WHITE,
2986     EL_DC_GATE_WHITE_GRAY,
2987     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2988     EL_SWITCHGATE_OPEN,
2989     EL_TIMEGATE_OPEN,
2990
2991     -1
2992   };
2993
2994   static int ep_passable_inside[] =
2995   {
2996     EL_SP_PORT_LEFT,
2997     EL_SP_PORT_RIGHT,
2998     EL_SP_PORT_UP,
2999     EL_SP_PORT_DOWN,
3000     EL_SP_PORT_HORIZONTAL,
3001     EL_SP_PORT_VERTICAL,
3002     EL_SP_PORT_ANY,
3003     EL_SP_GRAVITY_PORT_LEFT,
3004     EL_SP_GRAVITY_PORT_RIGHT,
3005     EL_SP_GRAVITY_PORT_UP,
3006     EL_SP_GRAVITY_PORT_DOWN,
3007     EL_SP_GRAVITY_ON_PORT_LEFT,
3008     EL_SP_GRAVITY_ON_PORT_RIGHT,
3009     EL_SP_GRAVITY_ON_PORT_UP,
3010     EL_SP_GRAVITY_ON_PORT_DOWN,
3011     EL_SP_GRAVITY_OFF_PORT_LEFT,
3012     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3013     EL_SP_GRAVITY_OFF_PORT_UP,
3014     EL_SP_GRAVITY_OFF_PORT_DOWN,
3015
3016     -1
3017   };
3018
3019   static int ep_passable_under[] =
3020   {
3021     -1
3022   };
3023
3024   static int ep_droppable[] =
3025   {
3026     -1
3027   };
3028
3029   static int ep_explodes_1x1_old[] =
3030   {
3031     -1
3032   };
3033
3034   static int ep_pushable[] =
3035   {
3036     EL_ROCK,
3037     EL_BOMB,
3038     EL_DX_SUPABOMB,
3039     EL_NUT,
3040     EL_TIME_ORB_EMPTY,
3041     EL_SP_ZONK,
3042     EL_SP_DISK_ORANGE,
3043     EL_SPRING,
3044     EL_BD_ROCK,
3045     EL_SOKOBAN_OBJECT,
3046     EL_SOKOBAN_FIELD_FULL,
3047     EL_SATELLITE,
3048     EL_SP_DISK_YELLOW,
3049     EL_BALLOON,
3050     EL_EMC_ANDROID,
3051
3052     -1
3053   };
3054
3055   static int ep_explodes_cross_old[] =
3056   {
3057     -1
3058   };
3059
3060   static int ep_protected[] =
3061   {
3062     /* same elements as in 'ep_walkable_inside' */
3063     EL_TUBE_ANY,
3064     EL_TUBE_VERTICAL,
3065     EL_TUBE_HORIZONTAL,
3066     EL_TUBE_VERTICAL_LEFT,
3067     EL_TUBE_VERTICAL_RIGHT,
3068     EL_TUBE_HORIZONTAL_UP,
3069     EL_TUBE_HORIZONTAL_DOWN,
3070     EL_TUBE_LEFT_UP,
3071     EL_TUBE_LEFT_DOWN,
3072     EL_TUBE_RIGHT_UP,
3073     EL_TUBE_RIGHT_DOWN,
3074
3075     /* same elements as in 'ep_passable_over' */
3076     EL_EM_GATE_1,
3077     EL_EM_GATE_2,
3078     EL_EM_GATE_3,
3079     EL_EM_GATE_4,
3080     EL_EM_GATE_1_GRAY,
3081     EL_EM_GATE_2_GRAY,
3082     EL_EM_GATE_3_GRAY,
3083     EL_EM_GATE_4_GRAY,
3084     EL_EM_GATE_1_GRAY_ACTIVE,
3085     EL_EM_GATE_2_GRAY_ACTIVE,
3086     EL_EM_GATE_3_GRAY_ACTIVE,
3087     EL_EM_GATE_4_GRAY_ACTIVE,
3088     EL_EMC_GATE_5,
3089     EL_EMC_GATE_6,
3090     EL_EMC_GATE_7,
3091     EL_EMC_GATE_8,
3092     EL_EMC_GATE_5_GRAY,
3093     EL_EMC_GATE_6_GRAY,
3094     EL_EMC_GATE_7_GRAY,
3095     EL_EMC_GATE_8_GRAY,
3096     EL_EMC_GATE_5_GRAY_ACTIVE,
3097     EL_EMC_GATE_6_GRAY_ACTIVE,
3098     EL_EMC_GATE_7_GRAY_ACTIVE,
3099     EL_EMC_GATE_8_GRAY_ACTIVE,
3100     EL_DC_GATE_WHITE,
3101     EL_DC_GATE_WHITE_GRAY,
3102     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3103     EL_SWITCHGATE_OPEN,
3104     EL_TIMEGATE_OPEN,
3105
3106     /* same elements as in 'ep_passable_inside' */
3107     EL_SP_PORT_LEFT,
3108     EL_SP_PORT_RIGHT,
3109     EL_SP_PORT_UP,
3110     EL_SP_PORT_DOWN,
3111     EL_SP_PORT_HORIZONTAL,
3112     EL_SP_PORT_VERTICAL,
3113     EL_SP_PORT_ANY,
3114     EL_SP_GRAVITY_PORT_LEFT,
3115     EL_SP_GRAVITY_PORT_RIGHT,
3116     EL_SP_GRAVITY_PORT_UP,
3117     EL_SP_GRAVITY_PORT_DOWN,
3118     EL_SP_GRAVITY_ON_PORT_LEFT,
3119     EL_SP_GRAVITY_ON_PORT_RIGHT,
3120     EL_SP_GRAVITY_ON_PORT_UP,
3121     EL_SP_GRAVITY_ON_PORT_DOWN,
3122     EL_SP_GRAVITY_OFF_PORT_LEFT,
3123     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3124     EL_SP_GRAVITY_OFF_PORT_UP,
3125     EL_SP_GRAVITY_OFF_PORT_DOWN,
3126
3127     -1
3128   };
3129
3130   static int ep_throwable[] =
3131   {
3132     -1
3133   };
3134
3135   static int ep_can_explode[] =
3136   {
3137     /* same elements as in 'ep_explodes_impact' */
3138     EL_BOMB,
3139     EL_SP_DISK_ORANGE,
3140     EL_DX_SUPABOMB,
3141
3142     /* same elements as in 'ep_explodes_smashed' */
3143     EL_SATELLITE,
3144     EL_PIG,
3145     EL_DRAGON,
3146     EL_MOLE,
3147
3148     /* elements that can explode by explosion or by dragonfire */
3149     EL_DYNAMITE,
3150     EL_DYNAMITE_ACTIVE,
3151     EL_EM_DYNAMITE,
3152     EL_EM_DYNAMITE_ACTIVE,
3153     EL_DYNABOMB_PLAYER_1_ACTIVE,
3154     EL_DYNABOMB_PLAYER_2_ACTIVE,
3155     EL_DYNABOMB_PLAYER_3_ACTIVE,
3156     EL_DYNABOMB_PLAYER_4_ACTIVE,
3157     EL_DYNABOMB_INCREASE_NUMBER,
3158     EL_DYNABOMB_INCREASE_SIZE,
3159     EL_DYNABOMB_INCREASE_POWER,
3160     EL_SP_DISK_RED_ACTIVE,
3161     EL_BUG,
3162     EL_PENGUIN,
3163     EL_SP_DISK_RED,
3164     EL_SP_DISK_YELLOW,
3165     EL_SP_SNIKSNAK,
3166     EL_SP_ELECTRON,
3167
3168     /* elements that can explode only by explosion */
3169     EL_BLACK_ORB,
3170
3171     -1
3172   };
3173
3174   static int ep_gravity_reachable[] =
3175   {
3176     EL_SAND,
3177     EL_SP_BASE,
3178     EL_TRAP,
3179     EL_INVISIBLE_SAND,
3180     EL_INVISIBLE_SAND_ACTIVE,
3181     EL_SP_PORT_LEFT,
3182     EL_SP_PORT_RIGHT,
3183     EL_SP_PORT_UP,
3184     EL_SP_PORT_DOWN,
3185     EL_SP_PORT_HORIZONTAL,
3186     EL_SP_PORT_VERTICAL,
3187     EL_SP_PORT_ANY,
3188     EL_SP_GRAVITY_PORT_LEFT,
3189     EL_SP_GRAVITY_PORT_RIGHT,
3190     EL_SP_GRAVITY_PORT_UP,
3191     EL_SP_GRAVITY_PORT_DOWN,
3192     EL_SP_GRAVITY_ON_PORT_LEFT,
3193     EL_SP_GRAVITY_ON_PORT_RIGHT,
3194     EL_SP_GRAVITY_ON_PORT_UP,
3195     EL_SP_GRAVITY_ON_PORT_DOWN,
3196     EL_SP_GRAVITY_OFF_PORT_LEFT,
3197     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3198     EL_SP_GRAVITY_OFF_PORT_UP,
3199     EL_SP_GRAVITY_OFF_PORT_DOWN,
3200     EL_EMC_GRASS,
3201
3202     -1
3203   };
3204
3205   static int ep_player[] =
3206   {
3207     EL_PLAYER_1,
3208     EL_PLAYER_2,
3209     EL_PLAYER_3,
3210     EL_PLAYER_4,
3211     EL_SP_MURPHY,
3212     EL_SOKOBAN_FIELD_PLAYER,
3213     EL_TRIGGER_PLAYER,
3214
3215     -1
3216   };
3217
3218   static int ep_can_pass_magic_wall[] =
3219   {
3220     EL_ROCK,
3221     EL_BD_ROCK,
3222     EL_EMERALD,
3223     EL_BD_DIAMOND,
3224     EL_EMERALD_YELLOW,
3225     EL_EMERALD_RED,
3226     EL_EMERALD_PURPLE,
3227     EL_DIAMOND,
3228
3229     -1
3230   };
3231
3232   static int ep_can_pass_dc_magic_wall[] =
3233   {
3234     EL_ROCK,
3235     EL_BD_ROCK,
3236     EL_EMERALD,
3237     EL_BD_DIAMOND,
3238     EL_EMERALD_YELLOW,
3239     EL_EMERALD_RED,
3240     EL_EMERALD_PURPLE,
3241     EL_DIAMOND,
3242     EL_PEARL,
3243     EL_CRYSTAL,
3244
3245     -1
3246   };
3247
3248   static int ep_switchable[] =
3249   {
3250     EL_ROBOT_WHEEL,
3251     EL_SP_TERMINAL,
3252     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3253     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3254     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3255     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3256     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3257     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3258     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3259     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3260     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3261     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3262     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3263     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3264     EL_SWITCHGATE_SWITCH_UP,
3265     EL_SWITCHGATE_SWITCH_DOWN,
3266     EL_DC_SWITCHGATE_SWITCH_UP,
3267     EL_DC_SWITCHGATE_SWITCH_DOWN,
3268     EL_LIGHT_SWITCH,
3269     EL_LIGHT_SWITCH_ACTIVE,
3270     EL_TIMEGATE_SWITCH,
3271     EL_DC_TIMEGATE_SWITCH,
3272     EL_BALLOON_SWITCH_LEFT,
3273     EL_BALLOON_SWITCH_RIGHT,
3274     EL_BALLOON_SWITCH_UP,
3275     EL_BALLOON_SWITCH_DOWN,
3276     EL_BALLOON_SWITCH_ANY,
3277     EL_BALLOON_SWITCH_NONE,
3278     EL_LAMP,
3279     EL_TIME_ORB_FULL,
3280     EL_EMC_MAGIC_BALL_SWITCH,
3281     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3282
3283     -1
3284   };
3285
3286   static int ep_bd_element[] =
3287   {
3288     EL_EMPTY,
3289     EL_SAND,
3290     EL_WALL_SLIPPERY,
3291     EL_BD_WALL,
3292     EL_ROCK,
3293     EL_BD_ROCK,
3294     EL_BD_DIAMOND,
3295     EL_BD_MAGIC_WALL,
3296     EL_EXIT_CLOSED,
3297     EL_EXIT_OPEN,
3298     EL_STEELWALL,
3299     EL_PLAYER_1,
3300     EL_PLAYER_2,
3301     EL_PLAYER_3,
3302     EL_PLAYER_4,
3303     EL_BD_FIREFLY,
3304     EL_BD_FIREFLY_1,
3305     EL_BD_FIREFLY_2,
3306     EL_BD_FIREFLY_3,
3307     EL_BD_FIREFLY_4,
3308     EL_BD_BUTTERFLY,
3309     EL_BD_BUTTERFLY_1,
3310     EL_BD_BUTTERFLY_2,
3311     EL_BD_BUTTERFLY_3,
3312     EL_BD_BUTTERFLY_4,
3313     EL_BD_AMOEBA,
3314     EL_CHAR_QUESTION,
3315     EL_UNKNOWN,
3316
3317     -1
3318   };
3319
3320   static int ep_sp_element[] =
3321   {
3322     /* should always be valid */
3323     EL_EMPTY,
3324
3325     /* standard classic Supaplex elements */
3326     EL_SP_EMPTY,
3327     EL_SP_ZONK,
3328     EL_SP_BASE,
3329     EL_SP_MURPHY,
3330     EL_SP_INFOTRON,
3331     EL_SP_CHIP_SINGLE,
3332     EL_SP_HARDWARE_GRAY,
3333     EL_SP_EXIT_CLOSED,
3334     EL_SP_EXIT_OPEN,
3335     EL_SP_DISK_ORANGE,
3336     EL_SP_PORT_RIGHT,
3337     EL_SP_PORT_DOWN,
3338     EL_SP_PORT_LEFT,
3339     EL_SP_PORT_UP,
3340     EL_SP_GRAVITY_PORT_RIGHT,
3341     EL_SP_GRAVITY_PORT_DOWN,
3342     EL_SP_GRAVITY_PORT_LEFT,
3343     EL_SP_GRAVITY_PORT_UP,
3344     EL_SP_SNIKSNAK,
3345     EL_SP_DISK_YELLOW,
3346     EL_SP_TERMINAL,
3347     EL_SP_DISK_RED,
3348     EL_SP_PORT_VERTICAL,
3349     EL_SP_PORT_HORIZONTAL,
3350     EL_SP_PORT_ANY,
3351     EL_SP_ELECTRON,
3352     EL_SP_BUGGY_BASE,
3353     EL_SP_CHIP_LEFT,
3354     EL_SP_CHIP_RIGHT,
3355     EL_SP_HARDWARE_BASE_1,
3356     EL_SP_HARDWARE_GREEN,
3357     EL_SP_HARDWARE_BLUE,
3358     EL_SP_HARDWARE_RED,
3359     EL_SP_HARDWARE_YELLOW,
3360     EL_SP_HARDWARE_BASE_2,
3361     EL_SP_HARDWARE_BASE_3,
3362     EL_SP_HARDWARE_BASE_4,
3363     EL_SP_HARDWARE_BASE_5,
3364     EL_SP_HARDWARE_BASE_6,
3365     EL_SP_CHIP_TOP,
3366     EL_SP_CHIP_BOTTOM,
3367
3368     /* additional elements that appeared in newer Supaplex levels */
3369     EL_INVISIBLE_WALL,
3370
3371     /* additional gravity port elements (not switching, but setting gravity) */
3372     EL_SP_GRAVITY_ON_PORT_LEFT,
3373     EL_SP_GRAVITY_ON_PORT_RIGHT,
3374     EL_SP_GRAVITY_ON_PORT_UP,
3375     EL_SP_GRAVITY_ON_PORT_DOWN,
3376     EL_SP_GRAVITY_OFF_PORT_LEFT,
3377     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3378     EL_SP_GRAVITY_OFF_PORT_UP,
3379     EL_SP_GRAVITY_OFF_PORT_DOWN,
3380
3381     /* more than one Murphy in a level results in an inactive clone */
3382     EL_SP_MURPHY_CLONE,
3383
3384     /* runtime Supaplex elements */
3385     EL_SP_DISK_RED_ACTIVE,
3386     EL_SP_TERMINAL_ACTIVE,
3387     EL_SP_BUGGY_BASE_ACTIVATING,
3388     EL_SP_BUGGY_BASE_ACTIVE,
3389     EL_SP_EXIT_OPENING,
3390     EL_SP_EXIT_CLOSING,
3391
3392     -1
3393   };
3394
3395   static int ep_sb_element[] =
3396   {
3397     EL_EMPTY,
3398     EL_STEELWALL,
3399     EL_SOKOBAN_OBJECT,
3400     EL_SOKOBAN_FIELD_EMPTY,
3401     EL_SOKOBAN_FIELD_FULL,
3402     EL_SOKOBAN_FIELD_PLAYER,
3403     EL_PLAYER_1,
3404     EL_PLAYER_2,
3405     EL_PLAYER_3,
3406     EL_PLAYER_4,
3407     EL_INVISIBLE_STEELWALL,
3408
3409     -1
3410   };
3411
3412   static int ep_gem[] =
3413   {
3414     EL_BD_DIAMOND,
3415     EL_EMERALD,
3416     EL_EMERALD_YELLOW,
3417     EL_EMERALD_RED,
3418     EL_EMERALD_PURPLE,
3419     EL_DIAMOND,
3420
3421     -1
3422   };
3423
3424   static int ep_food_dark_yamyam[] =
3425   {
3426     EL_SAND,
3427     EL_BUG,
3428     EL_SPACESHIP,
3429     EL_BD_BUTTERFLY,
3430     EL_BD_FIREFLY,
3431     EL_YAMYAM,
3432     EL_ROBOT,
3433     EL_PACMAN,
3434     EL_AMOEBA_DROP,
3435     EL_AMOEBA_DEAD,
3436     EL_AMOEBA_WET,
3437     EL_AMOEBA_DRY,
3438     EL_AMOEBA_FULL,
3439     EL_BD_AMOEBA,
3440     EL_EMERALD,
3441     EL_BD_DIAMOND,
3442     EL_EMERALD_YELLOW,
3443     EL_EMERALD_RED,
3444     EL_EMERALD_PURPLE,
3445     EL_DIAMOND,
3446     EL_PEARL,
3447     EL_CRYSTAL,
3448
3449     -1
3450   };
3451
3452   static int ep_food_penguin[] =
3453   {
3454     EL_EMERALD,
3455     EL_BD_DIAMOND,
3456     EL_EMERALD_YELLOW,
3457     EL_EMERALD_RED,
3458     EL_EMERALD_PURPLE,
3459     EL_DIAMOND,
3460     EL_PEARL,
3461     EL_CRYSTAL,
3462
3463     -1
3464   };
3465
3466   static int ep_food_pig[] =
3467   {
3468     EL_EMERALD,
3469     EL_BD_DIAMOND,
3470     EL_EMERALD_YELLOW,
3471     EL_EMERALD_RED,
3472     EL_EMERALD_PURPLE,
3473     EL_DIAMOND,
3474
3475     -1
3476   };
3477
3478   static int ep_historic_wall[] =
3479   {
3480     EL_STEELWALL,
3481     EL_GATE_1,
3482     EL_GATE_2,
3483     EL_GATE_3,
3484     EL_GATE_4,
3485     EL_GATE_1_GRAY,
3486     EL_GATE_2_GRAY,
3487     EL_GATE_3_GRAY,
3488     EL_GATE_4_GRAY,
3489     EL_GATE_1_GRAY_ACTIVE,
3490     EL_GATE_2_GRAY_ACTIVE,
3491     EL_GATE_3_GRAY_ACTIVE,
3492     EL_GATE_4_GRAY_ACTIVE,
3493     EL_EM_GATE_1,
3494     EL_EM_GATE_2,
3495     EL_EM_GATE_3,
3496     EL_EM_GATE_4,
3497     EL_EM_GATE_1_GRAY,
3498     EL_EM_GATE_2_GRAY,
3499     EL_EM_GATE_3_GRAY,
3500     EL_EM_GATE_4_GRAY,
3501     EL_EM_GATE_1_GRAY_ACTIVE,
3502     EL_EM_GATE_2_GRAY_ACTIVE,
3503     EL_EM_GATE_3_GRAY_ACTIVE,
3504     EL_EM_GATE_4_GRAY_ACTIVE,
3505     EL_EXIT_CLOSED,
3506     EL_EXIT_OPENING,
3507     EL_EXIT_OPEN,
3508     EL_WALL,
3509     EL_WALL_SLIPPERY,
3510     EL_EXPANDABLE_WALL,
3511     EL_EXPANDABLE_WALL_HORIZONTAL,
3512     EL_EXPANDABLE_WALL_VERTICAL,
3513     EL_EXPANDABLE_WALL_ANY,
3514     EL_EXPANDABLE_WALL_GROWING,
3515     EL_BD_EXPANDABLE_WALL,
3516     EL_BD_WALL,
3517     EL_SP_CHIP_SINGLE,
3518     EL_SP_CHIP_LEFT,
3519     EL_SP_CHIP_RIGHT,
3520     EL_SP_CHIP_TOP,
3521     EL_SP_CHIP_BOTTOM,
3522     EL_SP_HARDWARE_GRAY,
3523     EL_SP_HARDWARE_GREEN,
3524     EL_SP_HARDWARE_BLUE,
3525     EL_SP_HARDWARE_RED,
3526     EL_SP_HARDWARE_YELLOW,
3527     EL_SP_HARDWARE_BASE_1,
3528     EL_SP_HARDWARE_BASE_2,
3529     EL_SP_HARDWARE_BASE_3,
3530     EL_SP_HARDWARE_BASE_4,
3531     EL_SP_HARDWARE_BASE_5,
3532     EL_SP_HARDWARE_BASE_6,
3533     EL_SP_TERMINAL,
3534     EL_SP_TERMINAL_ACTIVE,
3535     EL_SP_EXIT_CLOSED,
3536     EL_SP_EXIT_OPEN,
3537     EL_INVISIBLE_STEELWALL,
3538     EL_INVISIBLE_STEELWALL_ACTIVE,
3539     EL_INVISIBLE_WALL,
3540     EL_INVISIBLE_WALL_ACTIVE,
3541     EL_STEELWALL_SLIPPERY,
3542     EL_EMC_STEELWALL_1,
3543     EL_EMC_STEELWALL_2,
3544     EL_EMC_STEELWALL_3,
3545     EL_EMC_STEELWALL_4,
3546     EL_EMC_WALL_1,
3547     EL_EMC_WALL_2,
3548     EL_EMC_WALL_3,
3549     EL_EMC_WALL_4,
3550     EL_EMC_WALL_5,
3551     EL_EMC_WALL_6,
3552     EL_EMC_WALL_7,
3553     EL_EMC_WALL_8,
3554
3555     -1
3556   };
3557
3558   static int ep_historic_solid[] =
3559   {
3560     EL_WALL,
3561     EL_EXPANDABLE_WALL,
3562     EL_EXPANDABLE_WALL_HORIZONTAL,
3563     EL_EXPANDABLE_WALL_VERTICAL,
3564     EL_EXPANDABLE_WALL_ANY,
3565     EL_BD_EXPANDABLE_WALL,
3566     EL_BD_WALL,
3567     EL_WALL_SLIPPERY,
3568     EL_EXIT_CLOSED,
3569     EL_EXIT_OPENING,
3570     EL_EXIT_OPEN,
3571     EL_AMOEBA_DEAD,
3572     EL_AMOEBA_WET,
3573     EL_AMOEBA_DRY,
3574     EL_AMOEBA_FULL,
3575     EL_BD_AMOEBA,
3576     EL_QUICKSAND_EMPTY,
3577     EL_QUICKSAND_FULL,
3578     EL_QUICKSAND_FILLING,
3579     EL_QUICKSAND_EMPTYING,
3580     EL_MAGIC_WALL,
3581     EL_MAGIC_WALL_ACTIVE,
3582     EL_MAGIC_WALL_EMPTYING,
3583     EL_MAGIC_WALL_FILLING,
3584     EL_MAGIC_WALL_FULL,
3585     EL_MAGIC_WALL_DEAD,
3586     EL_BD_MAGIC_WALL,
3587     EL_BD_MAGIC_WALL_ACTIVE,
3588     EL_BD_MAGIC_WALL_EMPTYING,
3589     EL_BD_MAGIC_WALL_FULL,
3590     EL_BD_MAGIC_WALL_FILLING,
3591     EL_BD_MAGIC_WALL_DEAD,
3592     EL_GAME_OF_LIFE,
3593     EL_BIOMAZE,
3594     EL_SP_CHIP_SINGLE,
3595     EL_SP_CHIP_LEFT,
3596     EL_SP_CHIP_RIGHT,
3597     EL_SP_CHIP_TOP,
3598     EL_SP_CHIP_BOTTOM,
3599     EL_SP_TERMINAL,
3600     EL_SP_TERMINAL_ACTIVE,
3601     EL_SP_EXIT_CLOSED,
3602     EL_SP_EXIT_OPEN,
3603     EL_INVISIBLE_WALL,
3604     EL_INVISIBLE_WALL_ACTIVE,
3605     EL_SWITCHGATE_SWITCH_UP,
3606     EL_SWITCHGATE_SWITCH_DOWN,
3607     EL_DC_SWITCHGATE_SWITCH_UP,
3608     EL_DC_SWITCHGATE_SWITCH_DOWN,
3609     EL_TIMEGATE_SWITCH,
3610     EL_TIMEGATE_SWITCH_ACTIVE,
3611     EL_DC_TIMEGATE_SWITCH,
3612     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3613     EL_EMC_WALL_1,
3614     EL_EMC_WALL_2,
3615     EL_EMC_WALL_3,
3616     EL_EMC_WALL_4,
3617     EL_EMC_WALL_5,
3618     EL_EMC_WALL_6,
3619     EL_EMC_WALL_7,
3620     EL_EMC_WALL_8,
3621     EL_WALL_PEARL,
3622     EL_WALL_CRYSTAL,
3623
3624     /* the following elements are a direct copy of "indestructible" elements,
3625        except "EL_ACID", which is "indestructible", but not "solid"! */
3626 #if 0
3627     EL_ACID,
3628 #endif
3629     EL_STEELWALL,
3630     EL_ACID_POOL_TOPLEFT,
3631     EL_ACID_POOL_TOPRIGHT,
3632     EL_ACID_POOL_BOTTOMLEFT,
3633     EL_ACID_POOL_BOTTOM,
3634     EL_ACID_POOL_BOTTOMRIGHT,
3635     EL_SP_HARDWARE_GRAY,
3636     EL_SP_HARDWARE_GREEN,
3637     EL_SP_HARDWARE_BLUE,
3638     EL_SP_HARDWARE_RED,
3639     EL_SP_HARDWARE_YELLOW,
3640     EL_SP_HARDWARE_BASE_1,
3641     EL_SP_HARDWARE_BASE_2,
3642     EL_SP_HARDWARE_BASE_3,
3643     EL_SP_HARDWARE_BASE_4,
3644     EL_SP_HARDWARE_BASE_5,
3645     EL_SP_HARDWARE_BASE_6,
3646     EL_INVISIBLE_STEELWALL,
3647     EL_INVISIBLE_STEELWALL_ACTIVE,
3648     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3649     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3650     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3651     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3652     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3653     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3654     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3655     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3656     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3657     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3658     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3659     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3660     EL_LIGHT_SWITCH,
3661     EL_LIGHT_SWITCH_ACTIVE,
3662     EL_SIGN_EXCLAMATION,
3663     EL_SIGN_RADIOACTIVITY,
3664     EL_SIGN_STOP,
3665     EL_SIGN_WHEELCHAIR,
3666     EL_SIGN_PARKING,
3667     EL_SIGN_NO_ENTRY,
3668     EL_SIGN_UNUSED_1,
3669     EL_SIGN_GIVE_WAY,
3670     EL_SIGN_ENTRY_FORBIDDEN,
3671     EL_SIGN_EMERGENCY_EXIT,
3672     EL_SIGN_YIN_YANG,
3673     EL_SIGN_UNUSED_2,
3674     EL_SIGN_SPERMS,
3675     EL_SIGN_BULLET,
3676     EL_SIGN_HEART,
3677     EL_SIGN_CROSS,
3678     EL_SIGN_FRANKIE,
3679     EL_STEEL_EXIT_CLOSED,
3680     EL_STEEL_EXIT_OPEN,
3681     EL_DC_STEELWALL_1_LEFT,
3682     EL_DC_STEELWALL_1_RIGHT,
3683     EL_DC_STEELWALL_1_TOP,
3684     EL_DC_STEELWALL_1_BOTTOM,
3685     EL_DC_STEELWALL_1_HORIZONTAL,
3686     EL_DC_STEELWALL_1_VERTICAL,
3687     EL_DC_STEELWALL_1_TOPLEFT,
3688     EL_DC_STEELWALL_1_TOPRIGHT,
3689     EL_DC_STEELWALL_1_BOTTOMLEFT,
3690     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3691     EL_DC_STEELWALL_1_TOPLEFT_2,
3692     EL_DC_STEELWALL_1_TOPRIGHT_2,
3693     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3694     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3695     EL_DC_STEELWALL_2_LEFT,
3696     EL_DC_STEELWALL_2_RIGHT,
3697     EL_DC_STEELWALL_2_TOP,
3698     EL_DC_STEELWALL_2_BOTTOM,
3699     EL_DC_STEELWALL_2_HORIZONTAL,
3700     EL_DC_STEELWALL_2_VERTICAL,
3701     EL_DC_STEELWALL_2_MIDDLE,
3702     EL_DC_STEELWALL_2_SINGLE,
3703     EL_STEELWALL_SLIPPERY,
3704     EL_EMC_STEELWALL_1,
3705     EL_EMC_STEELWALL_2,
3706     EL_EMC_STEELWALL_3,
3707     EL_EMC_STEELWALL_4,
3708     EL_CRYSTAL,
3709     EL_GATE_1,
3710     EL_GATE_2,
3711     EL_GATE_3,
3712     EL_GATE_4,
3713     EL_GATE_1_GRAY,
3714     EL_GATE_2_GRAY,
3715     EL_GATE_3_GRAY,
3716     EL_GATE_4_GRAY,
3717     EL_GATE_1_GRAY_ACTIVE,
3718     EL_GATE_2_GRAY_ACTIVE,
3719     EL_GATE_3_GRAY_ACTIVE,
3720     EL_GATE_4_GRAY_ACTIVE,
3721     EL_EM_GATE_1,
3722     EL_EM_GATE_2,
3723     EL_EM_GATE_3,
3724     EL_EM_GATE_4,
3725     EL_EM_GATE_1_GRAY,
3726     EL_EM_GATE_2_GRAY,
3727     EL_EM_GATE_3_GRAY,
3728     EL_EM_GATE_4_GRAY,
3729     EL_EM_GATE_1_GRAY_ACTIVE,
3730     EL_EM_GATE_2_GRAY_ACTIVE,
3731     EL_EM_GATE_3_GRAY_ACTIVE,
3732     EL_EM_GATE_4_GRAY_ACTIVE,
3733     EL_SWITCHGATE_OPEN,
3734     EL_SWITCHGATE_OPENING,
3735     EL_SWITCHGATE_CLOSED,
3736     EL_SWITCHGATE_CLOSING,
3737     EL_TIMEGATE_OPEN,
3738     EL_TIMEGATE_OPENING,
3739     EL_TIMEGATE_CLOSED,
3740     EL_TIMEGATE_CLOSING,
3741     EL_TUBE_ANY,
3742     EL_TUBE_VERTICAL,
3743     EL_TUBE_HORIZONTAL,
3744     EL_TUBE_VERTICAL_LEFT,
3745     EL_TUBE_VERTICAL_RIGHT,
3746     EL_TUBE_HORIZONTAL_UP,
3747     EL_TUBE_HORIZONTAL_DOWN,
3748     EL_TUBE_LEFT_UP,
3749     EL_TUBE_LEFT_DOWN,
3750     EL_TUBE_RIGHT_UP,
3751     EL_TUBE_RIGHT_DOWN,
3752
3753     -1
3754   };
3755
3756   static int ep_classic_enemy[] =
3757   {
3758     EL_BUG,
3759     EL_SPACESHIP,
3760     EL_BD_BUTTERFLY,
3761     EL_BD_FIREFLY,
3762
3763     EL_YAMYAM,
3764     EL_DARK_YAMYAM,
3765     EL_ROBOT,
3766     EL_PACMAN,
3767     EL_SP_SNIKSNAK,
3768     EL_SP_ELECTRON,
3769
3770     -1
3771   };
3772
3773   static int ep_belt[] =
3774   {
3775     EL_CONVEYOR_BELT_1_LEFT,
3776     EL_CONVEYOR_BELT_1_MIDDLE,
3777     EL_CONVEYOR_BELT_1_RIGHT,
3778     EL_CONVEYOR_BELT_2_LEFT,
3779     EL_CONVEYOR_BELT_2_MIDDLE,
3780     EL_CONVEYOR_BELT_2_RIGHT,
3781     EL_CONVEYOR_BELT_3_LEFT,
3782     EL_CONVEYOR_BELT_3_MIDDLE,
3783     EL_CONVEYOR_BELT_3_RIGHT,
3784     EL_CONVEYOR_BELT_4_LEFT,
3785     EL_CONVEYOR_BELT_4_MIDDLE,
3786     EL_CONVEYOR_BELT_4_RIGHT,
3787
3788     -1
3789   };
3790
3791   static int ep_belt_active[] =
3792   {
3793     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3794     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3795     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3796     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3797     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3798     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3799     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3800     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3801     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3802     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3803     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3804     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3805
3806     -1
3807   };
3808
3809   static int ep_belt_switch[] =
3810   {
3811     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3812     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3813     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3814     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3815     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3816     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3817     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3818     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3819     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3820     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3821     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3822     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3823
3824     -1
3825   };
3826
3827   static int ep_tube[] =
3828   {
3829     EL_TUBE_LEFT_UP,
3830     EL_TUBE_LEFT_DOWN,
3831     EL_TUBE_RIGHT_UP,
3832     EL_TUBE_RIGHT_DOWN,
3833     EL_TUBE_HORIZONTAL,
3834     EL_TUBE_HORIZONTAL_UP,
3835     EL_TUBE_HORIZONTAL_DOWN,
3836     EL_TUBE_VERTICAL,
3837     EL_TUBE_VERTICAL_LEFT,
3838     EL_TUBE_VERTICAL_RIGHT,
3839     EL_TUBE_ANY,
3840
3841     -1
3842   };
3843
3844   static int ep_acid_pool[] =
3845   {
3846     EL_ACID_POOL_TOPLEFT,
3847     EL_ACID_POOL_TOPRIGHT,
3848     EL_ACID_POOL_BOTTOMLEFT,
3849     EL_ACID_POOL_BOTTOM,
3850     EL_ACID_POOL_BOTTOMRIGHT,
3851
3852     -1
3853   };
3854
3855   static int ep_keygate[] =
3856   {
3857     EL_GATE_1,
3858     EL_GATE_2,
3859     EL_GATE_3,
3860     EL_GATE_4,
3861     EL_GATE_1_GRAY,
3862     EL_GATE_2_GRAY,
3863     EL_GATE_3_GRAY,
3864     EL_GATE_4_GRAY,
3865     EL_GATE_1_GRAY_ACTIVE,
3866     EL_GATE_2_GRAY_ACTIVE,
3867     EL_GATE_3_GRAY_ACTIVE,
3868     EL_GATE_4_GRAY_ACTIVE,
3869     EL_EM_GATE_1,
3870     EL_EM_GATE_2,
3871     EL_EM_GATE_3,
3872     EL_EM_GATE_4,
3873     EL_EM_GATE_1_GRAY,
3874     EL_EM_GATE_2_GRAY,
3875     EL_EM_GATE_3_GRAY,
3876     EL_EM_GATE_4_GRAY,
3877     EL_EM_GATE_1_GRAY_ACTIVE,
3878     EL_EM_GATE_2_GRAY_ACTIVE,
3879     EL_EM_GATE_3_GRAY_ACTIVE,
3880     EL_EM_GATE_4_GRAY_ACTIVE,
3881     EL_EMC_GATE_5,
3882     EL_EMC_GATE_6,
3883     EL_EMC_GATE_7,
3884     EL_EMC_GATE_8,
3885     EL_EMC_GATE_5_GRAY,
3886     EL_EMC_GATE_6_GRAY,
3887     EL_EMC_GATE_7_GRAY,
3888     EL_EMC_GATE_8_GRAY,
3889     EL_EMC_GATE_5_GRAY_ACTIVE,
3890     EL_EMC_GATE_6_GRAY_ACTIVE,
3891     EL_EMC_GATE_7_GRAY_ACTIVE,
3892     EL_EMC_GATE_8_GRAY_ACTIVE,
3893     EL_DC_GATE_WHITE,
3894     EL_DC_GATE_WHITE_GRAY,
3895     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3896
3897     -1
3898   };
3899
3900   static int ep_amoeboid[] =
3901   {
3902     EL_AMOEBA_DEAD,
3903     EL_AMOEBA_WET,
3904     EL_AMOEBA_DRY,
3905     EL_AMOEBA_FULL,
3906     EL_BD_AMOEBA,
3907     EL_EMC_DRIPPER,
3908
3909     -1
3910   };
3911
3912   static int ep_amoebalive[] =
3913   {
3914     EL_AMOEBA_WET,
3915     EL_AMOEBA_DRY,
3916     EL_AMOEBA_FULL,
3917     EL_BD_AMOEBA,
3918     EL_EMC_DRIPPER,
3919
3920     -1
3921   };
3922
3923   static int ep_has_editor_content[] =
3924   {
3925     EL_PLAYER_1,
3926     EL_PLAYER_2,
3927     EL_PLAYER_3,
3928     EL_PLAYER_4,
3929     EL_SOKOBAN_FIELD_PLAYER,
3930     EL_SP_MURPHY,
3931     EL_YAMYAM,
3932     EL_YAMYAM_LEFT,
3933     EL_YAMYAM_RIGHT,
3934     EL_YAMYAM_UP,
3935     EL_YAMYAM_DOWN,
3936     EL_AMOEBA_WET,
3937     EL_AMOEBA_DRY,
3938     EL_AMOEBA_FULL,
3939     EL_BD_AMOEBA,
3940     EL_EMC_MAGIC_BALL,
3941     EL_EMC_ANDROID,
3942
3943     -1
3944   };
3945
3946   static int ep_can_turn_each_move[] =
3947   {
3948     /* !!! do something with this one !!! */
3949     -1
3950   };
3951
3952   static int ep_can_grow[] =
3953   {
3954     EL_BD_AMOEBA,
3955     EL_AMOEBA_DROP,
3956     EL_AMOEBA_WET,
3957     EL_AMOEBA_DRY,
3958     EL_AMOEBA_FULL,
3959     EL_GAME_OF_LIFE,
3960     EL_BIOMAZE,
3961     EL_EMC_DRIPPER,
3962
3963     -1
3964   };
3965
3966   static int ep_active_bomb[] =
3967   {
3968     EL_DYNAMITE_ACTIVE,
3969     EL_EM_DYNAMITE_ACTIVE,
3970     EL_DYNABOMB_PLAYER_1_ACTIVE,
3971     EL_DYNABOMB_PLAYER_2_ACTIVE,
3972     EL_DYNABOMB_PLAYER_3_ACTIVE,
3973     EL_DYNABOMB_PLAYER_4_ACTIVE,
3974     EL_SP_DISK_RED_ACTIVE,
3975
3976     -1
3977   };
3978
3979   static int ep_inactive[] =
3980   {
3981     EL_EMPTY,
3982     EL_SAND,
3983     EL_WALL,
3984     EL_BD_WALL,
3985     EL_WALL_SLIPPERY,
3986     EL_STEELWALL,
3987     EL_AMOEBA_DEAD,
3988     EL_QUICKSAND_EMPTY,
3989     EL_QUICKSAND_FAST_EMPTY,
3990     EL_STONEBLOCK,
3991     EL_ROBOT_WHEEL,
3992     EL_KEY_1,
3993     EL_KEY_2,
3994     EL_KEY_3,
3995     EL_KEY_4,
3996     EL_EM_KEY_1,
3997     EL_EM_KEY_2,
3998     EL_EM_KEY_3,
3999     EL_EM_KEY_4,
4000     EL_EMC_KEY_5,
4001     EL_EMC_KEY_6,
4002     EL_EMC_KEY_7,
4003     EL_EMC_KEY_8,
4004     EL_GATE_1,
4005     EL_GATE_2,
4006     EL_GATE_3,
4007     EL_GATE_4,
4008     EL_GATE_1_GRAY,
4009     EL_GATE_2_GRAY,
4010     EL_GATE_3_GRAY,
4011     EL_GATE_4_GRAY,
4012     EL_GATE_1_GRAY_ACTIVE,
4013     EL_GATE_2_GRAY_ACTIVE,
4014     EL_GATE_3_GRAY_ACTIVE,
4015     EL_GATE_4_GRAY_ACTIVE,
4016     EL_EM_GATE_1,
4017     EL_EM_GATE_2,
4018     EL_EM_GATE_3,
4019     EL_EM_GATE_4,
4020     EL_EM_GATE_1_GRAY,
4021     EL_EM_GATE_2_GRAY,
4022     EL_EM_GATE_3_GRAY,
4023     EL_EM_GATE_4_GRAY,
4024     EL_EM_GATE_1_GRAY_ACTIVE,
4025     EL_EM_GATE_2_GRAY_ACTIVE,
4026     EL_EM_GATE_3_GRAY_ACTIVE,
4027     EL_EM_GATE_4_GRAY_ACTIVE,
4028     EL_EMC_GATE_5,
4029     EL_EMC_GATE_6,
4030     EL_EMC_GATE_7,
4031     EL_EMC_GATE_8,
4032     EL_EMC_GATE_5_GRAY,
4033     EL_EMC_GATE_6_GRAY,
4034     EL_EMC_GATE_7_GRAY,
4035     EL_EMC_GATE_8_GRAY,
4036     EL_EMC_GATE_5_GRAY_ACTIVE,
4037     EL_EMC_GATE_6_GRAY_ACTIVE,
4038     EL_EMC_GATE_7_GRAY_ACTIVE,
4039     EL_EMC_GATE_8_GRAY_ACTIVE,
4040     EL_DC_GATE_WHITE,
4041     EL_DC_GATE_WHITE_GRAY,
4042     EL_DC_GATE_WHITE_GRAY_ACTIVE,
4043     EL_DC_GATE_FAKE_GRAY,
4044     EL_DYNAMITE,
4045     EL_EM_DYNAMITE,
4046     EL_INVISIBLE_STEELWALL,
4047     EL_INVISIBLE_WALL,
4048     EL_INVISIBLE_SAND,
4049     EL_LAMP,
4050     EL_LAMP_ACTIVE,
4051     EL_WALL_EMERALD,
4052     EL_WALL_DIAMOND,
4053     EL_WALL_BD_DIAMOND,
4054     EL_WALL_EMERALD_YELLOW,
4055     EL_DYNABOMB_INCREASE_NUMBER,
4056     EL_DYNABOMB_INCREASE_SIZE,
4057     EL_DYNABOMB_INCREASE_POWER,
4058 #if 0
4059     EL_SOKOBAN_OBJECT,
4060 #endif
4061     EL_SOKOBAN_FIELD_EMPTY,
4062     EL_SOKOBAN_FIELD_FULL,
4063     EL_WALL_EMERALD_RED,
4064     EL_WALL_EMERALD_PURPLE,
4065     EL_ACID_POOL_TOPLEFT,
4066     EL_ACID_POOL_TOPRIGHT,
4067     EL_ACID_POOL_BOTTOMLEFT,
4068     EL_ACID_POOL_BOTTOM,
4069     EL_ACID_POOL_BOTTOMRIGHT,
4070     EL_MAGIC_WALL,
4071     EL_MAGIC_WALL_DEAD,
4072     EL_BD_MAGIC_WALL,
4073     EL_BD_MAGIC_WALL_DEAD,
4074     EL_DC_MAGIC_WALL,
4075     EL_DC_MAGIC_WALL_DEAD,
4076     EL_AMOEBA_TO_DIAMOND,
4077     EL_BLOCKED,
4078     EL_SP_EMPTY,
4079     EL_SP_BASE,
4080     EL_SP_PORT_RIGHT,
4081     EL_SP_PORT_DOWN,
4082     EL_SP_PORT_LEFT,
4083     EL_SP_PORT_UP,
4084     EL_SP_GRAVITY_PORT_RIGHT,
4085     EL_SP_GRAVITY_PORT_DOWN,
4086     EL_SP_GRAVITY_PORT_LEFT,
4087     EL_SP_GRAVITY_PORT_UP,
4088     EL_SP_PORT_HORIZONTAL,
4089     EL_SP_PORT_VERTICAL,
4090     EL_SP_PORT_ANY,
4091     EL_SP_DISK_RED,
4092 #if 0
4093     EL_SP_DISK_YELLOW,
4094 #endif
4095     EL_SP_CHIP_SINGLE,
4096     EL_SP_CHIP_LEFT,
4097     EL_SP_CHIP_RIGHT,
4098     EL_SP_CHIP_TOP,
4099     EL_SP_CHIP_BOTTOM,
4100     EL_SP_HARDWARE_GRAY,
4101     EL_SP_HARDWARE_GREEN,
4102     EL_SP_HARDWARE_BLUE,
4103     EL_SP_HARDWARE_RED,
4104     EL_SP_HARDWARE_YELLOW,
4105     EL_SP_HARDWARE_BASE_1,
4106     EL_SP_HARDWARE_BASE_2,
4107     EL_SP_HARDWARE_BASE_3,
4108     EL_SP_HARDWARE_BASE_4,
4109     EL_SP_HARDWARE_BASE_5,
4110     EL_SP_HARDWARE_BASE_6,
4111     EL_SP_GRAVITY_ON_PORT_LEFT,
4112     EL_SP_GRAVITY_ON_PORT_RIGHT,
4113     EL_SP_GRAVITY_ON_PORT_UP,
4114     EL_SP_GRAVITY_ON_PORT_DOWN,
4115     EL_SP_GRAVITY_OFF_PORT_LEFT,
4116     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4117     EL_SP_GRAVITY_OFF_PORT_UP,
4118     EL_SP_GRAVITY_OFF_PORT_DOWN,
4119     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4120     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4121     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4122     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4123     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4124     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4125     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4126     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4127     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4128     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4129     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4130     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4131     EL_SIGN_EXCLAMATION,
4132     EL_SIGN_RADIOACTIVITY,
4133     EL_SIGN_STOP,
4134     EL_SIGN_WHEELCHAIR,
4135     EL_SIGN_PARKING,
4136     EL_SIGN_NO_ENTRY,
4137     EL_SIGN_UNUSED_1,
4138     EL_SIGN_GIVE_WAY,
4139     EL_SIGN_ENTRY_FORBIDDEN,
4140     EL_SIGN_EMERGENCY_EXIT,
4141     EL_SIGN_YIN_YANG,
4142     EL_SIGN_UNUSED_2,
4143     EL_SIGN_SPERMS,
4144     EL_SIGN_BULLET,
4145     EL_SIGN_HEART,
4146     EL_SIGN_CROSS,
4147     EL_SIGN_FRANKIE,
4148     EL_DC_STEELWALL_1_LEFT,
4149     EL_DC_STEELWALL_1_RIGHT,
4150     EL_DC_STEELWALL_1_TOP,
4151     EL_DC_STEELWALL_1_BOTTOM,
4152     EL_DC_STEELWALL_1_HORIZONTAL,
4153     EL_DC_STEELWALL_1_VERTICAL,
4154     EL_DC_STEELWALL_1_TOPLEFT,
4155     EL_DC_STEELWALL_1_TOPRIGHT,
4156     EL_DC_STEELWALL_1_BOTTOMLEFT,
4157     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4158     EL_DC_STEELWALL_1_TOPLEFT_2,
4159     EL_DC_STEELWALL_1_TOPRIGHT_2,
4160     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4161     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4162     EL_DC_STEELWALL_2_LEFT,
4163     EL_DC_STEELWALL_2_RIGHT,
4164     EL_DC_STEELWALL_2_TOP,
4165     EL_DC_STEELWALL_2_BOTTOM,
4166     EL_DC_STEELWALL_2_HORIZONTAL,
4167     EL_DC_STEELWALL_2_VERTICAL,
4168     EL_DC_STEELWALL_2_MIDDLE,
4169     EL_DC_STEELWALL_2_SINGLE,
4170     EL_STEELWALL_SLIPPERY,
4171     EL_EMC_STEELWALL_1,
4172     EL_EMC_STEELWALL_2,
4173     EL_EMC_STEELWALL_3,
4174     EL_EMC_STEELWALL_4,
4175     EL_EMC_WALL_SLIPPERY_1,
4176     EL_EMC_WALL_SLIPPERY_2,
4177     EL_EMC_WALL_SLIPPERY_3,
4178     EL_EMC_WALL_SLIPPERY_4,
4179     EL_EMC_WALL_1,
4180     EL_EMC_WALL_2,
4181     EL_EMC_WALL_3,
4182     EL_EMC_WALL_4,
4183     EL_EMC_WALL_5,
4184     EL_EMC_WALL_6,
4185     EL_EMC_WALL_7,
4186     EL_EMC_WALL_8,
4187     EL_EMC_WALL_9,
4188     EL_EMC_WALL_10,
4189     EL_EMC_WALL_11,
4190     EL_EMC_WALL_12,
4191     EL_EMC_WALL_13,
4192     EL_EMC_WALL_14,
4193     EL_EMC_WALL_15,
4194     EL_EMC_WALL_16,
4195
4196     -1
4197   };
4198
4199   static int ep_em_slippery_wall[] =
4200   {
4201     -1
4202   };
4203
4204   static int ep_gfx_crumbled[] =
4205   {
4206     EL_SAND,
4207     EL_LANDMINE,
4208     EL_DC_LANDMINE,
4209     EL_TRAP,
4210     EL_TRAP_ACTIVE,
4211
4212     -1
4213   };
4214
4215   static int ep_editor_cascade_active[] =
4216   {
4217     EL_INTERNAL_CASCADE_BD_ACTIVE,
4218     EL_INTERNAL_CASCADE_EM_ACTIVE,
4219     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4220     EL_INTERNAL_CASCADE_RND_ACTIVE,
4221     EL_INTERNAL_CASCADE_SB_ACTIVE,
4222     EL_INTERNAL_CASCADE_SP_ACTIVE,
4223     EL_INTERNAL_CASCADE_DC_ACTIVE,
4224     EL_INTERNAL_CASCADE_DX_ACTIVE,
4225     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4226     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4227     EL_INTERNAL_CASCADE_CE_ACTIVE,
4228     EL_INTERNAL_CASCADE_GE_ACTIVE,
4229     EL_INTERNAL_CASCADE_REF_ACTIVE,
4230     EL_INTERNAL_CASCADE_USER_ACTIVE,
4231     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4232
4233     -1
4234   };
4235
4236   static int ep_editor_cascade_inactive[] =
4237   {
4238     EL_INTERNAL_CASCADE_BD,
4239     EL_INTERNAL_CASCADE_EM,
4240     EL_INTERNAL_CASCADE_EMC,
4241     EL_INTERNAL_CASCADE_RND,
4242     EL_INTERNAL_CASCADE_SB,
4243     EL_INTERNAL_CASCADE_SP,
4244     EL_INTERNAL_CASCADE_DC,
4245     EL_INTERNAL_CASCADE_DX,
4246     EL_INTERNAL_CASCADE_CHARS,
4247     EL_INTERNAL_CASCADE_STEEL_CHARS,
4248     EL_INTERNAL_CASCADE_CE,
4249     EL_INTERNAL_CASCADE_GE,
4250     EL_INTERNAL_CASCADE_REF,
4251     EL_INTERNAL_CASCADE_USER,
4252     EL_INTERNAL_CASCADE_DYNAMIC,
4253
4254     -1
4255   };
4256
4257   static int ep_obsolete[] =
4258   {
4259     EL_PLAYER_OBSOLETE,
4260     EL_KEY_OBSOLETE,
4261     EL_EM_KEY_1_FILE_OBSOLETE,
4262     EL_EM_KEY_2_FILE_OBSOLETE,
4263     EL_EM_KEY_3_FILE_OBSOLETE,
4264     EL_EM_KEY_4_FILE_OBSOLETE,
4265     EL_ENVELOPE_OBSOLETE,
4266
4267     -1
4268   };
4269
4270   static struct
4271   {
4272     int *elements;
4273     int property;
4274   } element_properties[] =
4275   {
4276     { ep_diggable,                      EP_DIGGABLE                     },
4277     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4278     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4279     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4280     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4281     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4282     { ep_slippery,                      EP_SLIPPERY                     },
4283     { ep_can_change,                    EP_CAN_CHANGE                   },
4284     { ep_can_move,                      EP_CAN_MOVE                     },
4285     { ep_can_fall,                      EP_CAN_FALL                     },
4286     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4287     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4288     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4289     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4290     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4291     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4292     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4293     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4294     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4295     { ep_passable_over,                 EP_PASSABLE_OVER                },
4296     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4297     { ep_passable_under,                EP_PASSABLE_UNDER               },
4298     { ep_droppable,                     EP_DROPPABLE                    },
4299     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4300     { ep_pushable,                      EP_PUSHABLE                     },
4301     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4302     { ep_protected,                     EP_PROTECTED                    },
4303     { ep_throwable,                     EP_THROWABLE                    },
4304     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4305     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4306
4307     { ep_player,                        EP_PLAYER                       },
4308     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4309     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4310     { ep_switchable,                    EP_SWITCHABLE                   },
4311     { ep_bd_element,                    EP_BD_ELEMENT                   },
4312     { ep_sp_element,                    EP_SP_ELEMENT                   },
4313     { ep_sb_element,                    EP_SB_ELEMENT                   },
4314     { ep_gem,                           EP_GEM                          },
4315     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4316     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4317     { ep_food_pig,                      EP_FOOD_PIG                     },
4318     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4319     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4320     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4321     { ep_belt,                          EP_BELT                         },
4322     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4323     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4324     { ep_tube,                          EP_TUBE                         },
4325     { ep_acid_pool,                     EP_ACID_POOL                    },
4326     { ep_keygate,                       EP_KEYGATE                      },
4327     { ep_amoeboid,                      EP_AMOEBOID                     },
4328     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4329     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4330     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4331     { ep_can_grow,                      EP_CAN_GROW                     },
4332     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4333     { ep_inactive,                      EP_INACTIVE                     },
4334
4335     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4336
4337     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4338
4339     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4340     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4341
4342     { ep_obsolete,                      EP_OBSOLETE                     },
4343
4344     { NULL,                             -1                              }
4345   };
4346
4347   int i, j, k;
4348
4349   /* always start with reliable default values (element has no properties) */
4350   /* (but never initialize clipboard elements after the very first time) */
4351   /* (to be able to use clipboard elements between several levels) */
4352   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4353     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4354       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4355         SET_PROPERTY(i, j, FALSE);
4356
4357   /* set all base element properties from above array definitions */
4358   for (i = 0; element_properties[i].elements != NULL; i++)
4359     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4360       SET_PROPERTY((element_properties[i].elements)[j],
4361                    element_properties[i].property, TRUE);
4362
4363   /* copy properties to some elements that are only stored in level file */
4364   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4365     for (j = 0; copy_properties[j][0] != -1; j++)
4366       if (HAS_PROPERTY(copy_properties[j][0], i))
4367         for (k = 1; k <= 4; k++)
4368           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4369
4370   /* set static element properties that are not listed in array definitions */
4371   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4372     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4373
4374   clipboard_elements_initialized = TRUE;
4375 }
4376
4377 void InitElementPropertiesEngine(int engine_version)
4378 {
4379   static int no_wall_properties[] =
4380   {
4381     EP_DIGGABLE,
4382     EP_COLLECTIBLE_ONLY,
4383     EP_DONT_RUN_INTO,
4384     EP_DONT_COLLIDE_WITH,
4385     EP_CAN_MOVE,
4386     EP_CAN_FALL,
4387     EP_CAN_SMASH_PLAYER,
4388     EP_CAN_SMASH_ENEMIES,
4389     EP_CAN_SMASH_EVERYTHING,
4390     EP_PUSHABLE,
4391
4392     EP_PLAYER,
4393     EP_GEM,
4394     EP_FOOD_DARK_YAMYAM,
4395     EP_FOOD_PENGUIN,
4396     EP_BELT,
4397     EP_BELT_ACTIVE,
4398     EP_TUBE,
4399     EP_AMOEBOID,
4400     EP_AMOEBALIVE,
4401     EP_ACTIVE_BOMB,
4402
4403     EP_ACCESSIBLE,
4404
4405     -1
4406   };
4407
4408   int i, j;
4409
4410   /* important: after initialization in InitElementPropertiesStatic(), the
4411      elements are not again initialized to a default value; therefore all
4412      changes have to make sure that they leave the element with a defined
4413      property (which means that conditional property changes must be set to
4414      a reliable default value before) */
4415
4416   /* resolve group elements */
4417   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4418     ResolveGroupElement(EL_GROUP_START + i);
4419
4420   /* set all special, combined or engine dependent element properties */
4421   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4422   {
4423     /* do not change (already initialized) clipboard elements here */
4424     if (IS_CLIPBOARD_ELEMENT(i))
4425       continue;
4426
4427     /* ---------- INACTIVE ------------------------------------------------- */
4428     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4429                                    i <= EL_CHAR_END) ||
4430                                   (i >= EL_STEEL_CHAR_START &&
4431                                    i <= EL_STEEL_CHAR_END)));
4432
4433     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4434     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4435                                   IS_WALKABLE_INSIDE(i) ||
4436                                   IS_WALKABLE_UNDER(i)));
4437
4438     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4439                                   IS_PASSABLE_INSIDE(i) ||
4440                                   IS_PASSABLE_UNDER(i)));
4441
4442     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4443                                          IS_PASSABLE_OVER(i)));
4444
4445     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4446                                            IS_PASSABLE_INSIDE(i)));
4447
4448     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4449                                           IS_PASSABLE_UNDER(i)));
4450
4451     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4452                                     IS_PASSABLE(i)));
4453
4454     /* ---------- COLLECTIBLE ---------------------------------------------- */
4455     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4456                                      IS_DROPPABLE(i) ||
4457                                      IS_THROWABLE(i)));
4458
4459     /* ---------- SNAPPABLE ------------------------------------------------ */
4460     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4461                                    IS_COLLECTIBLE(i) ||
4462                                    IS_SWITCHABLE(i) ||
4463                                    i == EL_BD_ROCK));
4464
4465     /* ---------- WALL ----------------------------------------------------- */
4466     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
4467
4468     for (j = 0; no_wall_properties[j] != -1; j++)
4469       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4470           i >= EL_FIRST_RUNTIME_UNREAL)
4471         SET_PROPERTY(i, EP_WALL, FALSE);
4472
4473     if (IS_HISTORIC_WALL(i))
4474       SET_PROPERTY(i, EP_WALL, TRUE);
4475
4476     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4477     if (engine_version < VERSION_IDENT(2,2,0,0))
4478       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4479     else
4480       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4481                                              !IS_DIGGABLE(i) &&
4482                                              !IS_COLLECTIBLE(i)));
4483
4484     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4485     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4486       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4487     else
4488       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4489                                             IS_INDESTRUCTIBLE(i)));
4490
4491     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4492     if (i == EL_FLAMES)
4493       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4494     else if (engine_version < VERSION_IDENT(2,2,0,0))
4495       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4496     else
4497       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4498                                            (!IS_WALKABLE(i) ||
4499                                             IS_PROTECTED(i))));
4500
4501     if (IS_CUSTOM_ELEMENT(i))
4502     {
4503       /* these are additional properties which are initially false when set */
4504
4505       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4506       if (DONT_TOUCH(i))
4507         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4508       if (DONT_COLLIDE_WITH(i))
4509         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4510
4511       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4512       if (CAN_SMASH_EVERYTHING(i))
4513         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4514       if (CAN_SMASH_ENEMIES(i))
4515         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4516     }
4517
4518     /* ---------- CAN_SMASH ------------------------------------------------ */
4519     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4520                                    CAN_SMASH_ENEMIES(i) ||
4521                                    CAN_SMASH_EVERYTHING(i)));
4522
4523     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4524     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4525                                              EXPLODES_BY_FIRE(i)));
4526
4527     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4528     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4529                                              EXPLODES_SMASHED(i)));
4530
4531     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4532     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4533                                             EXPLODES_IMPACT(i)));
4534
4535     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4536     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4537
4538     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4539     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4540                                                   i == EL_BLACK_ORB));
4541
4542     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4543     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4544                                               CAN_MOVE(i) ||
4545                                               IS_CUSTOM_ELEMENT(i)));
4546
4547     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4548     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4549                                                  i == EL_SP_ELECTRON));
4550
4551     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4552     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4553       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4554                    getMoveIntoAcidProperty(&level, i));
4555
4556     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4557     if (MAYBE_DONT_COLLIDE_WITH(i))
4558       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4559                    getDontCollideWithProperty(&level, i));
4560
4561     /* ---------- SP_PORT -------------------------------------------------- */
4562     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4563                                  IS_PASSABLE_INSIDE(i)));
4564
4565     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4566     for (j = 0; j < level.num_android_clone_elements; j++)
4567       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4568                    (i != EL_EMPTY &&
4569                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4570
4571     /* ---------- CAN_CHANGE ----------------------------------------------- */
4572     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
4573     for (j = 0; j < element_info[i].num_change_pages; j++)
4574       if (element_info[i].change_page[j].can_change)
4575         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4576
4577     /* ---------- HAS_ACTION ----------------------------------------------- */
4578     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4579     for (j = 0; j < element_info[i].num_change_pages; j++)
4580       if (element_info[i].change_page[j].has_action)
4581         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4582
4583     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4584     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4585                                                   HAS_ACTION(i)));
4586
4587     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4588     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4589                  element_info[i].crumbled[ACTION_DEFAULT] !=
4590                  element_info[i].graphic[ACTION_DEFAULT]);
4591
4592     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4593     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4594                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4595   }
4596
4597   /* dynamically adjust element properties according to game engine version */
4598   {
4599     static int ep_em_slippery_wall[] =
4600     {
4601       EL_WALL,
4602       EL_STEELWALL,
4603       EL_EXPANDABLE_WALL,
4604       EL_EXPANDABLE_WALL_HORIZONTAL,
4605       EL_EXPANDABLE_WALL_VERTICAL,
4606       EL_EXPANDABLE_WALL_ANY,
4607       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4608       EL_EXPANDABLE_STEELWALL_VERTICAL,
4609       EL_EXPANDABLE_STEELWALL_ANY,
4610       EL_EXPANDABLE_STEELWALL_GROWING,
4611       -1
4612     };
4613
4614     static int ep_em_explodes_by_fire[] =
4615     {
4616       EL_EM_DYNAMITE,
4617       EL_EM_DYNAMITE_ACTIVE,
4618       EL_MOLE,
4619       -1
4620     };
4621
4622     /* special EM style gems behaviour */
4623     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4624       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4625                    level.em_slippery_gems);
4626
4627     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4628     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4629                  (level.em_slippery_gems &&
4630                   engine_version > VERSION_IDENT(2,0,1,0)));
4631
4632     /* special EM style explosion behaviour regarding chain reactions */
4633     for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4634       SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4635                    level.em_explodes_by_fire);
4636   }
4637
4638   /* this is needed because some graphics depend on element properties */
4639   if (game_status == GAME_MODE_PLAYING)
4640     InitElementGraphicInfo();
4641 }
4642
4643 void InitElementPropertiesAfterLoading(int engine_version)
4644 {
4645   int i;
4646
4647   /* set some other uninitialized values of custom elements in older levels */
4648   if (engine_version < VERSION_IDENT(3,1,0,0))
4649   {
4650     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4651     {
4652       int element = EL_CUSTOM_START + i;
4653
4654       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4655
4656       element_info[element].explosion_delay = 17;
4657       element_info[element].ignition_delay = 8;
4658     }
4659   }
4660 }
4661
4662 void InitElementPropertiesGfxElement()
4663 {
4664   int i;
4665
4666   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4667   {
4668     struct ElementInfo *ei = &element_info[i];
4669
4670     ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4671   }
4672 }
4673
4674 static void InitGlobal()
4675 {
4676   int graphic;
4677   int i;
4678
4679   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4680   {
4681     /* check if element_name_info entry defined for each element in "main.h" */
4682     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4683       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4684
4685     element_info[i].token_name = element_name_info[i].token_name;
4686     element_info[i].class_name = element_name_info[i].class_name;
4687     element_info[i].editor_description= element_name_info[i].editor_description;
4688   }
4689
4690   /* create hash from image config list */
4691   image_config_hash = newSetupFileHash();
4692   for (i = 0; image_config[i].token != NULL; i++)
4693     setHashEntry(image_config_hash,
4694                  image_config[i].token,
4695                  image_config[i].value);
4696
4697   /* create hash from element token list */
4698   element_token_hash = newSetupFileHash();
4699   for (i = 0; element_name_info[i].token_name != NULL; i++)
4700     setHashEntry(element_token_hash,
4701                  element_name_info[i].token_name,
4702                  int2str(i, 0));
4703
4704   /* create hash from graphic token list */
4705   graphic_token_hash = newSetupFileHash();
4706   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4707     if (strSuffix(image_config[i].value, ".png") ||
4708         strSuffix(image_config[i].value, ".pcx") ||
4709         strSuffix(image_config[i].value, ".wav") ||
4710         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4711       setHashEntry(graphic_token_hash,
4712                    image_config[i].token,
4713                    int2str(graphic++, 0));
4714
4715   /* create hash from font token list */
4716   font_token_hash = newSetupFileHash();
4717   for (i = 0; font_info[i].token_name != NULL; i++)
4718     setHashEntry(font_token_hash,
4719                  font_info[i].token_name,
4720                  int2str(i, 0));
4721
4722   /* set default filenames for all cloned graphics in static configuration */
4723   for (i = 0; image_config[i].token != NULL; i++)
4724   {
4725     if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4726     {
4727       char *token = image_config[i].token;
4728       char *token_clone_from = getStringCat2(token, ".clone_from");
4729       char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4730
4731       if (token_cloned != NULL)
4732       {
4733         char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4734
4735         if (value_cloned != NULL)
4736         {
4737           /* set default filename in static configuration */
4738           image_config[i].value = value_cloned;
4739
4740           /* set default filename in image config hash */
4741           setHashEntry(image_config_hash, token, value_cloned);
4742         }
4743       }
4744
4745       free(token_clone_from);
4746     }
4747   }
4748
4749   /* always start with reliable default values (all elements) */
4750   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4751     ActiveElement[i] = i;
4752
4753   /* now add all entries that have an active state (active elements) */
4754   for (i = 0; element_with_active_state[i].element != -1; i++)
4755   {
4756     int element = element_with_active_state[i].element;
4757     int element_active = element_with_active_state[i].element_active;
4758
4759     ActiveElement[element] = element_active;
4760   }
4761
4762   /* always start with reliable default values (all buttons) */
4763   for (i = 0; i < NUM_IMAGE_FILES; i++)
4764     ActiveButton[i] = i;
4765
4766   /* now add all entries that have an active state (active buttons) */
4767   for (i = 0; button_with_active_state[i].button != -1; i++)
4768   {
4769     int button = button_with_active_state[i].button;
4770     int button_active = button_with_active_state[i].button_active;
4771
4772     ActiveButton[button] = button_active;
4773   }
4774
4775   /* always start with reliable default values (all fonts) */
4776   for (i = 0; i < NUM_FONTS; i++)
4777     ActiveFont[i] = i;
4778
4779   /* now add all entries that have an active state (active fonts) */
4780   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4781   {
4782     int font = font_with_active_state[i].font_nr;
4783     int font_active = font_with_active_state[i].font_nr_active;
4784
4785     ActiveFont[font] = font_active;
4786   }
4787
4788   global.autoplay_leveldir = NULL;
4789   global.convert_leveldir = NULL;
4790   global.create_images_dir = NULL;
4791
4792   global.frames_per_second = 0;
4793
4794   global.border_status = GAME_MODE_LOADING;
4795   global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4796
4797   global.use_envelope_request = FALSE;
4798 }
4799
4800 void Execute_Command(char *command)
4801 {
4802   int i;
4803
4804   if (strEqual(command, "print graphicsinfo.conf"))
4805   {
4806     Print("# You can configure additional/alternative image files here.\n");
4807     Print("# (The entries below are default and therefore commented out.)\n");
4808     Print("\n");
4809     Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4810     Print("\n");
4811     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4812     Print("\n");
4813
4814     for (i = 0; image_config[i].token != NULL; i++)
4815       Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4816                                              image_config[i].value));
4817
4818     exit(0);
4819   }
4820   else if (strEqual(command, "print soundsinfo.conf"))
4821   {
4822     Print("# You can configure additional/alternative sound files here.\n");
4823     Print("# (The entries below are default and therefore commented out.)\n");
4824     Print("\n");
4825     Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4826     Print("\n");
4827     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4828     Print("\n");
4829
4830     for (i = 0; sound_config[i].token != NULL; i++)
4831       Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4832                                              sound_config[i].value));
4833
4834     exit(0);
4835   }
4836   else if (strEqual(command, "print musicinfo.conf"))
4837   {
4838     Print("# You can configure additional/alternative music files here.\n");
4839     Print("# (The entries below are default and therefore commented out.)\n");
4840     Print("\n");
4841     Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4842     Print("\n");
4843     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4844     Print("\n");
4845
4846     for (i = 0; music_config[i].token != NULL; i++)
4847       Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4848                                              music_config[i].value));
4849
4850     exit(0);
4851   }
4852   else if (strEqual(command, "print editorsetup.conf"))
4853   {
4854     Print("# You can configure your personal editor element list here.\n");
4855     Print("# (The entries below are default and therefore commented out.)\n");
4856     Print("\n");
4857
4858     /* this is needed to be able to check element list for cascade elements */
4859     InitElementPropertiesStatic();
4860     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4861
4862     PrintEditorElementList();
4863
4864     exit(0);
4865   }
4866   else if (strEqual(command, "print helpanim.conf"))
4867   {
4868     Print("# You can configure different element help animations here.\n");
4869     Print("# (The entries below are default and therefore commented out.)\n");
4870     Print("\n");
4871
4872     for (i = 0; helpanim_config[i].token != NULL; i++)
4873     {
4874       Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4875                                              helpanim_config[i].value));
4876
4877       if (strEqual(helpanim_config[i].token, "end"))
4878         Print("#\n");
4879     }
4880
4881     exit(0);
4882   }
4883   else if (strEqual(command, "print helptext.conf"))
4884   {
4885     Print("# You can configure different element help text here.\n");
4886     Print("# (The entries below are default and therefore commented out.)\n");
4887     Print("\n");
4888
4889     for (i = 0; helptext_config[i].token != NULL; i++)
4890       Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4891                                              helptext_config[i].value));
4892
4893     exit(0);
4894   }
4895   else if (strPrefix(command, "dump level "))
4896   {
4897     char *filename = &command[11];
4898
4899     if (!fileExists(filename))
4900       Error(ERR_EXIT, "cannot open file '%s'", filename);
4901
4902     LoadLevelFromFilename(&level, filename);
4903     DumpLevel(&level);
4904
4905     exit(0);
4906   }
4907   else if (strPrefix(command, "dump tape "))
4908   {
4909     char *filename = &command[10];
4910
4911     if (!fileExists(filename))
4912       Error(ERR_EXIT, "cannot open file '%s'", filename);
4913
4914     LoadTapeFromFilename(filename);
4915     DumpTape(&tape);
4916
4917     exit(0);
4918   }
4919   else if (strPrefix(command, "autotest ") ||
4920            strPrefix(command, "autoplay ") ||
4921            strPrefix(command, "autoffwd ") ||
4922            strPrefix(command, "autowarp "))
4923   {
4924     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4925
4926     global.autoplay_mode =
4927       (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
4928        strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
4929        strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
4930        strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
4931        AUTOPLAY_MODE_NONE);
4932
4933     while (*str_ptr != '\0')                    /* continue parsing string */
4934     {
4935       /* cut leading whitespace from string, replace it by string terminator */
4936       while (*str_ptr == ' ' || *str_ptr == '\t')
4937         *str_ptr++ = '\0';
4938
4939       if (*str_ptr == '\0')                     /* end of string reached */
4940         break;
4941
4942       if (global.autoplay_leveldir == NULL)     /* read level set string */
4943       {
4944         global.autoplay_leveldir = str_ptr;
4945         global.autoplay_all = TRUE;             /* default: play all tapes */
4946
4947         for (i = 0; i < MAX_TAPES_PER_SET; i++)
4948           global.autoplay_level[i] = FALSE;
4949       }
4950       else                                      /* read level number string */
4951       {
4952         int level_nr = atoi(str_ptr);           /* get level_nr value */
4953
4954         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4955           global.autoplay_level[level_nr] = TRUE;
4956
4957         global.autoplay_all = FALSE;
4958       }
4959
4960       /* advance string pointer to the next whitespace (or end of string) */
4961       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4962         str_ptr++;
4963     }
4964   }
4965   else if (strPrefix(command, "convert "))
4966   {
4967     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4968     char *str_ptr = strchr(str_copy, ' ');
4969
4970     global.convert_leveldir = str_copy;
4971     global.convert_level_nr = -1;
4972
4973     if (str_ptr != NULL)                        /* level number follows */
4974     {
4975       *str_ptr++ = '\0';                        /* terminate leveldir string */
4976       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
4977     }
4978   }
4979   else if (strPrefix(command, "create images "))
4980   {
4981     global.create_images_dir = getStringCopy(&command[14]);
4982
4983     if (access(global.create_images_dir, W_OK) != 0)
4984       Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4985             global.create_images_dir);
4986   }
4987   else if (strPrefix(command, "create CE image "))
4988   {
4989     CreateCustomElementImages(&command[16]);
4990
4991     exit(0);
4992   }
4993   else
4994   {
4995     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4996   }
4997 }
4998
4999 static void InitSetup()
5000 {
5001   LoadSetup();                                  /* global setup info */
5002
5003   /* set some options from setup file */
5004
5005   if (setup.options.verbose)
5006     options.verbose = TRUE;
5007 }
5008
5009 static void InitGameInfo()
5010 {
5011   game.restart_level = FALSE;
5012 }
5013
5014 static void InitPlayerInfo()
5015 {
5016   int i;
5017
5018   /* choose default local player */
5019   local_player = &stored_player[0];
5020
5021   for (i = 0; i < MAX_PLAYERS; i++)
5022     stored_player[i].connected = FALSE;
5023
5024   local_player->connected = TRUE;
5025 }
5026
5027 static void InitArtworkInfo()
5028 {
5029   LoadArtworkInfo();
5030 }
5031
5032 static char *get_string_in_brackets(char *string)
5033 {
5034   char *string_in_brackets = checked_malloc(strlen(string) + 3);
5035
5036   sprintf(string_in_brackets, "[%s]", string);
5037
5038   return string_in_brackets;
5039 }
5040
5041 static char *get_level_id_suffix(int id_nr)
5042 {
5043   char *id_suffix = checked_malloc(1 + 3 + 1);
5044
5045   if (id_nr < 0 || id_nr > 999)
5046     id_nr = 0;
5047
5048   sprintf(id_suffix, ".%03d", id_nr);
5049
5050   return id_suffix;
5051 }
5052
5053 static void InitArtworkConfig()
5054 {
5055   static char *image_id_prefix[MAX_NUM_ELEMENTS +
5056                                NUM_FONTS +
5057                                NUM_GLOBAL_ANIM_TOKENS + 1];
5058   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
5059                                NUM_GLOBAL_ANIM_TOKENS + 1];
5060   static char *music_id_prefix[NUM_MUSIC_PREFIXES +
5061                                NUM_GLOBAL_ANIM_TOKENS + 1];
5062   static char *action_id_suffix[NUM_ACTIONS + 1];
5063   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
5064   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
5065   static char *level_id_suffix[MAX_LEVELS + 1];
5066   static char *dummy[1] = { NULL };
5067   static char *ignore_generic_tokens[] =
5068   {
5069     "name",
5070     "sort_priority",
5071     NULL
5072   };
5073   static char **ignore_image_tokens;
5074   static char **ignore_sound_tokens;
5075   static char **ignore_music_tokens;
5076   int num_ignore_generic_tokens;
5077   int num_ignore_image_tokens;
5078   int num_ignore_sound_tokens;
5079   int num_ignore_music_tokens;
5080   int i;
5081
5082   /* dynamically determine list of generic tokens to be ignored */
5083   num_ignore_generic_tokens = 0;
5084   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5085     num_ignore_generic_tokens++;
5086
5087   /* dynamically determine list of image tokens to be ignored */
5088   num_ignore_image_tokens = num_ignore_generic_tokens;
5089   for (i = 0; image_config_vars[i].token != NULL; i++)
5090     num_ignore_image_tokens++;
5091   ignore_image_tokens =
5092     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5093   for (i = 0; i < num_ignore_generic_tokens; i++)
5094     ignore_image_tokens[i] = ignore_generic_tokens[i];
5095   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5096     ignore_image_tokens[num_ignore_generic_tokens + i] =
5097       image_config_vars[i].token;
5098   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5099
5100   /* dynamically determine list of sound tokens to be ignored */
5101   num_ignore_sound_tokens = num_ignore_generic_tokens;
5102   ignore_sound_tokens =
5103     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5104   for (i = 0; i < num_ignore_generic_tokens; i++)
5105     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5106   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5107
5108   /* dynamically determine list of music tokens to be ignored */
5109   num_ignore_music_tokens = num_ignore_generic_tokens;
5110   ignore_music_tokens =
5111     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5112   for (i = 0; i < num_ignore_generic_tokens; i++)
5113     ignore_music_tokens[i] = ignore_generic_tokens[i];
5114   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5115
5116   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5117     image_id_prefix[i] = element_info[i].token_name;
5118   for (i = 0; i < NUM_FONTS; i++)
5119     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5120   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5121     image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5122       global_anim_info[i].token_name;
5123   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5124
5125   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5126     sound_id_prefix[i] = element_info[i].token_name;
5127   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5128     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5129       get_string_in_brackets(element_info[i].class_name);
5130   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5131     sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5132       global_anim_info[i].token_name;
5133   sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5134
5135   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5136     music_id_prefix[i] = music_prefix_info[i].prefix;
5137   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5138     music_id_prefix[NUM_MUSIC_PREFIXES + i] =
5139       global_anim_info[i].token_name;
5140   music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5141
5142   for (i = 0; i < NUM_ACTIONS; i++)
5143     action_id_suffix[i] = element_action_info[i].suffix;
5144   action_id_suffix[NUM_ACTIONS] = NULL;
5145
5146   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5147     direction_id_suffix[i] = element_direction_info[i].suffix;
5148   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5149
5150   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5151     special_id_suffix[i] = special_suffix_info[i].suffix;
5152   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5153
5154   for (i = 0; i < MAX_LEVELS; i++)
5155     level_id_suffix[i] = get_level_id_suffix(i);
5156   level_id_suffix[MAX_LEVELS] = NULL;
5157
5158   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5159                 image_id_prefix, action_id_suffix, direction_id_suffix,
5160                 special_id_suffix, ignore_image_tokens);
5161   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5162                 sound_id_prefix, action_id_suffix, dummy,
5163                 special_id_suffix, ignore_sound_tokens);
5164   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5165                 music_id_prefix, action_id_suffix, special_id_suffix,
5166                 level_id_suffix, ignore_music_tokens);
5167 }
5168
5169 static void InitMixer()
5170 {
5171   OpenAudio();
5172
5173   StartMixer();
5174 }
5175
5176 void InitGfxBuffers()
5177 {
5178   static int win_xsize_last = -1;
5179   static int win_ysize_last = -1;
5180
5181   /* create additional image buffers for double-buffering and cross-fading */
5182
5183   if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5184   {
5185     /* used to temporarily store the backbuffer -- only re-create if changed */
5186     ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
5187     ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
5188
5189     win_xsize_last = WIN_XSIZE;
5190     win_ysize_last = WIN_YSIZE;
5191   }
5192
5193   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
5194   ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
5195   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
5196   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
5197
5198   /* initialize screen properties */
5199   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5200                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5201                    bitmap_db_field);
5202   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5203   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5204   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5205   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5206   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5207   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5208
5209   /* required if door size definitions have changed */
5210   InitGraphicCompatibilityInfo_Doors();
5211
5212   InitGfxBuffers_EM();
5213   InitGfxBuffers_SP();
5214 }
5215
5216 void InitGfx()
5217 {
5218   struct GraphicInfo *graphic_info_last = graphic_info;
5219   char *filename_font_initial = NULL;
5220   char *filename_anim_initial = NULL;
5221   Bitmap *bitmap_font_initial = NULL;
5222   int font_height;
5223   int i, j;
5224
5225   /* determine settings for initial font (for displaying startup messages) */
5226   for (i = 0; image_config[i].token != NULL; i++)
5227   {
5228     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5229     {
5230       char font_token[128];
5231       int len_font_token;
5232
5233       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5234       len_font_token = strlen(font_token);
5235
5236       if (strEqual(image_config[i].token, font_token))
5237         filename_font_initial = image_config[i].value;
5238       else if (strlen(image_config[i].token) > len_font_token &&
5239                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5240       {
5241         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5242           font_initial[j].src_x = atoi(image_config[i].value);
5243         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5244           font_initial[j].src_y = atoi(image_config[i].value);
5245         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5246           font_initial[j].width = atoi(image_config[i].value);
5247         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5248           font_initial[j].height = atoi(image_config[i].value);
5249       }
5250     }
5251   }
5252
5253   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5254   {
5255     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5256     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5257   }
5258
5259   if (filename_font_initial == NULL)    /* should not happen */
5260     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5261
5262   InitGfxBuffers();
5263   InitGfxCustomArtworkInfo();
5264   InitGfxOtherSettings();
5265
5266   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5267
5268   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5269     font_initial[j].bitmap = bitmap_font_initial;
5270
5271   InitFontGraphicInfo();
5272
5273   font_height = getFontHeight(FC_RED);
5274
5275   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5276   DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5277   DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5278                FC_RED);
5279
5280   DrawInitText("Loading graphics", 120, FC_GREEN);
5281
5282   /* initialize settings for busy animation with default values */
5283   int parameter[NUM_GFX_ARGS];
5284   for (i = 0; i < NUM_GFX_ARGS; i++)
5285     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5286                                                image_config_suffix[i].token,
5287                                                image_config_suffix[i].type);
5288
5289   char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5290   int len_anim_token = strlen(anim_token);
5291
5292   /* read settings for busy animation from default custom artwork config */
5293   char *gfx_config_filename = getPath3(options.graphics_directory,
5294                                        GFX_DEFAULT_SUBDIR,
5295                                        GRAPHICSINFO_FILENAME);
5296
5297   if (fileExists(gfx_config_filename))
5298   {
5299     SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5300
5301     if (setup_file_hash)
5302     {
5303       char *filename = getHashEntry(setup_file_hash, anim_token);
5304
5305       if (filename)
5306       {
5307         filename_anim_initial = getStringCopy(filename);
5308
5309         for (j = 0; image_config_suffix[j].token != NULL; j++)
5310         {
5311           int type = image_config_suffix[j].type;
5312           char *suffix = image_config_suffix[j].token;
5313           char *token = getStringCat2(anim_token, suffix);
5314           char *value = getHashEntry(setup_file_hash, token);
5315
5316           checked_free(token);
5317
5318           if (value)
5319             parameter[j] = get_graphic_parameter_value(value, suffix, type);
5320         }
5321       }
5322
5323       freeSetupFileHash(setup_file_hash);
5324     }
5325   }
5326
5327   if (filename_anim_initial == NULL)
5328   {
5329     /* read settings for busy animation from static default artwork config */
5330     for (i = 0; image_config[i].token != NULL; i++)
5331     {
5332       if (strEqual(image_config[i].token, anim_token))
5333         filename_anim_initial = getStringCopy(image_config[i].value);
5334       else if (strlen(image_config[i].token) > len_anim_token &&
5335                strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5336       {
5337         for (j = 0; image_config_suffix[j].token != NULL; j++)
5338         {
5339           if (strEqual(&image_config[i].token[len_anim_token],
5340                        image_config_suffix[j].token))
5341             parameter[j] =
5342               get_graphic_parameter_value(image_config[i].value,
5343                                           image_config_suffix[j].token,
5344                                           image_config_suffix[j].type);
5345         }
5346       }
5347     }
5348   }
5349
5350   if (filename_anim_initial == NULL)    /* should not happen */
5351     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5352
5353   anim_initial.bitmaps =
5354     checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5355
5356   anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5357     LoadCustomImage(filename_anim_initial);
5358
5359   checked_free(filename_anim_initial);
5360
5361   graphic_info = &anim_initial;         /* graphic == 0 => anim_initial */
5362
5363   set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5364
5365   graphic_info = graphic_info_last;
5366
5367   init.busy.width  = anim_initial.width;
5368   init.busy.height = anim_initial.height;
5369
5370   InitMenuDesignSettings_Static();
5371
5372   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5373   InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
5374   InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5375
5376   gfx.fade_border_source_status = global.border_status;
5377   gfx.fade_border_target_status = global.border_status;
5378   gfx.masked_border_bitmap_ptr = backbuffer;
5379
5380   /* use copy of busy animation to prevent change while reloading artwork */
5381   init_last = init;
5382 }
5383
5384 void InitGfxBackground()
5385 {
5386   fieldbuffer = bitmap_db_field;
5387   SetDrawtoField(DRAW_TO_BACKBUFFER);
5388
5389   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5390
5391   redraw_mask = REDRAW_ALL;
5392 }
5393
5394 static void InitLevelInfo()
5395 {
5396   LoadLevelInfo();                              /* global level info */
5397   LoadLevelSetup_LastSeries();                  /* last played series info */
5398   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5399
5400   if (global.autoplay_leveldir &&
5401       global.autoplay_mode != AUTOPLAY_MODE_TEST)
5402   {
5403     leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5404                                                  global.autoplay_leveldir);
5405     if (leveldir_current == NULL)
5406       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5407   }
5408 }
5409
5410 static void InitLevelArtworkInfo()
5411 {
5412   LoadLevelArtworkInfo();
5413 }
5414
5415 static void InitImages()
5416 {
5417   print_timestamp_init("InitImages");
5418
5419 #if 0
5420   printf("::: leveldir_current->identifier == '%s'\n",
5421          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5422   printf("::: leveldir_current->graphics_path == '%s'\n",
5423          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5424   printf("::: leveldir_current->graphics_set == '%s'\n",
5425          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5426   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5427          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5428 #endif
5429
5430   setLevelArtworkDir(artwork.gfx_first);
5431
5432 #if 0
5433   printf("::: leveldir_current->identifier == '%s'\n",
5434          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5435   printf("::: leveldir_current->graphics_path == '%s'\n",
5436          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5437   printf("::: leveldir_current->graphics_set == '%s'\n",
5438          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5439   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5440          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5441 #endif
5442
5443 #if 0
5444   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5445          leveldir_current->identifier,
5446          artwork.gfx_current_identifier,
5447          artwork.gfx_current->identifier,
5448          leveldir_current->graphics_set,
5449          leveldir_current->graphics_path);
5450 #endif
5451
5452   UPDATE_BUSY_STATE();
5453
5454   ReloadCustomImages();
5455   print_timestamp_time("ReloadCustomImages");
5456
5457   UPDATE_BUSY_STATE();
5458
5459   LoadCustomElementDescriptions();
5460   print_timestamp_time("LoadCustomElementDescriptions");
5461
5462   UPDATE_BUSY_STATE();
5463
5464   LoadMenuDesignSettings();
5465   print_timestamp_time("LoadMenuDesignSettings");
5466
5467   UPDATE_BUSY_STATE();
5468
5469   ReinitializeGraphics();
5470   print_timestamp_time("ReinitializeGraphics");
5471
5472   LoadMenuDesignSettings_AfterGraphics();
5473   print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
5474
5475   UPDATE_BUSY_STATE();
5476
5477   print_timestamp_done("InitImages");
5478 }
5479
5480 static void InitSound(char *identifier)
5481 {
5482   print_timestamp_init("InitSound");
5483
5484   if (identifier == NULL)
5485     identifier = artwork.snd_current->identifier;
5486
5487   /* set artwork path to send it to the sound server process */
5488   setLevelArtworkDir(artwork.snd_first);
5489
5490   InitReloadCustomSounds(identifier);
5491   print_timestamp_time("InitReloadCustomSounds");
5492
5493   ReinitializeSounds();
5494   print_timestamp_time("ReinitializeSounds");
5495
5496   print_timestamp_done("InitSound");
5497 }
5498
5499 static void InitMusic(char *identifier)
5500 {
5501   print_timestamp_init("InitMusic");
5502
5503   if (identifier == NULL)
5504     identifier = artwork.mus_current->identifier;
5505
5506   /* set artwork path to send it to the sound server process */
5507   setLevelArtworkDir(artwork.mus_first);
5508
5509   InitReloadCustomMusic(identifier);
5510   print_timestamp_time("InitReloadCustomMusic");
5511
5512   ReinitializeMusic();
5513   print_timestamp_time("ReinitializeMusic");
5514
5515   print_timestamp_done("InitMusic");
5516 }
5517
5518 static void InitArtworkDone()
5519 {
5520   InitGlobalAnimations();
5521 }
5522
5523 void InitNetworkServer()
5524 {
5525 #if defined(NETWORK_AVALIABLE)
5526   int nr_wanted;
5527 #endif
5528
5529   if (!options.network)
5530     return;
5531
5532 #if defined(NETWORK_AVALIABLE)
5533   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5534
5535   if (!ConnectToServer(options.server_host, options.server_port))
5536     Error(ERR_EXIT, "cannot connect to network game server");
5537
5538   SendToServer_PlayerName(setup.player_name);
5539   SendToServer_ProtocolVersion();
5540
5541   if (nr_wanted)
5542     SendToServer_NrWanted(nr_wanted);
5543 #endif
5544 }
5545
5546 static boolean CheckArtworkConfigForCustomElements(char *filename)
5547 {
5548   SetupFileHash *setup_file_hash;
5549   boolean redefined_ce_found = FALSE;
5550
5551   /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5552
5553   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5554   {
5555     BEGIN_HASH_ITERATION(setup_file_hash, itr)
5556     {
5557       char *token = HASH_ITERATION_TOKEN(itr);
5558
5559       if (strPrefix(token, "custom_"))
5560       {
5561         redefined_ce_found = TRUE;
5562
5563         break;
5564       }
5565     }
5566     END_HASH_ITERATION(setup_file_hash, itr)
5567
5568     freeSetupFileHash(setup_file_hash);
5569   }
5570
5571   return redefined_ce_found;
5572 }
5573
5574 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5575 {
5576   char *filename_base, *filename_local;
5577   boolean redefined_ce_found = FALSE;
5578
5579   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5580
5581 #if 0
5582   printf("::: leveldir_current->identifier == '%s'\n",
5583          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5584   printf("::: leveldir_current->graphics_path == '%s'\n",
5585          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5586   printf("::: leveldir_current->graphics_set == '%s'\n",
5587          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5588   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5589          leveldir_current == NULL ? "[NULL]" :
5590          LEVELDIR_ARTWORK_SET(leveldir_current, type));
5591 #endif
5592
5593   /* first look for special artwork configured in level series config */
5594   filename_base = getCustomArtworkLevelConfigFilename(type);
5595
5596 #if 0
5597   printf("::: filename_base == '%s'\n", filename_base);
5598 #endif
5599
5600   if (fileExists(filename_base))
5601     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5602
5603   filename_local = getCustomArtworkConfigFilename(type);
5604
5605 #if 0
5606   printf("::: filename_local == '%s'\n", filename_local);
5607 #endif
5608
5609   if (filename_local != NULL && !strEqual(filename_base, filename_local))
5610     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5611
5612 #if 0
5613   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5614 #endif
5615
5616   return redefined_ce_found;
5617 }
5618
5619 static void InitOverrideArtwork()
5620 {
5621   boolean redefined_ce_found = FALSE;
5622
5623   /* to check if this level set redefines any CEs, do not use overriding */
5624   gfx.override_level_graphics = FALSE;
5625   gfx.override_level_sounds   = FALSE;
5626   gfx.override_level_music    = FALSE;
5627
5628   /* now check if this level set has definitions for custom elements */
5629   if (setup.override_level_graphics == AUTO ||
5630       setup.override_level_sounds   == AUTO ||
5631       setup.override_level_music    == AUTO)
5632     redefined_ce_found =
5633       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5634        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5635        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5636
5637 #if 0
5638   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5639 #endif
5640
5641   if (redefined_ce_found)
5642   {
5643     /* this level set has CE definitions: change "AUTO" to "FALSE" */
5644     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5645     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
5646     gfx.override_level_music    = (setup.override_level_music    == TRUE);
5647   }
5648   else
5649   {
5650     /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5651     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5652     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
5653     gfx.override_level_music    = (setup.override_level_music    != FALSE);
5654   }
5655
5656 #if 0
5657   printf("::: => %d, %d, %d\n",
5658          gfx.override_level_graphics,
5659          gfx.override_level_sounds,
5660          gfx.override_level_music);
5661 #endif
5662 }
5663
5664 static char *getNewArtworkIdentifier(int type)
5665 {
5666   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5667   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5668   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5669   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5670   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5671   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5672   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5673   char *leveldir_identifier = leveldir_current->identifier;
5674   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5675   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5676   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5677   char *artwork_current_identifier;
5678   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
5679
5680   /* leveldir_current may be invalid (level group, parent link) */
5681   if (!validLevelSeries(leveldir_current))
5682     return NULL;
5683
5684   /* 1st step: determine artwork set to be activated in descending order:
5685      --------------------------------------------------------------------
5686      1. setup artwork (when configured to override everything else)
5687      2. artwork set configured in "levelinfo.conf" of current level set
5688         (artwork in level directory will have priority when loading later)
5689      3. artwork in level directory (stored in artwork sub-directory)
5690      4. setup artwork (currently configured in setup menu) */
5691
5692   if (setup_override_artwork)
5693     artwork_current_identifier = setup_artwork_set;
5694   else if (leveldir_artwork_set != NULL)
5695     artwork_current_identifier = leveldir_artwork_set;
5696   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5697     artwork_current_identifier = leveldir_identifier;
5698   else
5699     artwork_current_identifier = setup_artwork_set;
5700
5701
5702   /* 2nd step: check if it is really needed to reload artwork set
5703      ------------------------------------------------------------ */
5704
5705   /* ---------- reload if level set and also artwork set has changed ------- */
5706   if (leveldir_current_identifier[type] != leveldir_identifier &&
5707       (last_has_level_artwork_set[type] || has_level_artwork_set))
5708     artwork_new_identifier = artwork_current_identifier;
5709
5710   leveldir_current_identifier[type] = leveldir_identifier;
5711   last_has_level_artwork_set[type] = has_level_artwork_set;
5712
5713   /* ---------- reload if "override artwork" setting has changed ----------- */
5714   if (last_override_level_artwork[type] != setup_override_artwork)
5715     artwork_new_identifier = artwork_current_identifier;
5716
5717   last_override_level_artwork[type] = setup_override_artwork;
5718
5719   /* ---------- reload if current artwork identifier has changed ----------- */
5720   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5721                 artwork_current_identifier))
5722     artwork_new_identifier = artwork_current_identifier;
5723
5724   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5725
5726   /* ---------- do not reload directly after starting ---------------------- */
5727   if (!initialized[type])
5728     artwork_new_identifier = NULL;
5729
5730   initialized[type] = TRUE;
5731
5732   return artwork_new_identifier;
5733 }
5734
5735 void ReloadCustomArtwork(int force_reload)
5736 {
5737   int last_game_status = game_status;   /* save current game status */
5738   char *gfx_new_identifier;
5739   char *snd_new_identifier;
5740   char *mus_new_identifier;
5741   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5742   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5743   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5744   boolean reload_needed;
5745
5746   InitOverrideArtwork();
5747
5748   force_reload_gfx |= AdjustGraphicsForEMC();
5749
5750   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5751   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5752   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5753
5754   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5755                    snd_new_identifier != NULL || force_reload_snd ||
5756                    mus_new_identifier != NULL || force_reload_mus);
5757
5758   if (!reload_needed)
5759     return;
5760
5761   print_timestamp_init("ReloadCustomArtwork");
5762
5763   SetGameStatus(GAME_MODE_LOADING);
5764
5765   FadeOut(REDRAW_ALL);
5766
5767   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5768   print_timestamp_time("ClearRectangle");
5769
5770   FadeIn(REDRAW_ALL);
5771
5772   if (gfx_new_identifier != NULL || force_reload_gfx)
5773   {
5774 #if 0
5775     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5776            artwork.gfx_current_identifier,
5777            gfx_new_identifier,
5778            artwork.gfx_current->identifier,
5779            leveldir_current->graphics_set);
5780 #endif
5781
5782     InitImages();
5783     print_timestamp_time("InitImages");
5784   }
5785
5786   if (snd_new_identifier != NULL || force_reload_snd)
5787   {
5788     InitSound(snd_new_identifier);
5789     print_timestamp_time("InitSound");
5790   }
5791
5792   if (mus_new_identifier != NULL || force_reload_mus)
5793   {
5794     InitMusic(mus_new_identifier);
5795     print_timestamp_time("InitMusic");
5796   }
5797
5798   InitArtworkDone();
5799
5800   SetGameStatus(last_game_status);      /* restore current game status */
5801
5802   init_last = init;                     /* switch to new busy animation */
5803
5804   FadeOut(REDRAW_ALL);
5805
5806   RedrawGlobalBorder();
5807
5808   /* force redraw of (open or closed) door graphics */
5809   SetDoorState(DOOR_OPEN_ALL);
5810   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5811
5812   FadeSetEnterScreen();
5813   FadeSkipNextFadeOut();
5814
5815   print_timestamp_done("ReloadCustomArtwork");
5816
5817   LimitScreenUpdates(FALSE);
5818 }
5819
5820 void KeyboardAutoRepeatOffUnlessAutoplay()
5821 {
5822   if (global.autoplay_leveldir == NULL)
5823     KeyboardAutoRepeatOff();
5824 }
5825
5826 void DisplayExitMessage(char *format, va_list ap)
5827 {
5828   // check if draw buffer and fonts for exit message are already available
5829   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5830     return;
5831
5832   int font_1 = FC_RED;
5833   int font_2 = FC_YELLOW;
5834   int font_3 = FC_BLUE;
5835   int font_width = getFontWidth(font_2);
5836   int font_height = getFontHeight(font_2);
5837   int sx = SX;
5838   int sy = SY;
5839   int sxsize = WIN_XSIZE - 2 * sx;
5840   int sysize = WIN_YSIZE - 2 * sy;
5841   int line_length = sxsize / font_width;
5842   int max_lines = sysize / font_height;
5843   int num_lines_printed;
5844
5845   gfx.sx = sx;
5846   gfx.sy = sy;
5847   gfx.sxsize = sxsize;
5848   gfx.sysize = sysize;
5849
5850   sy = 20;
5851
5852   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5853
5854   DrawTextSCentered(sy, font_1, "Fatal error:");
5855   sy += 3 * font_height;;
5856
5857   num_lines_printed =
5858     DrawTextBufferVA(sx, sy, format, ap, font_2,
5859                      line_length, line_length, max_lines,
5860                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5861   sy += (num_lines_printed + 3) * font_height;
5862
5863   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5864   sy += 3 * font_height;
5865
5866   num_lines_printed =
5867     DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5868                    line_length, line_length, max_lines,
5869                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5870
5871   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5872
5873   redraw_mask = REDRAW_ALL;
5874
5875   /* force drawing exit message even if screen updates are currently limited */
5876   LimitScreenUpdates(FALSE);
5877
5878   BackToFront();
5879
5880   /* deactivate toons on error message screen */
5881   setup.toons = FALSE;
5882
5883   WaitForEventToContinue();
5884 }
5885
5886
5887 /* ========================================================================= */
5888 /* OpenAll()                                                                 */
5889 /* ========================================================================= */
5890
5891 void OpenAll()
5892 {
5893   print_timestamp_init("OpenAll");
5894
5895   SetGameStatus(GAME_MODE_LOADING);
5896
5897   InitCounter();
5898
5899   InitGlobal();                 /* initialize some global variables */
5900
5901   print_timestamp_time("[init global stuff]");
5902
5903   InitSetup();
5904
5905   print_timestamp_time("[init setup/config stuff (1)]");
5906
5907   InitScoresInfo();
5908
5909   if (options.execute_command)
5910     Execute_Command(options.execute_command);
5911
5912   if (options.serveronly)
5913   {
5914 #if defined(PLATFORM_UNIX)
5915     NetworkServer(options.server_port, options.serveronly);
5916 #else
5917     Error(ERR_WARN, "networking only supported in Unix version");
5918 #endif
5919
5920     exit(0);                    /* never reached, server loops forever */
5921   }
5922
5923   InitGameInfo();
5924   print_timestamp_time("[init setup/config stuff (2)]");
5925   InitPlayerInfo();
5926   print_timestamp_time("[init setup/config stuff (3)]");
5927   InitArtworkInfo();            /* needed before loading gfx, sound & music */
5928   print_timestamp_time("[init setup/config stuff (4)]");
5929   InitArtworkConfig();          /* needed before forking sound child process */
5930   print_timestamp_time("[init setup/config stuff (5)]");
5931   InitMixer();
5932   print_timestamp_time("[init setup/config stuff (6)]");
5933
5934   InitRND(NEW_RANDOMIZE);
5935   InitSimpleRandom(NEW_RANDOMIZE);
5936
5937   InitJoysticks();
5938
5939   print_timestamp_time("[init setup/config stuff]");
5940
5941   InitVideoDisplay();
5942   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5943
5944   InitOverlayInfo();
5945
5946   print_timestamp_time("[init video stuff]");
5947
5948   InitElementPropertiesStatic();
5949   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5950   InitElementPropertiesGfxElement();
5951
5952   print_timestamp_time("[init element properties stuff]");
5953
5954   InitGfx();
5955
5956   print_timestamp_time("InitGfx");
5957
5958   InitLevelInfo();
5959   print_timestamp_time("InitLevelInfo");
5960
5961   InitLevelArtworkInfo();
5962   print_timestamp_time("InitLevelArtworkInfo");
5963
5964   InitOverrideArtwork();        /* needs to know current level directory */
5965   print_timestamp_time("InitOverrideArtwork");
5966
5967   InitImages();                 /* needs to know current level directory */
5968   print_timestamp_time("InitImages");
5969
5970   InitSound(NULL);              /* needs to know current level directory */
5971   print_timestamp_time("InitSound");
5972
5973   InitMusic(NULL);              /* needs to know current level directory */
5974   print_timestamp_time("InitMusic");
5975
5976   InitArtworkDone();
5977
5978   InitGfxBackground();
5979
5980   em_open_all();
5981   sp_open_all();
5982
5983   if (global.autoplay_leveldir)
5984   {
5985     AutoPlayTape();
5986     return;
5987   }
5988   else if (global.convert_leveldir)
5989   {
5990     ConvertLevels();
5991     return;
5992   }
5993   else if (global.create_images_dir)
5994   {
5995     CreateLevelSketchImages();
5996     return;
5997   }
5998
5999   SetGameStatus(GAME_MODE_MAIN);
6000
6001   FadeSetEnterScreen();
6002   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
6003     FadeSkipNextFadeOut();
6004
6005   print_timestamp_time("[post-artwork]");
6006
6007   print_timestamp_done("OpenAll");
6008
6009   DrawMainMenu();
6010
6011   InitNetworkServer();
6012
6013 #if 0
6014   Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
6015         SDL_GetBasePath());
6016   Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
6017         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
6018 #if defined(PLATFORM_ANDROID)
6019   Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
6020         SDL_AndroidGetInternalStoragePath());
6021   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
6022         SDL_AndroidGetExternalStoragePath());
6023   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
6024         (SDL_AndroidGetExternalStorageState() ==
6025          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
6026          SDL_AndroidGetExternalStorageState() ==
6027          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
6028 #endif
6029 #endif
6030 }
6031
6032 void CloseAllAndExit(int exit_value)
6033 {
6034   StopSounds();
6035   FreeAllSounds();
6036   FreeAllMusic();
6037   CloseAudio();         /* called after freeing sounds (needed for SDL) */
6038
6039   em_close_all();
6040   sp_close_all();
6041
6042   FreeAllImages();
6043
6044 #if defined(TARGET_SDL)
6045 #if defined(TARGET_SDL2)
6046   // !!! TODO !!!
6047   // set a flag to tell the network server thread to quit and wait for it
6048   // using SDL_WaitThread()
6049 #else
6050   if (network_server)   /* terminate network server */
6051     SDL_KillThread(server_thread);
6052 #endif
6053 #endif
6054
6055   CloseVideoDisplay();
6056   ClosePlatformDependentStuff();
6057
6058   if (exit_value != 0)
6059   {
6060     /* fall back to default level set (current set may have caused an error) */
6061     SaveLevelSetup_LastSeries_Deactivate();
6062
6063     /* tell user where to find error log file which may contain more details */
6064     // (error notification now directly displayed on screen inside R'n'D
6065     // NotifyUserAboutErrorFile();      /* currently only works for Windows */
6066   }
6067
6068   exit(exit_value);
6069 }