added first version of simple click events for global animations
[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->init_event = ANIM_EVENT_DEFAULT;
1262   g->anim_event = ANIM_EVENT_DEFAULT;
1263   g->draw_order = 0;
1264   g->fade_mode = FADE_MODE_DEFAULT;
1265   g->fade_delay = -1;
1266   g->post_delay = -1;
1267   g->auto_delay = -1;
1268   g->align = ALIGN_CENTER;              /* default for title screens */
1269   g->valign = VALIGN_MIDDLE;            /* default for title screens */
1270   g->sort_priority = 0;                 /* default for title screens */
1271   g->class = 0;
1272   g->style = STYLE_DEFAULT;
1273
1274   g->bitmaps = src_bitmaps;
1275   g->bitmap = src_bitmap;
1276
1277   /* optional zoom factor for scaling up the image to a larger size */
1278   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1279     g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1280   if (g->scale_up_factor < 1)
1281     g->scale_up_factor = 1;             /* no scaling */
1282
1283   /* optional tile size for using non-standard image size */
1284   if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1285   {
1286     g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1287
1288 #if 0
1289     // CHECK: should tile sizes less than standard tile size be allowed?
1290     if (g->tile_size < TILESIZE)
1291       g->tile_size = TILESIZE;          /* standard tile size */
1292 #endif
1293
1294     // when setting tile size, also set width and height accordingly
1295     g->width  = g->tile_size;
1296     g->height = g->tile_size;
1297   }
1298
1299   if (g->use_image_size)
1300   {
1301     /* set new default bitmap size (with scaling, but without small images) */
1302     g->width  = get_scaled_graphic_width(graphic);
1303     g->height = get_scaled_graphic_height(graphic);
1304   }
1305
1306   /* optional width and height of each animation frame */
1307   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1308     g->width = parameter[GFX_ARG_WIDTH];
1309   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1310     g->height = parameter[GFX_ARG_HEIGHT];
1311
1312   /* optional x and y tile position of animation frame sequence */
1313   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1314     g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1315   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1316     g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1317
1318   /* optional x and y pixel position of animation frame sequence */
1319   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1320     g->src_x = parameter[GFX_ARG_X];
1321   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1322     g->src_y = parameter[GFX_ARG_Y];
1323
1324   if (src_bitmap)
1325   {
1326     if (g->width <= 0)
1327     {
1328       Error(ERR_INFO_LINE, "-");
1329       Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1330             g->width, getTokenFromImageID(graphic), TILEX);
1331       Error(ERR_INFO_LINE, "-");
1332
1333       g->width = TILEX;         /* will be checked to be inside bitmap later */
1334     }
1335
1336     if (g->height <= 0)
1337     {
1338       Error(ERR_INFO_LINE, "-");
1339       Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1340             g->height, getTokenFromImageID(graphic), TILEY);
1341       Error(ERR_INFO_LINE, "-");
1342
1343       g->height = TILEY;        /* will be checked to be inside bitmap later */
1344     }
1345   }
1346
1347   if (src_bitmap)
1348   {
1349     /* get final bitmap size (with scaling, but without small images) */
1350     int src_image_width  = get_scaled_graphic_width(graphic);
1351     int src_image_height = get_scaled_graphic_height(graphic);
1352
1353     if (src_image_width == 0 || src_image_height == 0)
1354     {
1355       /* only happens when loaded outside artwork system (like "global.busy") */
1356       src_image_width  = src_bitmap->width;
1357       src_image_height = src_bitmap->height;
1358     }
1359
1360     if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1361     {
1362       anim_frames_per_row = MAX(1, src_image_width  / g->tile_size);
1363       anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
1364     }
1365     else
1366     {
1367       anim_frames_per_row = MAX(1, src_image_width  / g->width);
1368       anim_frames_per_col = MAX(1, src_image_height / g->height);
1369     }
1370
1371     g->src_image_width  = src_image_width;
1372     g->src_image_height = src_image_height;
1373   }
1374
1375   /* correct x or y offset dependent of vertical or horizontal frame order */
1376   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1377   {
1378     g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1379                    parameter[GFX_ARG_OFFSET] : g->height);
1380     anim_frames_per_line = anim_frames_per_col;
1381   }
1382   else                                  /* frames are ordered horizontally */
1383   {
1384     g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1385                    parameter[GFX_ARG_OFFSET] : g->width);
1386     anim_frames_per_line = anim_frames_per_row;
1387   }
1388
1389   /* optionally, the x and y offset of frames can be specified directly */
1390   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1391     g->offset_x = parameter[GFX_ARG_XOFFSET];
1392   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1393     g->offset_y = parameter[GFX_ARG_YOFFSET];
1394
1395   /* optionally, moving animations may have separate start and end graphics */
1396   g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1397
1398   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1399     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1400
1401   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1402   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1403     g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1404                     parameter[GFX_ARG_2ND_OFFSET] : g->height);
1405   else                                  /* frames are ordered horizontally */
1406     g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1407                     parameter[GFX_ARG_2ND_OFFSET] : g->width);
1408
1409   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1410   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1411     g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1412   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1413     g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1414
1415   /* optionally, the second movement tile can be specified as start tile */
1416   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1417     g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1418
1419   /* automatically determine correct number of frames, if not defined */
1420   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1421     g->anim_frames = parameter[GFX_ARG_FRAMES];
1422   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1423     g->anim_frames = anim_frames_per_row;
1424   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1425     g->anim_frames = anim_frames_per_col;
1426   else
1427     g->anim_frames = 1;
1428
1429   if (g->anim_frames == 0)              /* frames must be at least 1 */
1430     g->anim_frames = 1;
1431
1432   g->anim_frames_per_line =
1433     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1434      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1435
1436   g->anim_delay = parameter[GFX_ARG_DELAY];
1437   if (g->anim_delay == 0)               /* delay must be at least 1 */
1438     g->anim_delay = 1;
1439
1440   g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1441
1442   /* automatically determine correct start frame, if not defined */
1443   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1444     g->anim_start_frame = 0;
1445   else if (g->anim_mode & ANIM_REVERSE)
1446     g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1447   else
1448     g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1449
1450   /* animation synchronized with global frame counter, not move position */
1451   g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1452
1453   /* optional element for cloning crumble graphics */
1454   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1455     g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1456
1457   /* optional element for cloning digging graphics */
1458   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1459     g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1460
1461   /* optional border size for "crumbling" diggable graphics */
1462   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1463     g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1464
1465   /* used for global animations and player "boring" and "sleeping" actions */
1466   if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1467     g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1468   if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1469     g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1470   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1471     g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1472   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1473     g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1474   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1475     g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1476   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1477     g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1478
1479   /* used for global animations */
1480   if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
1481     g->init_event = parameter[GFX_ARG_INIT_EVENT];
1482   if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
1483     g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
1484
1485   /* used for toon animations and global animations */
1486   g->step_offset  = parameter[GFX_ARG_STEP_OFFSET];
1487   g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1488   g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1489   g->step_delay   = parameter[GFX_ARG_STEP_DELAY];
1490   g->direction    = parameter[GFX_ARG_DIRECTION];
1491   g->position     = parameter[GFX_ARG_POSITION];
1492   g->x            = parameter[GFX_ARG_X];       // (may be uninitialized,
1493   g->y            = parameter[GFX_ARG_Y];       // unlike src_x and src_y)
1494
1495   /* this is only used for drawing font characters */
1496   g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1497   g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1498
1499   /* this is only used for drawing envelope graphics */
1500   g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1501
1502   /* used for toon animations and global animations */
1503   if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1504     g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1505
1506   /* optional graphic for cloning all graphics settings */
1507   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1508     g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1509
1510   /* optional settings for drawing title screens and title messages */
1511   if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1512     g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1513   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1514     g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1515   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1516     g->post_delay = parameter[GFX_ARG_POST_DELAY];
1517   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1518     g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1519   if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1520     g->align = parameter[GFX_ARG_ALIGN];
1521   if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1522     g->valign = parameter[GFX_ARG_VALIGN];
1523   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1524     g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1525
1526   if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1527     g->class = parameter[GFX_ARG_CLASS];
1528   if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1529     g->style = parameter[GFX_ARG_STYLE];
1530
1531   /* this is only used for drawing menu buttons and text */
1532   g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1533   g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1534   g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1535   g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1536 }
1537
1538 static void set_graphic_parameters(int graphic)
1539 {
1540   struct FileInfo *image = getImageListEntryFromImageID(graphic);
1541   char **parameter_raw = image->parameter;
1542   Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1543   int parameter[NUM_GFX_ARGS];
1544   int i;
1545
1546   /* if fallback to default artwork is done, also use the default parameters */
1547   if (image->fallback_to_default)
1548     parameter_raw = image->default_parameter;
1549
1550   /* get integer values from string parameters */
1551   for (i = 0; i < NUM_GFX_ARGS; i++)
1552     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1553                                                image_config_suffix[i].token,
1554                                                image_config_suffix[i].type);
1555
1556   set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1557
1558   UPDATE_BUSY_STATE();
1559 }
1560
1561 static void set_cloned_graphic_parameters(int graphic)
1562 {
1563   int fallback_graphic = IMG_CHAR_EXCLAM;
1564   int max_num_images = getImageListSize();
1565   int clone_graphic = graphic_info[graphic].clone_from;
1566   int num_references_followed = 1;
1567
1568   while (graphic_info[clone_graphic].clone_from != -1 &&
1569          num_references_followed < max_num_images)
1570   {
1571     clone_graphic = graphic_info[clone_graphic].clone_from;
1572
1573     num_references_followed++;
1574   }
1575
1576   if (num_references_followed >= max_num_images)
1577   {
1578     Error(ERR_INFO_LINE, "-");
1579     Error(ERR_INFO, "warning: error found in config file:");
1580     Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1581     Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1582     Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1583     Error(ERR_INFO, "custom graphic rejected for this element/action");
1584
1585     if (graphic == fallback_graphic)
1586       Error(ERR_EXIT, "no fallback graphic available");
1587
1588     Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1589     Error(ERR_INFO_LINE, "-");
1590
1591     graphic_info[graphic] = graphic_info[fallback_graphic];
1592   }
1593   else
1594   {
1595     graphic_info[graphic] = graphic_info[clone_graphic];
1596     graphic_info[graphic].clone_from = clone_graphic;
1597   }
1598 }
1599
1600 static void InitGraphicInfo()
1601 {
1602   int fallback_graphic = IMG_CHAR_EXCLAM;
1603   int num_images = getImageListSize();
1604   int i;
1605
1606   /* use image size as default values for width and height for these images */
1607   static int full_size_graphics[] =
1608   {
1609     IMG_GLOBAL_BORDER,
1610     IMG_GLOBAL_BORDER_MAIN,
1611     IMG_GLOBAL_BORDER_SCORES,
1612     IMG_GLOBAL_BORDER_EDITOR,
1613     IMG_GLOBAL_BORDER_PLAYING,
1614     IMG_GLOBAL_DOOR,
1615
1616     IMG_BACKGROUND_ENVELOPE_1,
1617     IMG_BACKGROUND_ENVELOPE_2,
1618     IMG_BACKGROUND_ENVELOPE_3,
1619     IMG_BACKGROUND_ENVELOPE_4,
1620     IMG_BACKGROUND_REQUEST,
1621
1622     IMG_BACKGROUND,
1623     IMG_BACKGROUND_TITLE_INITIAL,
1624     IMG_BACKGROUND_TITLE,
1625     IMG_BACKGROUND_MAIN,
1626     IMG_BACKGROUND_LEVELS,
1627     IMG_BACKGROUND_LEVELNR,
1628     IMG_BACKGROUND_SCORES,
1629     IMG_BACKGROUND_EDITOR,
1630     IMG_BACKGROUND_INFO,
1631     IMG_BACKGROUND_INFO_ELEMENTS,
1632     IMG_BACKGROUND_INFO_MUSIC,
1633     IMG_BACKGROUND_INFO_CREDITS,
1634     IMG_BACKGROUND_INFO_PROGRAM,
1635     IMG_BACKGROUND_INFO_VERSION,
1636     IMG_BACKGROUND_INFO_LEVELSET,
1637     IMG_BACKGROUND_SETUP,
1638     IMG_BACKGROUND_PLAYING,
1639     IMG_BACKGROUND_DOOR,
1640     IMG_BACKGROUND_TAPE,
1641     IMG_BACKGROUND_PANEL,
1642     IMG_BACKGROUND_PALETTE,
1643     IMG_BACKGROUND_TOOLBOX,
1644
1645     IMG_TITLESCREEN_INITIAL_1,
1646     IMG_TITLESCREEN_INITIAL_2,
1647     IMG_TITLESCREEN_INITIAL_3,
1648     IMG_TITLESCREEN_INITIAL_4,
1649     IMG_TITLESCREEN_INITIAL_5,
1650     IMG_TITLESCREEN_1,
1651     IMG_TITLESCREEN_2,
1652     IMG_TITLESCREEN_3,
1653     IMG_TITLESCREEN_4,
1654     IMG_TITLESCREEN_5,
1655
1656     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1657     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1658     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1659     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1660     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1661     IMG_BACKGROUND_TITLEMESSAGE_1,
1662     IMG_BACKGROUND_TITLEMESSAGE_2,
1663     IMG_BACKGROUND_TITLEMESSAGE_3,
1664     IMG_BACKGROUND_TITLEMESSAGE_4,
1665     IMG_BACKGROUND_TITLEMESSAGE_5,
1666
1667     -1
1668   };
1669
1670   checked_free(graphic_info);
1671
1672   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1673
1674   /* initialize "use_image_size" flag with default value */
1675   for (i = 0; i < num_images; i++)
1676     graphic_info[i].use_image_size = FALSE;
1677
1678   /* initialize "use_image_size" flag from static configuration above */
1679   for (i = 0; full_size_graphics[i] != -1; i++)
1680     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1681
1682   /* first set all graphic paramaters ... */
1683   for (i = 0; i < num_images; i++)
1684     set_graphic_parameters(i);
1685
1686   /* ... then copy these parameters for cloned graphics */
1687   for (i = 0; i < num_images; i++)
1688     if (graphic_info[i].clone_from != -1)
1689       set_cloned_graphic_parameters(i);
1690
1691   for (i = 0; i < num_images; i++)
1692   {
1693     Bitmap *src_bitmap;
1694     int src_x, src_y;
1695     int width, height;
1696     int first_frame, last_frame;
1697     int src_bitmap_width, src_bitmap_height;
1698
1699     /* now check if no animation frames are outside of the loaded image */
1700
1701     if (graphic_info[i].bitmap == NULL)
1702       continue;         /* skip check for optional images that are undefined */
1703
1704     /* get image size (this can differ from the standard element tile size!) */
1705     width  = graphic_info[i].width;
1706     height = graphic_info[i].height;
1707
1708     /* get final bitmap size (with scaling, but without small images) */
1709     src_bitmap_width  = graphic_info[i].src_image_width;
1710     src_bitmap_height = graphic_info[i].src_image_height;
1711
1712     /* check if first animation frame is inside specified bitmap */
1713
1714     first_frame = 0;
1715     getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1716
1717     /* this avoids calculating wrong start position for out-of-bounds frame */
1718     src_x = graphic_info[i].src_x;
1719     src_y = graphic_info[i].src_y;
1720
1721     if (program.headless)
1722       continue;
1723
1724     if (src_x < 0 || src_y < 0 ||
1725         src_x + width  > src_bitmap_width ||
1726         src_y + height > src_bitmap_height)
1727     {
1728       Error(ERR_INFO_LINE, "-");
1729       Error(ERR_INFO, "warning: error found in config file:");
1730       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1731       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1732       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1733       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1734       Error(ERR_INFO,
1735             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1736             src_x, src_y, src_bitmap_width, src_bitmap_height);
1737       Error(ERR_INFO, "custom graphic rejected for this element/action");
1738
1739       if (i == fallback_graphic)
1740         Error(ERR_EXIT, "no fallback graphic available");
1741
1742       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1743       Error(ERR_INFO_LINE, "-");
1744
1745       graphic_info[i] = graphic_info[fallback_graphic];
1746     }
1747
1748     /* check if last animation frame is inside specified bitmap */
1749
1750     last_frame = graphic_info[i].anim_frames - 1;
1751     getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1752
1753     if (src_x < 0 || src_y < 0 ||
1754         src_x + width  > src_bitmap_width ||
1755         src_y + height > src_bitmap_height)
1756     {
1757       Error(ERR_INFO_LINE, "-");
1758       Error(ERR_INFO, "warning: error found in config file:");
1759       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1760       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1761       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1762       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1763       Error(ERR_INFO,
1764             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1765             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1766       Error(ERR_INFO, "custom graphic rejected for this element/action");
1767
1768       if (i == fallback_graphic)
1769         Error(ERR_EXIT, "no fallback graphic available");
1770
1771       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1772       Error(ERR_INFO_LINE, "-");
1773
1774       graphic_info[i] = graphic_info[fallback_graphic];
1775     }
1776   }
1777 }
1778
1779 static void InitGraphicCompatibilityInfo()
1780 {
1781   struct FileInfo *fi_global_door =
1782     getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1783   int num_images = getImageListSize();
1784   int i;
1785
1786   /* the following compatibility handling is needed for the following case:
1787      versions up to 3.3.0.0 used one large bitmap "global.door" for various
1788      graphics mainly used for door and panel graphics, like editor, tape and
1789      in-game buttons with hard-coded bitmap positions and button sizes; as
1790      these graphics now have individual definitions, redefining "global.door"
1791      to change all these graphics at once like before does not work anymore
1792      (because all those individual definitions still have their default values);
1793      to solve this, remap all those individual definitions that are not
1794      redefined to the new bitmap of "global.door" if it was redefined */
1795
1796   /* special compatibility handling if image "global.door" was redefined */
1797   if (fi_global_door->redefined)
1798   {
1799     for (i = 0; i < num_images; i++)
1800     {
1801       struct FileInfo *fi = getImageListEntryFromImageID(i);
1802
1803       /* process only those images that still use the default settings */
1804       if (!fi->redefined)
1805       {
1806         /* process all images which default to same image as "global.door" */
1807         if (strEqual(fi->default_filename, fi_global_door->default_filename))
1808         {
1809           // printf("::: special treatment needed for token '%s'\n", fi->token);
1810
1811           graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1812           graphic_info[i].bitmap  = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1813         }
1814       }
1815     }
1816   }
1817
1818   InitGraphicCompatibilityInfo_Doors();
1819 }
1820
1821 static void InitElementSoundInfo()
1822 {
1823   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1824   int num_property_mappings = getSoundListPropertyMappingSize();
1825   int i, j, act;
1826
1827   /* set values to -1 to identify later as "uninitialized" values */
1828   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1829     for (act = 0; act < NUM_ACTIONS; act++)
1830       element_info[i].sound[act] = -1;
1831
1832   /* initialize element/sound mapping from static configuration */
1833   for (i = 0; element_to_sound[i].element > -1; i++)
1834   {
1835     int element      = element_to_sound[i].element;
1836     int action       = element_to_sound[i].action;
1837     int sound        = element_to_sound[i].sound;
1838     boolean is_class = element_to_sound[i].is_class;
1839
1840     if (action < 0)
1841       action = ACTION_DEFAULT;
1842
1843     if (!is_class)
1844       element_info[element].sound[action] = sound;
1845     else
1846       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1847         if (strEqual(element_info[j].class_name,
1848                      element_info[element].class_name))
1849           element_info[j].sound[action] = sound;
1850   }
1851
1852   /* initialize element class/sound mapping from dynamic configuration */
1853   for (i = 0; i < num_property_mappings; i++)
1854   {
1855     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1856     int action        = property_mapping[i].ext1_index;
1857     int sound         = property_mapping[i].artwork_index;
1858
1859     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1860       continue;
1861
1862     if (action < 0)
1863       action = ACTION_DEFAULT;
1864
1865     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1866       if (strEqual(element_info[j].class_name,
1867                    element_info[element_class].class_name))
1868         element_info[j].sound[action] = sound;
1869   }
1870
1871   /* initialize element/sound mapping from dynamic configuration */
1872   for (i = 0; i < num_property_mappings; i++)
1873   {
1874     int element = property_mapping[i].base_index;
1875     int action  = property_mapping[i].ext1_index;
1876     int sound   = property_mapping[i].artwork_index;
1877
1878     if (element >= MAX_NUM_ELEMENTS)
1879       continue;
1880
1881     if (action < 0)
1882       action = ACTION_DEFAULT;
1883
1884     element_info[element].sound[action] = sound;
1885   }
1886
1887   /* now set all '-1' values to element specific default values */
1888   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1889   {
1890     for (act = 0; act < NUM_ACTIONS; act++)
1891     {
1892       /* generic default action sound (defined by "[default]" directive) */
1893       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1894
1895       /* look for special default action sound (classic game specific) */
1896       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1897         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1898       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1899         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1900       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1901         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1902
1903       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1904       /* !!! make this better !!! */
1905       if (i == EL_EMPTY_SPACE)
1906         default_action_sound = element_info[EL_DEFAULT].sound[act];
1907
1908       /* no sound for this specific action -- use default action sound */
1909       if (element_info[i].sound[act] == -1)
1910         element_info[i].sound[act] = default_action_sound;
1911     }
1912   }
1913
1914   /* copy sound settings to some elements that are only stored in level file
1915      in native R'n'D levels, but are used by game engine in native EM levels */
1916   for (i = 0; copy_properties[i][0] != -1; i++)
1917     for (j = 1; j <= 4; j++)
1918       for (act = 0; act < NUM_ACTIONS; act++)
1919         element_info[copy_properties[i][j]].sound[act] =
1920           element_info[copy_properties[i][0]].sound[act];
1921 }
1922
1923 static void InitGameModeSoundInfo()
1924 {
1925   int i;
1926
1927   /* set values to -1 to identify later as "uninitialized" values */
1928   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1929     menu.sound[i] = -1;
1930
1931   /* initialize gamemode/sound mapping from static configuration */
1932   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1933   {
1934     int gamemode = gamemode_to_sound[i].gamemode;
1935     int sound    = gamemode_to_sound[i].sound;
1936
1937     if (gamemode < 0)
1938       gamemode = GAME_MODE_DEFAULT;
1939
1940     menu.sound[gamemode] = sound;
1941   }
1942
1943   /* now set all '-1' values to levelset specific default values */
1944   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1945     if (menu.sound[i] == -1)
1946       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1947 }
1948
1949 static void set_sound_parameters(int sound, char **parameter_raw)
1950 {
1951   int parameter[NUM_SND_ARGS];
1952   int i;
1953
1954   /* get integer values from string parameters */
1955   for (i = 0; i < NUM_SND_ARGS; i++)
1956     parameter[i] =
1957       get_parameter_value(parameter_raw[i],
1958                           sound_config_suffix[i].token,
1959                           sound_config_suffix[i].type);
1960
1961   /* explicit loop mode setting in configuration overrides default value */
1962   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1963     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1964
1965   /* sound volume to change the original volume when loading the sound file */
1966   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1967
1968   /* sound priority to give certain sounds a higher or lower priority */
1969   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1970 }
1971
1972 static void InitSoundInfo()
1973 {
1974   int *sound_effect_properties;
1975   int num_sounds = getSoundListSize();
1976   int i, j;
1977
1978   checked_free(sound_info);
1979
1980   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1981   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1982
1983   /* initialize sound effect for all elements to "no sound" */
1984   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1985     for (j = 0; j < NUM_ACTIONS; j++)
1986       element_info[i].sound[j] = SND_UNDEFINED;
1987
1988   for (i = 0; i < num_sounds; i++)
1989   {
1990     struct FileInfo *sound = getSoundListEntry(i);
1991     int len_effect_text = strlen(sound->token);
1992
1993     sound_effect_properties[i] = ACTION_OTHER;
1994     sound_info[i].loop = FALSE;         /* default: play sound only once */
1995
1996     /* determine all loop sounds and identify certain sound classes */
1997
1998     for (j = 0; element_action_info[j].suffix; j++)
1999     {
2000       int len_action_text = strlen(element_action_info[j].suffix);
2001
2002       if (len_action_text < len_effect_text &&
2003           strEqual(&sound->token[len_effect_text - len_action_text],
2004                    element_action_info[j].suffix))
2005       {
2006         sound_effect_properties[i] = element_action_info[j].value;
2007         sound_info[i].loop = element_action_info[j].is_loop_sound;
2008
2009         break;
2010       }
2011     }
2012
2013     /* associate elements and some selected sound actions */
2014
2015     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
2016     {
2017       if (element_info[j].class_name)
2018       {
2019         int len_class_text = strlen(element_info[j].class_name);
2020
2021         if (len_class_text + 1 < len_effect_text &&
2022             strncmp(sound->token,
2023                     element_info[j].class_name, len_class_text) == 0 &&
2024             sound->token[len_class_text] == '.')
2025         {
2026           int sound_action_value = sound_effect_properties[i];
2027
2028           element_info[j].sound[sound_action_value] = i;
2029         }
2030       }
2031     }
2032
2033     set_sound_parameters(i, sound->parameter);
2034   }
2035
2036   free(sound_effect_properties);
2037 }
2038
2039 static void InitGameModeMusicInfo()
2040 {
2041   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2042   int num_property_mappings = getMusicListPropertyMappingSize();
2043   int default_levelset_music = -1;
2044   int i;
2045
2046   /* set values to -1 to identify later as "uninitialized" values */
2047   for (i = 0; i < MAX_LEVELS; i++)
2048     levelset.music[i] = -1;
2049   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2050     menu.music[i] = -1;
2051
2052   /* initialize gamemode/music mapping from static configuration */
2053   for (i = 0; gamemode_to_music[i].music > -1; i++)
2054   {
2055     int gamemode = gamemode_to_music[i].gamemode;
2056     int music    = gamemode_to_music[i].music;
2057
2058     if (gamemode < 0)
2059       gamemode = GAME_MODE_DEFAULT;
2060
2061     menu.music[gamemode] = music;
2062   }
2063
2064   /* initialize gamemode/music mapping from dynamic configuration */
2065   for (i = 0; i < num_property_mappings; i++)
2066   {
2067     int prefix   = property_mapping[i].base_index;
2068     int gamemode = property_mapping[i].ext2_index;
2069     int level    = property_mapping[i].ext3_index;
2070     int music    = property_mapping[i].artwork_index;
2071
2072     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2073       continue;
2074
2075     if (gamemode < 0)
2076       gamemode = GAME_MODE_DEFAULT;
2077
2078     /* level specific music only allowed for in-game music */
2079     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2080       gamemode = GAME_MODE_PLAYING;
2081
2082     if (level == -1)
2083     {
2084       level = 0;
2085       default_levelset_music = music;
2086     }
2087
2088     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2089       levelset.music[level] = music;
2090     if (gamemode != GAME_MODE_PLAYING)
2091       menu.music[gamemode] = music;
2092   }
2093
2094   /* now set all '-1' values to menu specific default values */
2095   /* (undefined values of "levelset.music[]" might stay at "-1" to
2096      allow dynamic selection of music files from music directory!) */
2097   for (i = 0; i < MAX_LEVELS; i++)
2098     if (levelset.music[i] == -1)
2099       levelset.music[i] = default_levelset_music;
2100   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2101     if (menu.music[i] == -1)
2102       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2103 }
2104
2105 static void set_music_parameters(int music, char **parameter_raw)
2106 {
2107   int parameter[NUM_MUS_ARGS];
2108   int i;
2109
2110   /* get integer values from string parameters */
2111   for (i = 0; i < NUM_MUS_ARGS; i++)
2112     parameter[i] =
2113       get_parameter_value(parameter_raw[i],
2114                           music_config_suffix[i].token,
2115                           music_config_suffix[i].type);
2116
2117   /* explicit loop mode setting in configuration overrides default value */
2118   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2119     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2120 }
2121
2122 static void InitMusicInfo()
2123 {
2124   int num_music = getMusicListSize();
2125   int i, j;
2126
2127   checked_free(music_info);
2128
2129   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2130
2131   for (i = 0; i < num_music; i++)
2132   {
2133     struct FileInfo *music = getMusicListEntry(i);
2134     int len_music_text = strlen(music->token);
2135
2136     music_info[i].loop = TRUE;          /* default: play music in loop mode */
2137
2138     /* determine all loop music */
2139
2140     for (j = 0; music_prefix_info[j].prefix; j++)
2141     {
2142       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2143
2144       if (len_prefix_text < len_music_text &&
2145           strncmp(music->token,
2146                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2147       {
2148         music_info[i].loop = music_prefix_info[j].is_loop_music;
2149
2150         break;
2151       }
2152     }
2153
2154     set_music_parameters(i, music->parameter);
2155   }
2156 }
2157
2158 static void ReinitializeGraphics()
2159 {
2160   print_timestamp_init("ReinitializeGraphics");
2161
2162   InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2163
2164   InitGraphicInfo();                    /* graphic properties mapping */
2165   print_timestamp_time("InitGraphicInfo");
2166   InitElementGraphicInfo();             /* element game graphic mapping */
2167   print_timestamp_time("InitElementGraphicInfo");
2168   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
2169   print_timestamp_time("InitElementSpecialGraphicInfo");
2170
2171   InitElementSmallImages();             /* scale elements to all needed sizes */
2172   print_timestamp_time("InitElementSmallImages");
2173   InitScaledImages();                   /* scale all other images, if needed */
2174   print_timestamp_time("InitScaledImages");
2175   InitBitmapPointers();                 /* set standard size bitmap pointers */
2176   print_timestamp_time("InitBitmapPointers");
2177   InitFontGraphicInfo();                /* initialize text drawing functions */
2178   print_timestamp_time("InitFontGraphicInfo");
2179   InitGlobalAnimGraphicInfo();          /* initialize global animation config */
2180   print_timestamp_time("InitGlobalAnimGraphicInfo");
2181
2182   InitImageTextures();                  /* create textures for certain images */
2183   print_timestamp_time("InitImageTextures");
2184
2185   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
2186   print_timestamp_time("InitGraphicInfo_EM");
2187
2188   InitGraphicCompatibilityInfo();
2189   print_timestamp_time("InitGraphicCompatibilityInfo");
2190
2191   SetMainBackgroundImage(IMG_BACKGROUND);
2192   print_timestamp_time("SetMainBackgroundImage");
2193   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2194   print_timestamp_time("SetDoorBackgroundImage");
2195
2196   InitGadgets();
2197   print_timestamp_time("InitGadgets");
2198   InitDoors();
2199   print_timestamp_time("InitDoors");
2200
2201   print_timestamp_done("ReinitializeGraphics");
2202 }
2203
2204 static void ReinitializeSounds()
2205 {
2206   InitSoundInfo();              /* sound properties mapping */
2207   InitElementSoundInfo();       /* element game sound mapping */
2208   InitGameModeSoundInfo();      /* game mode sound mapping */
2209   InitGlobalAnimSoundInfo();    /* global animation sound settings */
2210
2211   InitPlayLevelSound();         /* internal game sound settings */
2212 }
2213
2214 static void ReinitializeMusic()
2215 {
2216   InitMusicInfo();              /* music properties mapping */
2217   InitGameModeMusicInfo();      /* game mode music mapping */
2218   InitGlobalAnimMusicInfo();    /* global animation music settings */
2219 }
2220
2221 static int get_special_property_bit(int element, int property_bit_nr)
2222 {
2223   struct PropertyBitInfo
2224   {
2225     int element;
2226     int bit_nr;
2227   };
2228
2229   static struct PropertyBitInfo pb_can_move_into_acid[] =
2230   {
2231     /* the player may be able fall into acid when gravity is activated */
2232     { EL_PLAYER_1,              0       },
2233     { EL_PLAYER_2,              0       },
2234     { EL_PLAYER_3,              0       },
2235     { EL_PLAYER_4,              0       },
2236     { EL_SP_MURPHY,             0       },
2237     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2238
2239     /* all elements that can move may be able to also move into acid */
2240     { EL_BUG,                   1       },
2241     { EL_BUG_LEFT,              1       },
2242     { EL_BUG_RIGHT,             1       },
2243     { EL_BUG_UP,                1       },
2244     { EL_BUG_DOWN,              1       },
2245     { EL_SPACESHIP,             2       },
2246     { EL_SPACESHIP_LEFT,        2       },
2247     { EL_SPACESHIP_RIGHT,       2       },
2248     { EL_SPACESHIP_UP,          2       },
2249     { EL_SPACESHIP_DOWN,        2       },
2250     { EL_BD_BUTTERFLY,          3       },
2251     { EL_BD_BUTTERFLY_LEFT,     3       },
2252     { EL_BD_BUTTERFLY_RIGHT,    3       },
2253     { EL_BD_BUTTERFLY_UP,       3       },
2254     { EL_BD_BUTTERFLY_DOWN,     3       },
2255     { EL_BD_FIREFLY,            4       },
2256     { EL_BD_FIREFLY_LEFT,       4       },
2257     { EL_BD_FIREFLY_RIGHT,      4       },
2258     { EL_BD_FIREFLY_UP,         4       },
2259     { EL_BD_FIREFLY_DOWN,       4       },
2260     { EL_YAMYAM,                5       },
2261     { EL_YAMYAM_LEFT,           5       },
2262     { EL_YAMYAM_RIGHT,          5       },
2263     { EL_YAMYAM_UP,             5       },
2264     { EL_YAMYAM_DOWN,           5       },
2265     { EL_DARK_YAMYAM,           6       },
2266     { EL_ROBOT,                 7       },
2267     { EL_PACMAN,                8       },
2268     { EL_PACMAN_LEFT,           8       },
2269     { EL_PACMAN_RIGHT,          8       },
2270     { EL_PACMAN_UP,             8       },
2271     { EL_PACMAN_DOWN,           8       },
2272     { EL_MOLE,                  9       },
2273     { EL_MOLE_LEFT,             9       },
2274     { EL_MOLE_RIGHT,            9       },
2275     { EL_MOLE_UP,               9       },
2276     { EL_MOLE_DOWN,             9       },
2277     { EL_PENGUIN,               10      },
2278     { EL_PIG,                   11      },
2279     { EL_DRAGON,                12      },
2280     { EL_SATELLITE,             13      },
2281     { EL_SP_SNIKSNAK,           14      },
2282     { EL_SP_ELECTRON,           15      },
2283     { EL_BALLOON,               16      },
2284     { EL_SPRING,                17      },
2285     { EL_EMC_ANDROID,           18      },
2286
2287     { -1,                       -1      },
2288   };
2289
2290   static struct PropertyBitInfo pb_dont_collide_with[] =
2291   {
2292     { EL_SP_SNIKSNAK,           0       },
2293     { EL_SP_ELECTRON,           1       },
2294
2295     { -1,                       -1      },
2296   };
2297
2298   static struct
2299   {
2300     int bit_nr;
2301     struct PropertyBitInfo *pb_info;
2302   } pb_definition[] =
2303   {
2304     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2305     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2306
2307     { -1,                       NULL                    },
2308   };
2309
2310   struct PropertyBitInfo *pb_info = NULL;
2311   int i;
2312
2313   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2314     if (pb_definition[i].bit_nr == property_bit_nr)
2315       pb_info = pb_definition[i].pb_info;
2316
2317   if (pb_info == NULL)
2318     return -1;
2319
2320   for (i = 0; pb_info[i].element != -1; i++)
2321     if (pb_info[i].element == element)
2322       return pb_info[i].bit_nr;
2323
2324   return -1;
2325 }
2326
2327 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2328                          boolean property_value)
2329 {
2330   int bit_nr = get_special_property_bit(element, property_bit_nr);
2331
2332   if (bit_nr > -1)
2333   {
2334     if (property_value)
2335       *bitfield |=  (1 << bit_nr);
2336     else
2337       *bitfield &= ~(1 << bit_nr);
2338   }
2339 }
2340
2341 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2342 {
2343   int bit_nr = get_special_property_bit(element, property_bit_nr);
2344
2345   if (bit_nr > -1)
2346     return ((*bitfield & (1 << bit_nr)) != 0);
2347
2348   return FALSE;
2349 }
2350
2351 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2352 {
2353   static int group_nr;
2354   static struct ElementGroupInfo *group;
2355   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2356   int i;
2357
2358   if (actual_group == NULL)                     /* not yet initialized */
2359     return;
2360
2361   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2362   {
2363     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2364           group_element - EL_GROUP_START + 1);
2365
2366     /* replace element which caused too deep recursion by question mark */
2367     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2368
2369     return;
2370   }
2371
2372   if (recursion_depth == 0)                     /* initialization */
2373   {
2374     group = actual_group;
2375     group_nr = GROUP_NR(group_element);
2376
2377     group->num_elements_resolved = 0;
2378     group->choice_pos = 0;
2379
2380     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2381       element_info[i].in_group[group_nr] = FALSE;
2382   }
2383
2384   for (i = 0; i < actual_group->num_elements; i++)
2385   {
2386     int element = actual_group->element[i];
2387
2388     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2389       break;
2390
2391     if (IS_GROUP_ELEMENT(element))
2392       ResolveGroupElementExt(element, recursion_depth + 1);
2393     else
2394     {
2395       group->element_resolved[group->num_elements_resolved++] = element;
2396       element_info[element].in_group[group_nr] = TRUE;
2397     }
2398   }
2399 }
2400
2401 void ResolveGroupElement(int group_element)
2402 {
2403   ResolveGroupElementExt(group_element, 0);
2404 }
2405
2406 void InitElementPropertiesStatic()
2407 {
2408   static boolean clipboard_elements_initialized = FALSE;
2409
2410   static int ep_diggable[] =
2411   {
2412     EL_SAND,
2413     EL_SP_BASE,
2414     EL_SP_BUGGY_BASE,
2415     EL_SP_BUGGY_BASE_ACTIVATING,
2416     EL_TRAP,
2417     EL_INVISIBLE_SAND,
2418     EL_INVISIBLE_SAND_ACTIVE,
2419     EL_EMC_GRASS,
2420
2421     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2422     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2423 #if 0
2424     EL_LANDMINE,
2425     EL_DC_LANDMINE,
2426     EL_TRAP_ACTIVE,
2427     EL_SP_BUGGY_BASE_ACTIVE,
2428     EL_EMC_PLANT,
2429 #endif
2430
2431     -1
2432   };
2433
2434   static int ep_collectible_only[] =
2435   {
2436     EL_BD_DIAMOND,
2437     EL_EMERALD,
2438     EL_DIAMOND,
2439     EL_EMERALD_YELLOW,
2440     EL_EMERALD_RED,
2441     EL_EMERALD_PURPLE,
2442     EL_KEY_1,
2443     EL_KEY_2,
2444     EL_KEY_3,
2445     EL_KEY_4,
2446     EL_EM_KEY_1,
2447     EL_EM_KEY_2,
2448     EL_EM_KEY_3,
2449     EL_EM_KEY_4,
2450     EL_EMC_KEY_5,
2451     EL_EMC_KEY_6,
2452     EL_EMC_KEY_7,
2453     EL_EMC_KEY_8,
2454     EL_DYNAMITE,
2455     EL_EM_DYNAMITE,
2456     EL_DYNABOMB_INCREASE_NUMBER,
2457     EL_DYNABOMB_INCREASE_SIZE,
2458     EL_DYNABOMB_INCREASE_POWER,
2459     EL_SP_INFOTRON,
2460     EL_SP_DISK_RED,
2461     EL_PEARL,
2462     EL_CRYSTAL,
2463     EL_DC_KEY_WHITE,
2464     EL_SHIELD_NORMAL,
2465     EL_SHIELD_DEADLY,
2466     EL_EXTRA_TIME,
2467     EL_ENVELOPE_1,
2468     EL_ENVELOPE_2,
2469     EL_ENVELOPE_3,
2470     EL_ENVELOPE_4,
2471     EL_SPEED_PILL,
2472     EL_EMC_LENSES,
2473     EL_EMC_MAGNIFIER,
2474
2475 #if 0
2476     /* !!! handle separately !!! */
2477     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2478 #endif
2479
2480     -1
2481   };
2482
2483   static int ep_dont_run_into[] =
2484   {
2485     /* same elements as in 'ep_dont_touch' */
2486     EL_BUG,
2487     EL_SPACESHIP,
2488     EL_BD_BUTTERFLY,
2489     EL_BD_FIREFLY,
2490
2491     /* same elements as in 'ep_dont_collide_with' */
2492     EL_YAMYAM,
2493     EL_DARK_YAMYAM,
2494     EL_ROBOT,
2495     EL_PACMAN,
2496     EL_SP_SNIKSNAK,
2497     EL_SP_ELECTRON,
2498
2499     /* new elements */
2500     EL_AMOEBA_DROP,
2501     EL_ACID,
2502
2503     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2504 #if 1
2505     EL_LANDMINE,
2506     EL_DC_LANDMINE,
2507     EL_TRAP_ACTIVE,
2508     EL_SP_BUGGY_BASE_ACTIVE,
2509     EL_EMC_PLANT,
2510 #endif
2511
2512     -1
2513   };
2514
2515   static int ep_dont_collide_with[] =
2516   {
2517     /* same elements as in 'ep_dont_touch' */
2518     EL_BUG,
2519     EL_SPACESHIP,
2520     EL_BD_BUTTERFLY,
2521     EL_BD_FIREFLY,
2522
2523     /* new elements */
2524     EL_YAMYAM,
2525     EL_DARK_YAMYAM,
2526     EL_ROBOT,
2527     EL_PACMAN,
2528     EL_SP_SNIKSNAK,
2529     EL_SP_ELECTRON,
2530
2531     -1
2532   };
2533
2534   static int ep_dont_touch[] =
2535   {
2536     EL_BUG,
2537     EL_SPACESHIP,
2538     EL_BD_BUTTERFLY,
2539     EL_BD_FIREFLY,
2540
2541     -1
2542   };
2543
2544   static int ep_indestructible[] =
2545   {
2546     EL_STEELWALL,
2547     EL_ACID,
2548     EL_ACID_POOL_TOPLEFT,
2549     EL_ACID_POOL_TOPRIGHT,
2550     EL_ACID_POOL_BOTTOMLEFT,
2551     EL_ACID_POOL_BOTTOM,
2552     EL_ACID_POOL_BOTTOMRIGHT,
2553     EL_SP_HARDWARE_GRAY,
2554     EL_SP_HARDWARE_GREEN,
2555     EL_SP_HARDWARE_BLUE,
2556     EL_SP_HARDWARE_RED,
2557     EL_SP_HARDWARE_YELLOW,
2558     EL_SP_HARDWARE_BASE_1,
2559     EL_SP_HARDWARE_BASE_2,
2560     EL_SP_HARDWARE_BASE_3,
2561     EL_SP_HARDWARE_BASE_4,
2562     EL_SP_HARDWARE_BASE_5,
2563     EL_SP_HARDWARE_BASE_6,
2564     EL_INVISIBLE_STEELWALL,
2565     EL_INVISIBLE_STEELWALL_ACTIVE,
2566     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2567     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2568     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2569     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2570     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2571     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2572     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2573     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2574     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2575     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2576     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2577     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2578     EL_LIGHT_SWITCH,
2579     EL_LIGHT_SWITCH_ACTIVE,
2580     EL_SIGN_EXCLAMATION,
2581     EL_SIGN_RADIOACTIVITY,
2582     EL_SIGN_STOP,
2583     EL_SIGN_WHEELCHAIR,
2584     EL_SIGN_PARKING,
2585     EL_SIGN_NO_ENTRY,
2586     EL_SIGN_UNUSED_1,
2587     EL_SIGN_GIVE_WAY,
2588     EL_SIGN_ENTRY_FORBIDDEN,
2589     EL_SIGN_EMERGENCY_EXIT,
2590     EL_SIGN_YIN_YANG,
2591     EL_SIGN_UNUSED_2,
2592     EL_SIGN_SPERMS,
2593     EL_SIGN_BULLET,
2594     EL_SIGN_HEART,
2595     EL_SIGN_CROSS,
2596     EL_SIGN_FRANKIE,
2597     EL_STEEL_EXIT_CLOSED,
2598     EL_STEEL_EXIT_OPEN,
2599     EL_STEEL_EXIT_OPENING,
2600     EL_STEEL_EXIT_CLOSING,
2601     EL_EM_STEEL_EXIT_CLOSED,
2602     EL_EM_STEEL_EXIT_OPEN,
2603     EL_EM_STEEL_EXIT_OPENING,
2604     EL_EM_STEEL_EXIT_CLOSING,
2605     EL_DC_STEELWALL_1_LEFT,
2606     EL_DC_STEELWALL_1_RIGHT,
2607     EL_DC_STEELWALL_1_TOP,
2608     EL_DC_STEELWALL_1_BOTTOM,
2609     EL_DC_STEELWALL_1_HORIZONTAL,
2610     EL_DC_STEELWALL_1_VERTICAL,
2611     EL_DC_STEELWALL_1_TOPLEFT,
2612     EL_DC_STEELWALL_1_TOPRIGHT,
2613     EL_DC_STEELWALL_1_BOTTOMLEFT,
2614     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2615     EL_DC_STEELWALL_1_TOPLEFT_2,
2616     EL_DC_STEELWALL_1_TOPRIGHT_2,
2617     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2618     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2619     EL_DC_STEELWALL_2_LEFT,
2620     EL_DC_STEELWALL_2_RIGHT,
2621     EL_DC_STEELWALL_2_TOP,
2622     EL_DC_STEELWALL_2_BOTTOM,
2623     EL_DC_STEELWALL_2_HORIZONTAL,
2624     EL_DC_STEELWALL_2_VERTICAL,
2625     EL_DC_STEELWALL_2_MIDDLE,
2626     EL_DC_STEELWALL_2_SINGLE,
2627     EL_STEELWALL_SLIPPERY,
2628     EL_EMC_STEELWALL_1,
2629     EL_EMC_STEELWALL_2,
2630     EL_EMC_STEELWALL_3,
2631     EL_EMC_STEELWALL_4,
2632     EL_CRYSTAL,
2633     EL_GATE_1,
2634     EL_GATE_2,
2635     EL_GATE_3,
2636     EL_GATE_4,
2637     EL_GATE_1_GRAY,
2638     EL_GATE_2_GRAY,
2639     EL_GATE_3_GRAY,
2640     EL_GATE_4_GRAY,
2641     EL_GATE_1_GRAY_ACTIVE,
2642     EL_GATE_2_GRAY_ACTIVE,
2643     EL_GATE_3_GRAY_ACTIVE,
2644     EL_GATE_4_GRAY_ACTIVE,
2645     EL_EM_GATE_1,
2646     EL_EM_GATE_2,
2647     EL_EM_GATE_3,
2648     EL_EM_GATE_4,
2649     EL_EM_GATE_1_GRAY,
2650     EL_EM_GATE_2_GRAY,
2651     EL_EM_GATE_3_GRAY,
2652     EL_EM_GATE_4_GRAY,
2653     EL_EM_GATE_1_GRAY_ACTIVE,
2654     EL_EM_GATE_2_GRAY_ACTIVE,
2655     EL_EM_GATE_3_GRAY_ACTIVE,
2656     EL_EM_GATE_4_GRAY_ACTIVE,
2657     EL_EMC_GATE_5,
2658     EL_EMC_GATE_6,
2659     EL_EMC_GATE_7,
2660     EL_EMC_GATE_8,
2661     EL_EMC_GATE_5_GRAY,
2662     EL_EMC_GATE_6_GRAY,
2663     EL_EMC_GATE_7_GRAY,
2664     EL_EMC_GATE_8_GRAY,
2665     EL_EMC_GATE_5_GRAY_ACTIVE,
2666     EL_EMC_GATE_6_GRAY_ACTIVE,
2667     EL_EMC_GATE_7_GRAY_ACTIVE,
2668     EL_EMC_GATE_8_GRAY_ACTIVE,
2669     EL_DC_GATE_WHITE,
2670     EL_DC_GATE_WHITE_GRAY,
2671     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2672     EL_DC_GATE_FAKE_GRAY,
2673     EL_SWITCHGATE_OPEN,
2674     EL_SWITCHGATE_OPENING,
2675     EL_SWITCHGATE_CLOSED,
2676     EL_SWITCHGATE_CLOSING,
2677     EL_DC_SWITCHGATE_SWITCH_UP,
2678     EL_DC_SWITCHGATE_SWITCH_DOWN,
2679     EL_TIMEGATE_OPEN,
2680     EL_TIMEGATE_OPENING,
2681     EL_TIMEGATE_CLOSED,
2682     EL_TIMEGATE_CLOSING,
2683     EL_DC_TIMEGATE_SWITCH,
2684     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2685     EL_TUBE_ANY,
2686     EL_TUBE_VERTICAL,
2687     EL_TUBE_HORIZONTAL,
2688     EL_TUBE_VERTICAL_LEFT,
2689     EL_TUBE_VERTICAL_RIGHT,
2690     EL_TUBE_HORIZONTAL_UP,
2691     EL_TUBE_HORIZONTAL_DOWN,
2692     EL_TUBE_LEFT_UP,
2693     EL_TUBE_LEFT_DOWN,
2694     EL_TUBE_RIGHT_UP,
2695     EL_TUBE_RIGHT_DOWN,
2696     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2697     EL_EXPANDABLE_STEELWALL_VERTICAL,
2698     EL_EXPANDABLE_STEELWALL_ANY,
2699
2700     -1
2701   };
2702
2703   static int ep_slippery[] =
2704   {
2705     EL_WALL_SLIPPERY,
2706     EL_BD_WALL,
2707     EL_ROCK,
2708     EL_BD_ROCK,
2709     EL_EMERALD,
2710     EL_BD_DIAMOND,
2711     EL_EMERALD_YELLOW,
2712     EL_EMERALD_RED,
2713     EL_EMERALD_PURPLE,
2714     EL_DIAMOND,
2715     EL_BOMB,
2716     EL_NUT,
2717     EL_ROBOT_WHEEL_ACTIVE,
2718     EL_ROBOT_WHEEL,
2719     EL_TIME_ORB_FULL,
2720     EL_TIME_ORB_EMPTY,
2721     EL_LAMP_ACTIVE,
2722     EL_LAMP,
2723     EL_ACID_POOL_TOPLEFT,
2724     EL_ACID_POOL_TOPRIGHT,
2725     EL_SATELLITE,
2726     EL_SP_ZONK,
2727     EL_SP_INFOTRON,
2728     EL_SP_CHIP_SINGLE,
2729     EL_SP_CHIP_LEFT,
2730     EL_SP_CHIP_RIGHT,
2731     EL_SP_CHIP_TOP,
2732     EL_SP_CHIP_BOTTOM,
2733     EL_SPEED_PILL,
2734     EL_STEELWALL_SLIPPERY,
2735     EL_PEARL,
2736     EL_CRYSTAL,
2737     EL_EMC_WALL_SLIPPERY_1,
2738     EL_EMC_WALL_SLIPPERY_2,
2739     EL_EMC_WALL_SLIPPERY_3,
2740     EL_EMC_WALL_SLIPPERY_4,
2741     EL_EMC_MAGIC_BALL,
2742     EL_EMC_MAGIC_BALL_ACTIVE,
2743
2744     -1
2745   };
2746
2747   static int ep_can_change[] =
2748   {
2749     -1
2750   };
2751
2752   static int ep_can_move[] =
2753   {
2754     /* same elements as in 'pb_can_move_into_acid' */
2755     EL_BUG,
2756     EL_SPACESHIP,
2757     EL_BD_BUTTERFLY,
2758     EL_BD_FIREFLY,
2759     EL_YAMYAM,
2760     EL_DARK_YAMYAM,
2761     EL_ROBOT,
2762     EL_PACMAN,
2763     EL_MOLE,
2764     EL_PENGUIN,
2765     EL_PIG,
2766     EL_DRAGON,
2767     EL_SATELLITE,
2768     EL_SP_SNIKSNAK,
2769     EL_SP_ELECTRON,
2770     EL_BALLOON,
2771     EL_SPRING,
2772     EL_EMC_ANDROID,
2773
2774     -1
2775   };
2776
2777   static int ep_can_fall[] =
2778   {
2779     EL_ROCK,
2780     EL_BD_ROCK,
2781     EL_EMERALD,
2782     EL_BD_DIAMOND,
2783     EL_EMERALD_YELLOW,
2784     EL_EMERALD_RED,
2785     EL_EMERALD_PURPLE,
2786     EL_DIAMOND,
2787     EL_BOMB,
2788     EL_NUT,
2789     EL_AMOEBA_DROP,
2790     EL_QUICKSAND_FULL,
2791     EL_QUICKSAND_FAST_FULL,
2792     EL_MAGIC_WALL_FULL,
2793     EL_BD_MAGIC_WALL_FULL,
2794     EL_DC_MAGIC_WALL_FULL,
2795     EL_TIME_ORB_FULL,
2796     EL_TIME_ORB_EMPTY,
2797     EL_SP_ZONK,
2798     EL_SP_INFOTRON,
2799     EL_SP_DISK_ORANGE,
2800     EL_PEARL,
2801     EL_CRYSTAL,
2802     EL_SPRING,
2803     EL_DX_SUPABOMB,
2804
2805     -1
2806   };
2807
2808   static int ep_can_smash_player[] =
2809   {
2810     EL_ROCK,
2811     EL_BD_ROCK,
2812     EL_EMERALD,
2813     EL_BD_DIAMOND,
2814     EL_EMERALD_YELLOW,
2815     EL_EMERALD_RED,
2816     EL_EMERALD_PURPLE,
2817     EL_DIAMOND,
2818     EL_BOMB,
2819     EL_NUT,
2820     EL_AMOEBA_DROP,
2821     EL_TIME_ORB_FULL,
2822     EL_TIME_ORB_EMPTY,
2823     EL_SP_ZONK,
2824     EL_SP_INFOTRON,
2825     EL_SP_DISK_ORANGE,
2826     EL_PEARL,
2827     EL_CRYSTAL,
2828     EL_SPRING,
2829     EL_DX_SUPABOMB,
2830
2831     -1
2832   };
2833
2834   static int ep_can_smash_enemies[] =
2835   {
2836     EL_ROCK,
2837     EL_BD_ROCK,
2838     EL_SP_ZONK,
2839
2840     -1
2841   };
2842
2843   static int ep_can_smash_everything[] =
2844   {
2845     EL_ROCK,
2846     EL_BD_ROCK,
2847     EL_SP_ZONK,
2848
2849     -1
2850   };
2851
2852   static int ep_explodes_by_fire[] =
2853   {
2854     /* same elements as in 'ep_explodes_impact' */
2855     EL_BOMB,
2856     EL_SP_DISK_ORANGE,
2857     EL_DX_SUPABOMB,
2858
2859     /* same elements as in 'ep_explodes_smashed' */
2860     EL_SATELLITE,
2861     EL_PIG,
2862     EL_DRAGON,
2863     EL_MOLE,
2864
2865     /* new elements */
2866     EL_DYNAMITE,
2867     EL_DYNAMITE_ACTIVE,
2868     EL_EM_DYNAMITE,
2869     EL_EM_DYNAMITE_ACTIVE,
2870     EL_DYNABOMB_PLAYER_1_ACTIVE,
2871     EL_DYNABOMB_PLAYER_2_ACTIVE,
2872     EL_DYNABOMB_PLAYER_3_ACTIVE,
2873     EL_DYNABOMB_PLAYER_4_ACTIVE,
2874     EL_DYNABOMB_INCREASE_NUMBER,
2875     EL_DYNABOMB_INCREASE_SIZE,
2876     EL_DYNABOMB_INCREASE_POWER,
2877     EL_SP_DISK_RED_ACTIVE,
2878     EL_BUG,
2879     EL_PENGUIN,
2880     EL_SP_DISK_RED,
2881     EL_SP_DISK_YELLOW,
2882     EL_SP_SNIKSNAK,
2883     EL_SP_ELECTRON,
2884 #if 0
2885     EL_BLACK_ORB,
2886 #endif
2887
2888     -1
2889   };
2890
2891   static int ep_explodes_smashed[] =
2892   {
2893     /* same elements as in 'ep_explodes_impact' */
2894     EL_BOMB,
2895     EL_SP_DISK_ORANGE,
2896     EL_DX_SUPABOMB,
2897
2898     /* new elements */
2899     EL_SATELLITE,
2900     EL_PIG,
2901     EL_DRAGON,
2902     EL_MOLE,
2903
2904     -1
2905   };
2906
2907   static int ep_explodes_impact[] =
2908   {
2909     EL_BOMB,
2910     EL_SP_DISK_ORANGE,
2911     EL_DX_SUPABOMB,
2912
2913     -1
2914   };
2915
2916   static int ep_walkable_over[] =
2917   {
2918     EL_EMPTY_SPACE,
2919     EL_SP_EMPTY_SPACE,
2920     EL_SOKOBAN_FIELD_EMPTY,
2921     EL_EXIT_OPEN,
2922     EL_EM_EXIT_OPEN,
2923     EL_EM_EXIT_OPENING,
2924     EL_SP_EXIT_OPEN,
2925     EL_SP_EXIT_OPENING,
2926     EL_STEEL_EXIT_OPEN,
2927     EL_EM_STEEL_EXIT_OPEN,
2928     EL_EM_STEEL_EXIT_OPENING,
2929     EL_GATE_1,
2930     EL_GATE_2,
2931     EL_GATE_3,
2932     EL_GATE_4,
2933     EL_GATE_1_GRAY,
2934     EL_GATE_2_GRAY,
2935     EL_GATE_3_GRAY,
2936     EL_GATE_4_GRAY,
2937     EL_GATE_1_GRAY_ACTIVE,
2938     EL_GATE_2_GRAY_ACTIVE,
2939     EL_GATE_3_GRAY_ACTIVE,
2940     EL_GATE_4_GRAY_ACTIVE,
2941     EL_PENGUIN,
2942     EL_PIG,
2943     EL_DRAGON,
2944
2945     -1
2946   };
2947
2948   static int ep_walkable_inside[] =
2949   {
2950     EL_TUBE_ANY,
2951     EL_TUBE_VERTICAL,
2952     EL_TUBE_HORIZONTAL,
2953     EL_TUBE_VERTICAL_LEFT,
2954     EL_TUBE_VERTICAL_RIGHT,
2955     EL_TUBE_HORIZONTAL_UP,
2956     EL_TUBE_HORIZONTAL_DOWN,
2957     EL_TUBE_LEFT_UP,
2958     EL_TUBE_LEFT_DOWN,
2959     EL_TUBE_RIGHT_UP,
2960     EL_TUBE_RIGHT_DOWN,
2961
2962     -1
2963   };
2964
2965   static int ep_walkable_under[] =
2966   {
2967     -1
2968   };
2969
2970   static int ep_passable_over[] =
2971   {
2972     EL_EM_GATE_1,
2973     EL_EM_GATE_2,
2974     EL_EM_GATE_3,
2975     EL_EM_GATE_4,
2976     EL_EM_GATE_1_GRAY,
2977     EL_EM_GATE_2_GRAY,
2978     EL_EM_GATE_3_GRAY,
2979     EL_EM_GATE_4_GRAY,
2980     EL_EM_GATE_1_GRAY_ACTIVE,
2981     EL_EM_GATE_2_GRAY_ACTIVE,
2982     EL_EM_GATE_3_GRAY_ACTIVE,
2983     EL_EM_GATE_4_GRAY_ACTIVE,
2984     EL_EMC_GATE_5,
2985     EL_EMC_GATE_6,
2986     EL_EMC_GATE_7,
2987     EL_EMC_GATE_8,
2988     EL_EMC_GATE_5_GRAY,
2989     EL_EMC_GATE_6_GRAY,
2990     EL_EMC_GATE_7_GRAY,
2991     EL_EMC_GATE_8_GRAY,
2992     EL_EMC_GATE_5_GRAY_ACTIVE,
2993     EL_EMC_GATE_6_GRAY_ACTIVE,
2994     EL_EMC_GATE_7_GRAY_ACTIVE,
2995     EL_EMC_GATE_8_GRAY_ACTIVE,
2996     EL_DC_GATE_WHITE,
2997     EL_DC_GATE_WHITE_GRAY,
2998     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2999     EL_SWITCHGATE_OPEN,
3000     EL_TIMEGATE_OPEN,
3001
3002     -1
3003   };
3004
3005   static int ep_passable_inside[] =
3006   {
3007     EL_SP_PORT_LEFT,
3008     EL_SP_PORT_RIGHT,
3009     EL_SP_PORT_UP,
3010     EL_SP_PORT_DOWN,
3011     EL_SP_PORT_HORIZONTAL,
3012     EL_SP_PORT_VERTICAL,
3013     EL_SP_PORT_ANY,
3014     EL_SP_GRAVITY_PORT_LEFT,
3015     EL_SP_GRAVITY_PORT_RIGHT,
3016     EL_SP_GRAVITY_PORT_UP,
3017     EL_SP_GRAVITY_PORT_DOWN,
3018     EL_SP_GRAVITY_ON_PORT_LEFT,
3019     EL_SP_GRAVITY_ON_PORT_RIGHT,
3020     EL_SP_GRAVITY_ON_PORT_UP,
3021     EL_SP_GRAVITY_ON_PORT_DOWN,
3022     EL_SP_GRAVITY_OFF_PORT_LEFT,
3023     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3024     EL_SP_GRAVITY_OFF_PORT_UP,
3025     EL_SP_GRAVITY_OFF_PORT_DOWN,
3026
3027     -1
3028   };
3029
3030   static int ep_passable_under[] =
3031   {
3032     -1
3033   };
3034
3035   static int ep_droppable[] =
3036   {
3037     -1
3038   };
3039
3040   static int ep_explodes_1x1_old[] =
3041   {
3042     -1
3043   };
3044
3045   static int ep_pushable[] =
3046   {
3047     EL_ROCK,
3048     EL_BOMB,
3049     EL_DX_SUPABOMB,
3050     EL_NUT,
3051     EL_TIME_ORB_EMPTY,
3052     EL_SP_ZONK,
3053     EL_SP_DISK_ORANGE,
3054     EL_SPRING,
3055     EL_BD_ROCK,
3056     EL_SOKOBAN_OBJECT,
3057     EL_SOKOBAN_FIELD_FULL,
3058     EL_SATELLITE,
3059     EL_SP_DISK_YELLOW,
3060     EL_BALLOON,
3061     EL_EMC_ANDROID,
3062
3063     -1
3064   };
3065
3066   static int ep_explodes_cross_old[] =
3067   {
3068     -1
3069   };
3070
3071   static int ep_protected[] =
3072   {
3073     /* same elements as in 'ep_walkable_inside' */
3074     EL_TUBE_ANY,
3075     EL_TUBE_VERTICAL,
3076     EL_TUBE_HORIZONTAL,
3077     EL_TUBE_VERTICAL_LEFT,
3078     EL_TUBE_VERTICAL_RIGHT,
3079     EL_TUBE_HORIZONTAL_UP,
3080     EL_TUBE_HORIZONTAL_DOWN,
3081     EL_TUBE_LEFT_UP,
3082     EL_TUBE_LEFT_DOWN,
3083     EL_TUBE_RIGHT_UP,
3084     EL_TUBE_RIGHT_DOWN,
3085
3086     /* same elements as in 'ep_passable_over' */
3087     EL_EM_GATE_1,
3088     EL_EM_GATE_2,
3089     EL_EM_GATE_3,
3090     EL_EM_GATE_4,
3091     EL_EM_GATE_1_GRAY,
3092     EL_EM_GATE_2_GRAY,
3093     EL_EM_GATE_3_GRAY,
3094     EL_EM_GATE_4_GRAY,
3095     EL_EM_GATE_1_GRAY_ACTIVE,
3096     EL_EM_GATE_2_GRAY_ACTIVE,
3097     EL_EM_GATE_3_GRAY_ACTIVE,
3098     EL_EM_GATE_4_GRAY_ACTIVE,
3099     EL_EMC_GATE_5,
3100     EL_EMC_GATE_6,
3101     EL_EMC_GATE_7,
3102     EL_EMC_GATE_8,
3103     EL_EMC_GATE_5_GRAY,
3104     EL_EMC_GATE_6_GRAY,
3105     EL_EMC_GATE_7_GRAY,
3106     EL_EMC_GATE_8_GRAY,
3107     EL_EMC_GATE_5_GRAY_ACTIVE,
3108     EL_EMC_GATE_6_GRAY_ACTIVE,
3109     EL_EMC_GATE_7_GRAY_ACTIVE,
3110     EL_EMC_GATE_8_GRAY_ACTIVE,
3111     EL_DC_GATE_WHITE,
3112     EL_DC_GATE_WHITE_GRAY,
3113     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3114     EL_SWITCHGATE_OPEN,
3115     EL_TIMEGATE_OPEN,
3116
3117     /* same elements as in 'ep_passable_inside' */
3118     EL_SP_PORT_LEFT,
3119     EL_SP_PORT_RIGHT,
3120     EL_SP_PORT_UP,
3121     EL_SP_PORT_DOWN,
3122     EL_SP_PORT_HORIZONTAL,
3123     EL_SP_PORT_VERTICAL,
3124     EL_SP_PORT_ANY,
3125     EL_SP_GRAVITY_PORT_LEFT,
3126     EL_SP_GRAVITY_PORT_RIGHT,
3127     EL_SP_GRAVITY_PORT_UP,
3128     EL_SP_GRAVITY_PORT_DOWN,
3129     EL_SP_GRAVITY_ON_PORT_LEFT,
3130     EL_SP_GRAVITY_ON_PORT_RIGHT,
3131     EL_SP_GRAVITY_ON_PORT_UP,
3132     EL_SP_GRAVITY_ON_PORT_DOWN,
3133     EL_SP_GRAVITY_OFF_PORT_LEFT,
3134     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3135     EL_SP_GRAVITY_OFF_PORT_UP,
3136     EL_SP_GRAVITY_OFF_PORT_DOWN,
3137
3138     -1
3139   };
3140
3141   static int ep_throwable[] =
3142   {
3143     -1
3144   };
3145
3146   static int ep_can_explode[] =
3147   {
3148     /* same elements as in 'ep_explodes_impact' */
3149     EL_BOMB,
3150     EL_SP_DISK_ORANGE,
3151     EL_DX_SUPABOMB,
3152
3153     /* same elements as in 'ep_explodes_smashed' */
3154     EL_SATELLITE,
3155     EL_PIG,
3156     EL_DRAGON,
3157     EL_MOLE,
3158
3159     /* elements that can explode by explosion or by dragonfire */
3160     EL_DYNAMITE,
3161     EL_DYNAMITE_ACTIVE,
3162     EL_EM_DYNAMITE,
3163     EL_EM_DYNAMITE_ACTIVE,
3164     EL_DYNABOMB_PLAYER_1_ACTIVE,
3165     EL_DYNABOMB_PLAYER_2_ACTIVE,
3166     EL_DYNABOMB_PLAYER_3_ACTIVE,
3167     EL_DYNABOMB_PLAYER_4_ACTIVE,
3168     EL_DYNABOMB_INCREASE_NUMBER,
3169     EL_DYNABOMB_INCREASE_SIZE,
3170     EL_DYNABOMB_INCREASE_POWER,
3171     EL_SP_DISK_RED_ACTIVE,
3172     EL_BUG,
3173     EL_PENGUIN,
3174     EL_SP_DISK_RED,
3175     EL_SP_DISK_YELLOW,
3176     EL_SP_SNIKSNAK,
3177     EL_SP_ELECTRON,
3178
3179     /* elements that can explode only by explosion */
3180     EL_BLACK_ORB,
3181
3182     -1
3183   };
3184
3185   static int ep_gravity_reachable[] =
3186   {
3187     EL_SAND,
3188     EL_SP_BASE,
3189     EL_TRAP,
3190     EL_INVISIBLE_SAND,
3191     EL_INVISIBLE_SAND_ACTIVE,
3192     EL_SP_PORT_LEFT,
3193     EL_SP_PORT_RIGHT,
3194     EL_SP_PORT_UP,
3195     EL_SP_PORT_DOWN,
3196     EL_SP_PORT_HORIZONTAL,
3197     EL_SP_PORT_VERTICAL,
3198     EL_SP_PORT_ANY,
3199     EL_SP_GRAVITY_PORT_LEFT,
3200     EL_SP_GRAVITY_PORT_RIGHT,
3201     EL_SP_GRAVITY_PORT_UP,
3202     EL_SP_GRAVITY_PORT_DOWN,
3203     EL_SP_GRAVITY_ON_PORT_LEFT,
3204     EL_SP_GRAVITY_ON_PORT_RIGHT,
3205     EL_SP_GRAVITY_ON_PORT_UP,
3206     EL_SP_GRAVITY_ON_PORT_DOWN,
3207     EL_SP_GRAVITY_OFF_PORT_LEFT,
3208     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3209     EL_SP_GRAVITY_OFF_PORT_UP,
3210     EL_SP_GRAVITY_OFF_PORT_DOWN,
3211     EL_EMC_GRASS,
3212
3213     -1
3214   };
3215
3216   static int ep_player[] =
3217   {
3218     EL_PLAYER_1,
3219     EL_PLAYER_2,
3220     EL_PLAYER_3,
3221     EL_PLAYER_4,
3222     EL_SP_MURPHY,
3223     EL_SOKOBAN_FIELD_PLAYER,
3224     EL_TRIGGER_PLAYER,
3225
3226     -1
3227   };
3228
3229   static int ep_can_pass_magic_wall[] =
3230   {
3231     EL_ROCK,
3232     EL_BD_ROCK,
3233     EL_EMERALD,
3234     EL_BD_DIAMOND,
3235     EL_EMERALD_YELLOW,
3236     EL_EMERALD_RED,
3237     EL_EMERALD_PURPLE,
3238     EL_DIAMOND,
3239
3240     -1
3241   };
3242
3243   static int ep_can_pass_dc_magic_wall[] =
3244   {
3245     EL_ROCK,
3246     EL_BD_ROCK,
3247     EL_EMERALD,
3248     EL_BD_DIAMOND,
3249     EL_EMERALD_YELLOW,
3250     EL_EMERALD_RED,
3251     EL_EMERALD_PURPLE,
3252     EL_DIAMOND,
3253     EL_PEARL,
3254     EL_CRYSTAL,
3255
3256     -1
3257   };
3258
3259   static int ep_switchable[] =
3260   {
3261     EL_ROBOT_WHEEL,
3262     EL_SP_TERMINAL,
3263     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3264     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3265     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3266     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3267     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3268     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3269     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3270     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3271     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3272     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3273     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3274     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3275     EL_SWITCHGATE_SWITCH_UP,
3276     EL_SWITCHGATE_SWITCH_DOWN,
3277     EL_DC_SWITCHGATE_SWITCH_UP,
3278     EL_DC_SWITCHGATE_SWITCH_DOWN,
3279     EL_LIGHT_SWITCH,
3280     EL_LIGHT_SWITCH_ACTIVE,
3281     EL_TIMEGATE_SWITCH,
3282     EL_DC_TIMEGATE_SWITCH,
3283     EL_BALLOON_SWITCH_LEFT,
3284     EL_BALLOON_SWITCH_RIGHT,
3285     EL_BALLOON_SWITCH_UP,
3286     EL_BALLOON_SWITCH_DOWN,
3287     EL_BALLOON_SWITCH_ANY,
3288     EL_BALLOON_SWITCH_NONE,
3289     EL_LAMP,
3290     EL_TIME_ORB_FULL,
3291     EL_EMC_MAGIC_BALL_SWITCH,
3292     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3293
3294     -1
3295   };
3296
3297   static int ep_bd_element[] =
3298   {
3299     EL_EMPTY,
3300     EL_SAND,
3301     EL_WALL_SLIPPERY,
3302     EL_BD_WALL,
3303     EL_ROCK,
3304     EL_BD_ROCK,
3305     EL_BD_DIAMOND,
3306     EL_BD_MAGIC_WALL,
3307     EL_EXIT_CLOSED,
3308     EL_EXIT_OPEN,
3309     EL_STEELWALL,
3310     EL_PLAYER_1,
3311     EL_PLAYER_2,
3312     EL_PLAYER_3,
3313     EL_PLAYER_4,
3314     EL_BD_FIREFLY,
3315     EL_BD_FIREFLY_1,
3316     EL_BD_FIREFLY_2,
3317     EL_BD_FIREFLY_3,
3318     EL_BD_FIREFLY_4,
3319     EL_BD_BUTTERFLY,
3320     EL_BD_BUTTERFLY_1,
3321     EL_BD_BUTTERFLY_2,
3322     EL_BD_BUTTERFLY_3,
3323     EL_BD_BUTTERFLY_4,
3324     EL_BD_AMOEBA,
3325     EL_CHAR_QUESTION,
3326     EL_UNKNOWN,
3327
3328     -1
3329   };
3330
3331   static int ep_sp_element[] =
3332   {
3333     /* should always be valid */
3334     EL_EMPTY,
3335
3336     /* standard classic Supaplex elements */
3337     EL_SP_EMPTY,
3338     EL_SP_ZONK,
3339     EL_SP_BASE,
3340     EL_SP_MURPHY,
3341     EL_SP_INFOTRON,
3342     EL_SP_CHIP_SINGLE,
3343     EL_SP_HARDWARE_GRAY,
3344     EL_SP_EXIT_CLOSED,
3345     EL_SP_EXIT_OPEN,
3346     EL_SP_DISK_ORANGE,
3347     EL_SP_PORT_RIGHT,
3348     EL_SP_PORT_DOWN,
3349     EL_SP_PORT_LEFT,
3350     EL_SP_PORT_UP,
3351     EL_SP_GRAVITY_PORT_RIGHT,
3352     EL_SP_GRAVITY_PORT_DOWN,
3353     EL_SP_GRAVITY_PORT_LEFT,
3354     EL_SP_GRAVITY_PORT_UP,
3355     EL_SP_SNIKSNAK,
3356     EL_SP_DISK_YELLOW,
3357     EL_SP_TERMINAL,
3358     EL_SP_DISK_RED,
3359     EL_SP_PORT_VERTICAL,
3360     EL_SP_PORT_HORIZONTAL,
3361     EL_SP_PORT_ANY,
3362     EL_SP_ELECTRON,
3363     EL_SP_BUGGY_BASE,
3364     EL_SP_CHIP_LEFT,
3365     EL_SP_CHIP_RIGHT,
3366     EL_SP_HARDWARE_BASE_1,
3367     EL_SP_HARDWARE_GREEN,
3368     EL_SP_HARDWARE_BLUE,
3369     EL_SP_HARDWARE_RED,
3370     EL_SP_HARDWARE_YELLOW,
3371     EL_SP_HARDWARE_BASE_2,
3372     EL_SP_HARDWARE_BASE_3,
3373     EL_SP_HARDWARE_BASE_4,
3374     EL_SP_HARDWARE_BASE_5,
3375     EL_SP_HARDWARE_BASE_6,
3376     EL_SP_CHIP_TOP,
3377     EL_SP_CHIP_BOTTOM,
3378
3379     /* additional elements that appeared in newer Supaplex levels */
3380     EL_INVISIBLE_WALL,
3381
3382     /* additional gravity port elements (not switching, but setting gravity) */
3383     EL_SP_GRAVITY_ON_PORT_LEFT,
3384     EL_SP_GRAVITY_ON_PORT_RIGHT,
3385     EL_SP_GRAVITY_ON_PORT_UP,
3386     EL_SP_GRAVITY_ON_PORT_DOWN,
3387     EL_SP_GRAVITY_OFF_PORT_LEFT,
3388     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3389     EL_SP_GRAVITY_OFF_PORT_UP,
3390     EL_SP_GRAVITY_OFF_PORT_DOWN,
3391
3392     /* more than one Murphy in a level results in an inactive clone */
3393     EL_SP_MURPHY_CLONE,
3394
3395     /* runtime Supaplex elements */
3396     EL_SP_DISK_RED_ACTIVE,
3397     EL_SP_TERMINAL_ACTIVE,
3398     EL_SP_BUGGY_BASE_ACTIVATING,
3399     EL_SP_BUGGY_BASE_ACTIVE,
3400     EL_SP_EXIT_OPENING,
3401     EL_SP_EXIT_CLOSING,
3402
3403     -1
3404   };
3405
3406   static int ep_sb_element[] =
3407   {
3408     EL_EMPTY,
3409     EL_STEELWALL,
3410     EL_SOKOBAN_OBJECT,
3411     EL_SOKOBAN_FIELD_EMPTY,
3412     EL_SOKOBAN_FIELD_FULL,
3413     EL_SOKOBAN_FIELD_PLAYER,
3414     EL_PLAYER_1,
3415     EL_PLAYER_2,
3416     EL_PLAYER_3,
3417     EL_PLAYER_4,
3418     EL_INVISIBLE_STEELWALL,
3419
3420     -1
3421   };
3422
3423   static int ep_gem[] =
3424   {
3425     EL_BD_DIAMOND,
3426     EL_EMERALD,
3427     EL_EMERALD_YELLOW,
3428     EL_EMERALD_RED,
3429     EL_EMERALD_PURPLE,
3430     EL_DIAMOND,
3431
3432     -1
3433   };
3434
3435   static int ep_food_dark_yamyam[] =
3436   {
3437     EL_SAND,
3438     EL_BUG,
3439     EL_SPACESHIP,
3440     EL_BD_BUTTERFLY,
3441     EL_BD_FIREFLY,
3442     EL_YAMYAM,
3443     EL_ROBOT,
3444     EL_PACMAN,
3445     EL_AMOEBA_DROP,
3446     EL_AMOEBA_DEAD,
3447     EL_AMOEBA_WET,
3448     EL_AMOEBA_DRY,
3449     EL_AMOEBA_FULL,
3450     EL_BD_AMOEBA,
3451     EL_EMERALD,
3452     EL_BD_DIAMOND,
3453     EL_EMERALD_YELLOW,
3454     EL_EMERALD_RED,
3455     EL_EMERALD_PURPLE,
3456     EL_DIAMOND,
3457     EL_PEARL,
3458     EL_CRYSTAL,
3459
3460     -1
3461   };
3462
3463   static int ep_food_penguin[] =
3464   {
3465     EL_EMERALD,
3466     EL_BD_DIAMOND,
3467     EL_EMERALD_YELLOW,
3468     EL_EMERALD_RED,
3469     EL_EMERALD_PURPLE,
3470     EL_DIAMOND,
3471     EL_PEARL,
3472     EL_CRYSTAL,
3473
3474     -1
3475   };
3476
3477   static int ep_food_pig[] =
3478   {
3479     EL_EMERALD,
3480     EL_BD_DIAMOND,
3481     EL_EMERALD_YELLOW,
3482     EL_EMERALD_RED,
3483     EL_EMERALD_PURPLE,
3484     EL_DIAMOND,
3485
3486     -1
3487   };
3488
3489   static int ep_historic_wall[] =
3490   {
3491     EL_STEELWALL,
3492     EL_GATE_1,
3493     EL_GATE_2,
3494     EL_GATE_3,
3495     EL_GATE_4,
3496     EL_GATE_1_GRAY,
3497     EL_GATE_2_GRAY,
3498     EL_GATE_3_GRAY,
3499     EL_GATE_4_GRAY,
3500     EL_GATE_1_GRAY_ACTIVE,
3501     EL_GATE_2_GRAY_ACTIVE,
3502     EL_GATE_3_GRAY_ACTIVE,
3503     EL_GATE_4_GRAY_ACTIVE,
3504     EL_EM_GATE_1,
3505     EL_EM_GATE_2,
3506     EL_EM_GATE_3,
3507     EL_EM_GATE_4,
3508     EL_EM_GATE_1_GRAY,
3509     EL_EM_GATE_2_GRAY,
3510     EL_EM_GATE_3_GRAY,
3511     EL_EM_GATE_4_GRAY,
3512     EL_EM_GATE_1_GRAY_ACTIVE,
3513     EL_EM_GATE_2_GRAY_ACTIVE,
3514     EL_EM_GATE_3_GRAY_ACTIVE,
3515     EL_EM_GATE_4_GRAY_ACTIVE,
3516     EL_EXIT_CLOSED,
3517     EL_EXIT_OPENING,
3518     EL_EXIT_OPEN,
3519     EL_WALL,
3520     EL_WALL_SLIPPERY,
3521     EL_EXPANDABLE_WALL,
3522     EL_EXPANDABLE_WALL_HORIZONTAL,
3523     EL_EXPANDABLE_WALL_VERTICAL,
3524     EL_EXPANDABLE_WALL_ANY,
3525     EL_EXPANDABLE_WALL_GROWING,
3526     EL_BD_EXPANDABLE_WALL,
3527     EL_BD_WALL,
3528     EL_SP_CHIP_SINGLE,
3529     EL_SP_CHIP_LEFT,
3530     EL_SP_CHIP_RIGHT,
3531     EL_SP_CHIP_TOP,
3532     EL_SP_CHIP_BOTTOM,
3533     EL_SP_HARDWARE_GRAY,
3534     EL_SP_HARDWARE_GREEN,
3535     EL_SP_HARDWARE_BLUE,
3536     EL_SP_HARDWARE_RED,
3537     EL_SP_HARDWARE_YELLOW,
3538     EL_SP_HARDWARE_BASE_1,
3539     EL_SP_HARDWARE_BASE_2,
3540     EL_SP_HARDWARE_BASE_3,
3541     EL_SP_HARDWARE_BASE_4,
3542     EL_SP_HARDWARE_BASE_5,
3543     EL_SP_HARDWARE_BASE_6,
3544     EL_SP_TERMINAL,
3545     EL_SP_TERMINAL_ACTIVE,
3546     EL_SP_EXIT_CLOSED,
3547     EL_SP_EXIT_OPEN,
3548     EL_INVISIBLE_STEELWALL,
3549     EL_INVISIBLE_STEELWALL_ACTIVE,
3550     EL_INVISIBLE_WALL,
3551     EL_INVISIBLE_WALL_ACTIVE,
3552     EL_STEELWALL_SLIPPERY,
3553     EL_EMC_STEELWALL_1,
3554     EL_EMC_STEELWALL_2,
3555     EL_EMC_STEELWALL_3,
3556     EL_EMC_STEELWALL_4,
3557     EL_EMC_WALL_1,
3558     EL_EMC_WALL_2,
3559     EL_EMC_WALL_3,
3560     EL_EMC_WALL_4,
3561     EL_EMC_WALL_5,
3562     EL_EMC_WALL_6,
3563     EL_EMC_WALL_7,
3564     EL_EMC_WALL_8,
3565
3566     -1
3567   };
3568
3569   static int ep_historic_solid[] =
3570   {
3571     EL_WALL,
3572     EL_EXPANDABLE_WALL,
3573     EL_EXPANDABLE_WALL_HORIZONTAL,
3574     EL_EXPANDABLE_WALL_VERTICAL,
3575     EL_EXPANDABLE_WALL_ANY,
3576     EL_BD_EXPANDABLE_WALL,
3577     EL_BD_WALL,
3578     EL_WALL_SLIPPERY,
3579     EL_EXIT_CLOSED,
3580     EL_EXIT_OPENING,
3581     EL_EXIT_OPEN,
3582     EL_AMOEBA_DEAD,
3583     EL_AMOEBA_WET,
3584     EL_AMOEBA_DRY,
3585     EL_AMOEBA_FULL,
3586     EL_BD_AMOEBA,
3587     EL_QUICKSAND_EMPTY,
3588     EL_QUICKSAND_FULL,
3589     EL_QUICKSAND_FILLING,
3590     EL_QUICKSAND_EMPTYING,
3591     EL_MAGIC_WALL,
3592     EL_MAGIC_WALL_ACTIVE,
3593     EL_MAGIC_WALL_EMPTYING,
3594     EL_MAGIC_WALL_FILLING,
3595     EL_MAGIC_WALL_FULL,
3596     EL_MAGIC_WALL_DEAD,
3597     EL_BD_MAGIC_WALL,
3598     EL_BD_MAGIC_WALL_ACTIVE,
3599     EL_BD_MAGIC_WALL_EMPTYING,
3600     EL_BD_MAGIC_WALL_FULL,
3601     EL_BD_MAGIC_WALL_FILLING,
3602     EL_BD_MAGIC_WALL_DEAD,
3603     EL_GAME_OF_LIFE,
3604     EL_BIOMAZE,
3605     EL_SP_CHIP_SINGLE,
3606     EL_SP_CHIP_LEFT,
3607     EL_SP_CHIP_RIGHT,
3608     EL_SP_CHIP_TOP,
3609     EL_SP_CHIP_BOTTOM,
3610     EL_SP_TERMINAL,
3611     EL_SP_TERMINAL_ACTIVE,
3612     EL_SP_EXIT_CLOSED,
3613     EL_SP_EXIT_OPEN,
3614     EL_INVISIBLE_WALL,
3615     EL_INVISIBLE_WALL_ACTIVE,
3616     EL_SWITCHGATE_SWITCH_UP,
3617     EL_SWITCHGATE_SWITCH_DOWN,
3618     EL_DC_SWITCHGATE_SWITCH_UP,
3619     EL_DC_SWITCHGATE_SWITCH_DOWN,
3620     EL_TIMEGATE_SWITCH,
3621     EL_TIMEGATE_SWITCH_ACTIVE,
3622     EL_DC_TIMEGATE_SWITCH,
3623     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3624     EL_EMC_WALL_1,
3625     EL_EMC_WALL_2,
3626     EL_EMC_WALL_3,
3627     EL_EMC_WALL_4,
3628     EL_EMC_WALL_5,
3629     EL_EMC_WALL_6,
3630     EL_EMC_WALL_7,
3631     EL_EMC_WALL_8,
3632     EL_WALL_PEARL,
3633     EL_WALL_CRYSTAL,
3634
3635     /* the following elements are a direct copy of "indestructible" elements,
3636        except "EL_ACID", which is "indestructible", but not "solid"! */
3637 #if 0
3638     EL_ACID,
3639 #endif
3640     EL_STEELWALL,
3641     EL_ACID_POOL_TOPLEFT,
3642     EL_ACID_POOL_TOPRIGHT,
3643     EL_ACID_POOL_BOTTOMLEFT,
3644     EL_ACID_POOL_BOTTOM,
3645     EL_ACID_POOL_BOTTOMRIGHT,
3646     EL_SP_HARDWARE_GRAY,
3647     EL_SP_HARDWARE_GREEN,
3648     EL_SP_HARDWARE_BLUE,
3649     EL_SP_HARDWARE_RED,
3650     EL_SP_HARDWARE_YELLOW,
3651     EL_SP_HARDWARE_BASE_1,
3652     EL_SP_HARDWARE_BASE_2,
3653     EL_SP_HARDWARE_BASE_3,
3654     EL_SP_HARDWARE_BASE_4,
3655     EL_SP_HARDWARE_BASE_5,
3656     EL_SP_HARDWARE_BASE_6,
3657     EL_INVISIBLE_STEELWALL,
3658     EL_INVISIBLE_STEELWALL_ACTIVE,
3659     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3660     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3661     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3662     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3663     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3664     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3665     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3666     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3667     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3668     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3669     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3670     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3671     EL_LIGHT_SWITCH,
3672     EL_LIGHT_SWITCH_ACTIVE,
3673     EL_SIGN_EXCLAMATION,
3674     EL_SIGN_RADIOACTIVITY,
3675     EL_SIGN_STOP,
3676     EL_SIGN_WHEELCHAIR,
3677     EL_SIGN_PARKING,
3678     EL_SIGN_NO_ENTRY,
3679     EL_SIGN_UNUSED_1,
3680     EL_SIGN_GIVE_WAY,
3681     EL_SIGN_ENTRY_FORBIDDEN,
3682     EL_SIGN_EMERGENCY_EXIT,
3683     EL_SIGN_YIN_YANG,
3684     EL_SIGN_UNUSED_2,
3685     EL_SIGN_SPERMS,
3686     EL_SIGN_BULLET,
3687     EL_SIGN_HEART,
3688     EL_SIGN_CROSS,
3689     EL_SIGN_FRANKIE,
3690     EL_STEEL_EXIT_CLOSED,
3691     EL_STEEL_EXIT_OPEN,
3692     EL_DC_STEELWALL_1_LEFT,
3693     EL_DC_STEELWALL_1_RIGHT,
3694     EL_DC_STEELWALL_1_TOP,
3695     EL_DC_STEELWALL_1_BOTTOM,
3696     EL_DC_STEELWALL_1_HORIZONTAL,
3697     EL_DC_STEELWALL_1_VERTICAL,
3698     EL_DC_STEELWALL_1_TOPLEFT,
3699     EL_DC_STEELWALL_1_TOPRIGHT,
3700     EL_DC_STEELWALL_1_BOTTOMLEFT,
3701     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3702     EL_DC_STEELWALL_1_TOPLEFT_2,
3703     EL_DC_STEELWALL_1_TOPRIGHT_2,
3704     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3705     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3706     EL_DC_STEELWALL_2_LEFT,
3707     EL_DC_STEELWALL_2_RIGHT,
3708     EL_DC_STEELWALL_2_TOP,
3709     EL_DC_STEELWALL_2_BOTTOM,
3710     EL_DC_STEELWALL_2_HORIZONTAL,
3711     EL_DC_STEELWALL_2_VERTICAL,
3712     EL_DC_STEELWALL_2_MIDDLE,
3713     EL_DC_STEELWALL_2_SINGLE,
3714     EL_STEELWALL_SLIPPERY,
3715     EL_EMC_STEELWALL_1,
3716     EL_EMC_STEELWALL_2,
3717     EL_EMC_STEELWALL_3,
3718     EL_EMC_STEELWALL_4,
3719     EL_CRYSTAL,
3720     EL_GATE_1,
3721     EL_GATE_2,
3722     EL_GATE_3,
3723     EL_GATE_4,
3724     EL_GATE_1_GRAY,
3725     EL_GATE_2_GRAY,
3726     EL_GATE_3_GRAY,
3727     EL_GATE_4_GRAY,
3728     EL_GATE_1_GRAY_ACTIVE,
3729     EL_GATE_2_GRAY_ACTIVE,
3730     EL_GATE_3_GRAY_ACTIVE,
3731     EL_GATE_4_GRAY_ACTIVE,
3732     EL_EM_GATE_1,
3733     EL_EM_GATE_2,
3734     EL_EM_GATE_3,
3735     EL_EM_GATE_4,
3736     EL_EM_GATE_1_GRAY,
3737     EL_EM_GATE_2_GRAY,
3738     EL_EM_GATE_3_GRAY,
3739     EL_EM_GATE_4_GRAY,
3740     EL_EM_GATE_1_GRAY_ACTIVE,
3741     EL_EM_GATE_2_GRAY_ACTIVE,
3742     EL_EM_GATE_3_GRAY_ACTIVE,
3743     EL_EM_GATE_4_GRAY_ACTIVE,
3744     EL_SWITCHGATE_OPEN,
3745     EL_SWITCHGATE_OPENING,
3746     EL_SWITCHGATE_CLOSED,
3747     EL_SWITCHGATE_CLOSING,
3748     EL_TIMEGATE_OPEN,
3749     EL_TIMEGATE_OPENING,
3750     EL_TIMEGATE_CLOSED,
3751     EL_TIMEGATE_CLOSING,
3752     EL_TUBE_ANY,
3753     EL_TUBE_VERTICAL,
3754     EL_TUBE_HORIZONTAL,
3755     EL_TUBE_VERTICAL_LEFT,
3756     EL_TUBE_VERTICAL_RIGHT,
3757     EL_TUBE_HORIZONTAL_UP,
3758     EL_TUBE_HORIZONTAL_DOWN,
3759     EL_TUBE_LEFT_UP,
3760     EL_TUBE_LEFT_DOWN,
3761     EL_TUBE_RIGHT_UP,
3762     EL_TUBE_RIGHT_DOWN,
3763
3764     -1
3765   };
3766
3767   static int ep_classic_enemy[] =
3768   {
3769     EL_BUG,
3770     EL_SPACESHIP,
3771     EL_BD_BUTTERFLY,
3772     EL_BD_FIREFLY,
3773
3774     EL_YAMYAM,
3775     EL_DARK_YAMYAM,
3776     EL_ROBOT,
3777     EL_PACMAN,
3778     EL_SP_SNIKSNAK,
3779     EL_SP_ELECTRON,
3780
3781     -1
3782   };
3783
3784   static int ep_belt[] =
3785   {
3786     EL_CONVEYOR_BELT_1_LEFT,
3787     EL_CONVEYOR_BELT_1_MIDDLE,
3788     EL_CONVEYOR_BELT_1_RIGHT,
3789     EL_CONVEYOR_BELT_2_LEFT,
3790     EL_CONVEYOR_BELT_2_MIDDLE,
3791     EL_CONVEYOR_BELT_2_RIGHT,
3792     EL_CONVEYOR_BELT_3_LEFT,
3793     EL_CONVEYOR_BELT_3_MIDDLE,
3794     EL_CONVEYOR_BELT_3_RIGHT,
3795     EL_CONVEYOR_BELT_4_LEFT,
3796     EL_CONVEYOR_BELT_4_MIDDLE,
3797     EL_CONVEYOR_BELT_4_RIGHT,
3798
3799     -1
3800   };
3801
3802   static int ep_belt_active[] =
3803   {
3804     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3805     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3806     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3807     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3808     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3809     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3810     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3811     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3812     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3813     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3814     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3815     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3816
3817     -1
3818   };
3819
3820   static int ep_belt_switch[] =
3821   {
3822     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3823     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3824     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3825     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3826     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3827     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3828     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3829     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3830     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3831     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3832     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3833     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3834
3835     -1
3836   };
3837
3838   static int ep_tube[] =
3839   {
3840     EL_TUBE_LEFT_UP,
3841     EL_TUBE_LEFT_DOWN,
3842     EL_TUBE_RIGHT_UP,
3843     EL_TUBE_RIGHT_DOWN,
3844     EL_TUBE_HORIZONTAL,
3845     EL_TUBE_HORIZONTAL_UP,
3846     EL_TUBE_HORIZONTAL_DOWN,
3847     EL_TUBE_VERTICAL,
3848     EL_TUBE_VERTICAL_LEFT,
3849     EL_TUBE_VERTICAL_RIGHT,
3850     EL_TUBE_ANY,
3851
3852     -1
3853   };
3854
3855   static int ep_acid_pool[] =
3856   {
3857     EL_ACID_POOL_TOPLEFT,
3858     EL_ACID_POOL_TOPRIGHT,
3859     EL_ACID_POOL_BOTTOMLEFT,
3860     EL_ACID_POOL_BOTTOM,
3861     EL_ACID_POOL_BOTTOMRIGHT,
3862
3863     -1
3864   };
3865
3866   static int ep_keygate[] =
3867   {
3868     EL_GATE_1,
3869     EL_GATE_2,
3870     EL_GATE_3,
3871     EL_GATE_4,
3872     EL_GATE_1_GRAY,
3873     EL_GATE_2_GRAY,
3874     EL_GATE_3_GRAY,
3875     EL_GATE_4_GRAY,
3876     EL_GATE_1_GRAY_ACTIVE,
3877     EL_GATE_2_GRAY_ACTIVE,
3878     EL_GATE_3_GRAY_ACTIVE,
3879     EL_GATE_4_GRAY_ACTIVE,
3880     EL_EM_GATE_1,
3881     EL_EM_GATE_2,
3882     EL_EM_GATE_3,
3883     EL_EM_GATE_4,
3884     EL_EM_GATE_1_GRAY,
3885     EL_EM_GATE_2_GRAY,
3886     EL_EM_GATE_3_GRAY,
3887     EL_EM_GATE_4_GRAY,
3888     EL_EM_GATE_1_GRAY_ACTIVE,
3889     EL_EM_GATE_2_GRAY_ACTIVE,
3890     EL_EM_GATE_3_GRAY_ACTIVE,
3891     EL_EM_GATE_4_GRAY_ACTIVE,
3892     EL_EMC_GATE_5,
3893     EL_EMC_GATE_6,
3894     EL_EMC_GATE_7,
3895     EL_EMC_GATE_8,
3896     EL_EMC_GATE_5_GRAY,
3897     EL_EMC_GATE_6_GRAY,
3898     EL_EMC_GATE_7_GRAY,
3899     EL_EMC_GATE_8_GRAY,
3900     EL_EMC_GATE_5_GRAY_ACTIVE,
3901     EL_EMC_GATE_6_GRAY_ACTIVE,
3902     EL_EMC_GATE_7_GRAY_ACTIVE,
3903     EL_EMC_GATE_8_GRAY_ACTIVE,
3904     EL_DC_GATE_WHITE,
3905     EL_DC_GATE_WHITE_GRAY,
3906     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3907
3908     -1
3909   };
3910
3911   static int ep_amoeboid[] =
3912   {
3913     EL_AMOEBA_DEAD,
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_amoebalive[] =
3924   {
3925     EL_AMOEBA_WET,
3926     EL_AMOEBA_DRY,
3927     EL_AMOEBA_FULL,
3928     EL_BD_AMOEBA,
3929     EL_EMC_DRIPPER,
3930
3931     -1
3932   };
3933
3934   static int ep_has_editor_content[] =
3935   {
3936     EL_PLAYER_1,
3937     EL_PLAYER_2,
3938     EL_PLAYER_3,
3939     EL_PLAYER_4,
3940     EL_SOKOBAN_FIELD_PLAYER,
3941     EL_SP_MURPHY,
3942     EL_YAMYAM,
3943     EL_YAMYAM_LEFT,
3944     EL_YAMYAM_RIGHT,
3945     EL_YAMYAM_UP,
3946     EL_YAMYAM_DOWN,
3947     EL_AMOEBA_WET,
3948     EL_AMOEBA_DRY,
3949     EL_AMOEBA_FULL,
3950     EL_BD_AMOEBA,
3951     EL_EMC_MAGIC_BALL,
3952     EL_EMC_ANDROID,
3953
3954     -1
3955   };
3956
3957   static int ep_can_turn_each_move[] =
3958   {
3959     /* !!! do something with this one !!! */
3960     -1
3961   };
3962
3963   static int ep_can_grow[] =
3964   {
3965     EL_BD_AMOEBA,
3966     EL_AMOEBA_DROP,
3967     EL_AMOEBA_WET,
3968     EL_AMOEBA_DRY,
3969     EL_AMOEBA_FULL,
3970     EL_GAME_OF_LIFE,
3971     EL_BIOMAZE,
3972     EL_EMC_DRIPPER,
3973
3974     -1
3975   };
3976
3977   static int ep_active_bomb[] =
3978   {
3979     EL_DYNAMITE_ACTIVE,
3980     EL_EM_DYNAMITE_ACTIVE,
3981     EL_DYNABOMB_PLAYER_1_ACTIVE,
3982     EL_DYNABOMB_PLAYER_2_ACTIVE,
3983     EL_DYNABOMB_PLAYER_3_ACTIVE,
3984     EL_DYNABOMB_PLAYER_4_ACTIVE,
3985     EL_SP_DISK_RED_ACTIVE,
3986
3987     -1
3988   };
3989
3990   static int ep_inactive[] =
3991   {
3992     EL_EMPTY,
3993     EL_SAND,