fixed error output for out-of-bounds graphic definitions
[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 void InitScaledImages()
223 {
224   int i;
225
226   /* scale normal images from static configuration, if not already scaled */
227   for (i = 0; i < NUM_IMAGE_FILES; i++)
228     ScaleImage(i, graphic_info[i].scale_up_factor);
229 }
230
231 void InitBitmapPointers()
232 {
233   int num_images = getImageListSize();
234   int i;
235
236   // standard size bitmap may have changed -- update default bitmap pointer
237   for (i = 0; i < num_images; i++)
238     if (graphic_info[i].bitmaps)
239       graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
240 }
241
242 void InitImageTextures()
243 {
244   int i, j, k;
245
246   FreeAllImageTextures();
247
248   for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
249     CreateImageTextures(i);
250
251   for (i = 0; i < MAX_NUM_TOONS; i++)
252     CreateImageTextures(IMG_TOON_1 + i);
253
254   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
255   {
256     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
257     {
258       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
259       {
260         int graphic = global_anim_info[i].graphic[j][k];
261
262         if (graphic == IMG_UNDEFINED)
263           continue;
264
265         CreateImageTextures(graphic);
266       }
267     }
268   }
269 }
270
271 #if 1
272 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
273 void SetBitmaps_EM(Bitmap **em_bitmap)
274 {
275   em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
276   em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].bitmap;
277 }
278 #endif
279
280 #if 0
281 /* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
282 void SetBitmaps_SP(Bitmap **sp_bitmap)
283 {
284   *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
285 }
286 #endif
287
288 static int getFontBitmapID(int font_nr)
289 {
290   int special = -1;
291
292   /* (special case: do not use special font for GAME_MODE_LOADING) */
293   if (game_status >= GAME_MODE_TITLE_INITIAL &&
294       game_status <= GAME_MODE_PSEUDO_PREVIEW)
295     special = game_status;
296   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
297     special = GFX_SPECIAL_ARG_MAIN;
298
299   if (special != -1)
300     return font_info[font_nr].special_bitmap_id[special];
301   else
302     return font_nr;
303 }
304
305 static int getFontFromToken(char *token)
306 {
307   char *value = getHashEntry(font_token_hash, token);
308
309   if (value != NULL)
310     return atoi(value);
311
312   /* if font not found, use reliable default value */
313   return FONT_INITIAL_1;
314 }
315
316 void InitFontGraphicInfo()
317 {
318   static struct FontBitmapInfo *font_bitmap_info = NULL;
319   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
320   int num_property_mappings = getImageListPropertyMappingSize();
321   int num_font_bitmaps = NUM_FONTS;
322   int i, j;
323
324   if (graphic_info == NULL)             /* still at startup phase */
325   {
326     InitFontInfo(font_initial, NUM_INITIAL_FONTS,
327                  getFontBitmapID, getFontFromToken);
328
329     return;
330   }
331
332   /* ---------- initialize font graphic definitions ---------- */
333
334   /* always start with reliable default values (normal font graphics) */
335   for (i = 0; i < NUM_FONTS; i++)
336     font_info[i].graphic = IMG_FONT_INITIAL_1;
337
338   /* initialize normal font/graphic mapping from static configuration */
339   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
340   {
341     int font_nr = font_to_graphic[i].font_nr;
342     int special = font_to_graphic[i].special;
343     int graphic = font_to_graphic[i].graphic;
344
345     if (special != -1)
346       continue;
347
348     font_info[font_nr].graphic = graphic;
349   }
350
351   /* always start with reliable default values (special font graphics) */
352   for (i = 0; i < NUM_FONTS; i++)
353   {
354     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
355     {
356       font_info[i].special_graphic[j] = font_info[i].graphic;
357       font_info[i].special_bitmap_id[j] = i;
358     }
359   }
360
361   /* initialize special font/graphic mapping from static configuration */
362   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
363   {
364     int font_nr      = font_to_graphic[i].font_nr;
365     int special      = font_to_graphic[i].special;
366     int graphic      = font_to_graphic[i].graphic;
367     int base_graphic = font2baseimg(font_nr);
368
369     if (IS_SPECIAL_GFX_ARG(special))
370     {
371       boolean base_redefined =
372         getImageListEntryFromImageID(base_graphic)->redefined;
373       boolean special_redefined =
374         getImageListEntryFromImageID(graphic)->redefined;
375       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
376
377       /* if the base font ("font.title_1", for example) has been redefined,
378          but not the special font ("font.title_1.LEVELS", for example), do not
379          use an existing (in this case considered obsolete) special font
380          anymore, but use the automatically determined default font */
381       /* special case: cloned special fonts must be explicitly redefined,
382          but are not automatically redefined by redefining base font */
383       if (base_redefined && !special_redefined && !special_cloned)
384         continue;
385
386       font_info[font_nr].special_graphic[special] = graphic;
387       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
388       num_font_bitmaps++;
389     }
390   }
391
392   /* initialize special font/graphic mapping from dynamic configuration */
393   for (i = 0; i < num_property_mappings; i++)
394   {
395     int font_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
396     int special = property_mapping[i].ext3_index;
397     int graphic = property_mapping[i].artwork_index;
398
399     if (font_nr < 0)
400       continue;
401
402     if (IS_SPECIAL_GFX_ARG(special))
403     {
404       font_info[font_nr].special_graphic[special] = graphic;
405       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
406       num_font_bitmaps++;
407     }
408   }
409
410   /* correct special font/graphic mapping for cloned fonts for downwards
411      compatibility of PREVIEW fonts -- this is only needed for implicit
412      redefinition of special font by redefined base font, and only if other
413      fonts are cloned from this special font (like in the "Zelda" level set) */
414   for (i = 0; font_to_graphic[i].font_nr > -1; i++)
415   {
416     int font_nr = font_to_graphic[i].font_nr;
417     int special = font_to_graphic[i].special;
418     int graphic = font_to_graphic[i].graphic;
419
420     if (IS_SPECIAL_GFX_ARG(special))
421     {
422       boolean special_redefined =
423         getImageListEntryFromImageID(graphic)->redefined;
424       boolean special_cloned = (graphic_info[graphic].clone_from != -1);
425
426       if (special_cloned && !special_redefined)
427       {
428         int j;
429
430         for (j = 0; font_to_graphic[j].font_nr > -1; j++)
431         {
432           int font_nr2 = font_to_graphic[j].font_nr;
433           int special2 = font_to_graphic[j].special;
434           int graphic2 = font_to_graphic[j].graphic;
435
436           if (IS_SPECIAL_GFX_ARG(special2) &&
437               graphic2 == graphic_info[graphic].clone_from)
438           {
439             font_info[font_nr].special_graphic[special] =
440               font_info[font_nr2].special_graphic[special2];
441             font_info[font_nr].special_bitmap_id[special] =
442               font_info[font_nr2].special_bitmap_id[special2];
443           }
444         }
445       }
446     }
447   }
448
449   /* reset non-redefined ".active" font graphics if normal font is redefined */
450   /* (this different treatment is needed because normal and active fonts are
451      independently defined ("active" is not a property of font definitions!) */
452   for (i = 0; i < NUM_FONTS; i++)
453   {
454     int font_nr_base = i;
455     int font_nr_active = FONT_ACTIVE(font_nr_base);
456
457     /* check only those fonts with exist as normal and ".active" variant */
458     if (font_nr_base != font_nr_active)
459     {
460       int base_graphic = font_info[font_nr_base].graphic;
461       int active_graphic = font_info[font_nr_active].graphic;
462       boolean base_redefined =
463         getImageListEntryFromImageID(base_graphic)->redefined;
464       boolean active_redefined =
465         getImageListEntryFromImageID(active_graphic)->redefined;
466
467       /* if the base font ("font.menu_1", for example) has been redefined,
468          but not the active font ("font.menu_1.active", for example), do not
469          use an existing (in this case considered obsolete) active font
470          anymore, but use the automatically determined default font */
471       if (base_redefined && !active_redefined)
472         font_info[font_nr_active].graphic = base_graphic;
473
474       /* now also check each "special" font (which may be the same as above) */
475       for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
476       {
477         int base_graphic = font_info[font_nr_base].special_graphic[j];
478         int active_graphic = font_info[font_nr_active].special_graphic[j];
479         boolean base_redefined =
480           getImageListEntryFromImageID(base_graphic)->redefined;
481         boolean active_redefined =
482           getImageListEntryFromImageID(active_graphic)->redefined;
483
484         /* same as above, but check special graphic definitions, for example:
485            redefined "font.menu_1.MAIN" invalidates "font.menu_1.active.MAIN" */
486         if (base_redefined && !active_redefined)
487         {
488           font_info[font_nr_active].special_graphic[j] =
489             font_info[font_nr_base].special_graphic[j];
490           font_info[font_nr_active].special_bitmap_id[j] =
491             font_info[font_nr_base].special_bitmap_id[j];
492         }
493       }
494     }
495   }
496
497   /* ---------- initialize font bitmap array ---------- */
498
499   if (font_bitmap_info != NULL)
500     FreeFontInfo(font_bitmap_info);
501
502   font_bitmap_info =
503     checked_calloc(num_font_bitmaps * sizeof(struct FontBitmapInfo));
504
505   /* ---------- initialize font bitmap definitions ---------- */
506
507   for (i = 0; i < NUM_FONTS; i++)
508   {
509     if (i < NUM_INITIAL_FONTS)
510     {
511       font_bitmap_info[i] = font_initial[i];
512       continue;
513     }
514
515     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
516     {
517       int font_bitmap_id = font_info[i].special_bitmap_id[j];
518       int graphic = font_info[i].special_graphic[j];
519
520       /* set 'graphic_info' for font entries, if uninitialized (guessed) */
521       if (graphic_info[graphic].anim_frames < MIN_NUM_CHARS_PER_FONT)
522       {
523         graphic_info[graphic].anim_frames = DEFAULT_NUM_CHARS_PER_FONT;
524         graphic_info[graphic].anim_frames_per_line = DEFAULT_NUM_CHARS_PER_LINE;
525       }
526
527       /* copy font relevant information from graphics information */
528       font_bitmap_info[font_bitmap_id].bitmap = graphic_info[graphic].bitmap;
529       font_bitmap_info[font_bitmap_id].src_x  = graphic_info[graphic].src_x;
530       font_bitmap_info[font_bitmap_id].src_y  = graphic_info[graphic].src_y;
531       font_bitmap_info[font_bitmap_id].width  = graphic_info[graphic].width;
532       font_bitmap_info[font_bitmap_id].height = graphic_info[graphic].height;
533
534       font_bitmap_info[font_bitmap_id].draw_xoffset =
535         graphic_info[graphic].draw_xoffset;
536       font_bitmap_info[font_bitmap_id].draw_yoffset =
537         graphic_info[graphic].draw_yoffset;
538
539       font_bitmap_info[font_bitmap_id].num_chars =
540         graphic_info[graphic].anim_frames;
541       font_bitmap_info[font_bitmap_id].num_chars_per_line =
542         graphic_info[graphic].anim_frames_per_line;
543     }
544   }
545
546   InitFontInfo(font_bitmap_info, num_font_bitmaps,
547                getFontBitmapID, getFontFromToken);
548 }
549
550 void InitGlobalAnimGraphicInfo()
551 {
552   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
553   int num_property_mappings = getImageListPropertyMappingSize();
554   int i, j, k;
555
556   if (graphic_info == NULL)             /* still at startup phase */
557     return;
558
559   /* always start with reliable default values (no global animations) */
560   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
561     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
562       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
563         global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
564
565   /* initialize global animation definitions from static configuration */
566   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
567   {
568     int j = GLOBAL_ANIM_ID_PART_BASE;
569     int k = GFX_SPECIAL_ARG_DEFAULT;
570
571     global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
572   }
573
574   /* initialize global animation definitions from dynamic configuration */
575   for (i = 0; i < num_property_mappings; i++)
576   {
577     int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
578     int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
579     int special = property_mapping[i].ext3_index;
580     int graphic = property_mapping[i].artwork_index;
581
582     if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
583       continue;
584
585     /* set animation part to base part, if not specified */
586     if (!IS_GLOBAL_ANIM_PART(part_nr))
587       part_nr = GLOBAL_ANIM_ID_PART_BASE;
588
589     /* set animation screen to default, if not specified */
590     if (!IS_SPECIAL_GFX_ARG(special))
591       special = GFX_SPECIAL_ARG_DEFAULT;
592
593     global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
594   }
595
596 #if 0
597   printf("::: InitGlobalAnimGraphicInfo\n");
598
599   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
600     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
601       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
602         if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
603             graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
604           printf("::: - anim %d, part %d, mode %d => %d\n",
605                  i, j, k, global_anim_info[i].graphic[j][k]);
606 #endif
607 }
608
609 void InitGlobalAnimSoundInfo()
610 {
611   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
612   int num_property_mappings = getSoundListPropertyMappingSize();
613   int i, j, k;
614
615   /* always start with reliable default values (no global animation sounds) */
616   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
617     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
618       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
619         global_anim_info[i].sound[j][k] = SND_UNDEFINED;
620
621   /* initialize global animation sound definitions from dynamic configuration */
622   for (i = 0; i < num_property_mappings; i++)
623   {
624     int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
625     int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
626     int special = property_mapping[i].ext3_index;
627     int sound   = property_mapping[i].artwork_index;
628
629     // sound uses control definition; map it to position of graphic (artwork)
630     anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
631
632     if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
633       continue;
634
635     /* set animation part to base part, if not specified */
636     if (!IS_GLOBAL_ANIM_PART(part_nr))
637       part_nr = GLOBAL_ANIM_ID_PART_BASE;
638
639     /* set animation screen to default, if not specified */
640     if (!IS_SPECIAL_GFX_ARG(special))
641       special = GFX_SPECIAL_ARG_DEFAULT;
642
643     global_anim_info[anim_nr].sound[part_nr][special] = sound;
644   }
645
646 #if 0
647   printf("::: InitGlobalAnimSoundInfo\n");
648
649   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
650     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
651       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
652         if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
653           printf("::: - anim %d, part %d, mode %d => %d\n",
654                  i, j, k, global_anim_info[i].sound[j][k]);
655 #endif
656 }
657
658 void InitGlobalAnimMusicInfo()
659 {
660   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
661   int num_property_mappings = getMusicListPropertyMappingSize();
662   int i, j, k;
663
664   /* always start with reliable default values (no global animation music) */
665   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
666     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
667       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
668         global_anim_info[i].music[j][k] = MUS_UNDEFINED;
669
670   /* initialize global animation music definitions from dynamic configuration */
671   for (i = 0; i < num_property_mappings; i++)
672   {
673     int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
674     int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
675     int special = property_mapping[i].ext2_index;
676     int music   = property_mapping[i].artwork_index;
677
678     // music uses control definition; map it to position of graphic (artwork)
679     anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
680
681     if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
682       continue;
683
684     /* set animation part to base part, if not specified */
685     if (!IS_GLOBAL_ANIM_PART(part_nr))
686       part_nr = GLOBAL_ANIM_ID_PART_BASE;
687
688     /* set animation screen to default, if not specified */
689     if (!IS_SPECIAL_GFX_ARG(special))
690       special = GFX_SPECIAL_ARG_DEFAULT;
691
692     global_anim_info[anim_nr].music[part_nr][special] = music;
693   }
694
695 #if 0
696   printf("::: InitGlobalAnimMusicInfo\n");
697
698   for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
699     for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
700       for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
701         if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
702           printf("::: - anim %d, part %d, mode %d => %d\n",
703                  i, j, k, global_anim_info[i].music[j][k]);
704 #endif
705 }
706
707 void InitElementGraphicInfo()
708 {
709   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
710   int num_property_mappings = getImageListPropertyMappingSize();
711   int i, act, dir;
712
713   if (graphic_info == NULL)             /* still at startup phase */
714     return;
715
716   /* set values to -1 to identify later as "uninitialized" values */
717   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
718   {
719     for (act = 0; act < NUM_ACTIONS; act++)
720     {
721       element_info[i].graphic[act] = -1;
722       element_info[i].crumbled[act] = -1;
723
724       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
725       {
726         element_info[i].direction_graphic[act][dir] = -1;
727         element_info[i].direction_crumbled[act][dir] = -1;
728       }
729     }
730   }
731
732   UPDATE_BUSY_STATE();
733
734   /* initialize normal element/graphic mapping from static configuration */
735   for (i = 0; element_to_graphic[i].element > -1; i++)
736   {
737     int element      = element_to_graphic[i].element;
738     int action       = element_to_graphic[i].action;
739     int direction    = element_to_graphic[i].direction;
740     boolean crumbled = element_to_graphic[i].crumbled;
741     int graphic      = element_to_graphic[i].graphic;
742     int base_graphic = el2baseimg(element);
743
744     if (graphic_info[graphic].bitmap == NULL)
745       continue;
746
747     if ((action > -1 || direction > -1 || crumbled == TRUE) &&
748         base_graphic != -1)
749     {
750       boolean base_redefined =
751         getImageListEntryFromImageID(base_graphic)->redefined;
752       boolean act_dir_redefined =
753         getImageListEntryFromImageID(graphic)->redefined;
754
755       /* if the base graphic ("emerald", for example) has been redefined,
756          but not the action graphic ("emerald.falling", for example), do not
757          use an existing (in this case considered obsolete) action graphic
758          anymore, but use the automatically determined default graphic */
759       if (base_redefined && !act_dir_redefined)
760         continue;
761     }
762
763     if (action < 0)
764       action = ACTION_DEFAULT;
765
766     if (crumbled)
767     {
768       if (direction > -1)
769         element_info[element].direction_crumbled[action][direction] = graphic;
770       else
771         element_info[element].crumbled[action] = graphic;
772     }
773     else
774     {
775       if (direction > -1)
776         element_info[element].direction_graphic[action][direction] = graphic;
777       else
778         element_info[element].graphic[action] = graphic;
779     }
780   }
781
782   /* initialize normal element/graphic mapping from dynamic configuration */
783   for (i = 0; i < num_property_mappings; i++)
784   {
785     int element   = property_mapping[i].base_index;
786     int action    = property_mapping[i].ext1_index;
787     int direction = property_mapping[i].ext2_index;
788     int special   = property_mapping[i].ext3_index;
789     int graphic   = property_mapping[i].artwork_index;
790     boolean crumbled = FALSE;
791
792     if (special == GFX_SPECIAL_ARG_CRUMBLED)
793     {
794       special = -1;
795       crumbled = TRUE;
796     }
797
798     if (graphic_info[graphic].bitmap == NULL)
799       continue;
800
801     if (element >= MAX_NUM_ELEMENTS || special != -1)
802       continue;
803
804     if (action < 0)
805       action = ACTION_DEFAULT;
806
807     if (crumbled)
808     {
809       if (direction < 0)
810         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
811           element_info[element].direction_crumbled[action][dir] = -1;
812
813       if (direction > -1)
814         element_info[element].direction_crumbled[action][direction] = graphic;
815       else
816         element_info[element].crumbled[action] = graphic;
817     }
818     else
819     {
820       if (direction < 0)
821         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
822           element_info[element].direction_graphic[action][dir] = -1;
823
824       if (direction > -1)
825         element_info[element].direction_graphic[action][direction] = graphic;
826       else
827         element_info[element].graphic[action] = graphic;
828     }
829   }
830
831   /* now copy all graphics that are defined to be cloned from other graphics */
832   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
833   {
834     int graphic = element_info[i].graphic[ACTION_DEFAULT];
835     int crumbled_like, diggable_like;
836
837     if (graphic == -1)
838       continue;
839
840     crumbled_like = graphic_info[graphic].crumbled_like;
841     diggable_like = graphic_info[graphic].diggable_like;
842
843     if (crumbled_like != -1 && element_info[i].crumbled[ACTION_DEFAULT] == -1)
844     {
845       for (act = 0; act < NUM_ACTIONS; act++)
846         element_info[i].crumbled[act] =
847           element_info[crumbled_like].crumbled[act];
848       for (act = 0; act < NUM_ACTIONS; act++)
849         for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
850           element_info[i].direction_crumbled[act][dir] =
851             element_info[crumbled_like].direction_crumbled[act][dir];
852     }
853
854     if (diggable_like != -1 && element_info[i].graphic[ACTION_DIGGING] == -1)
855     {
856       element_info[i].graphic[ACTION_DIGGING] =
857         element_info[diggable_like].graphic[ACTION_DIGGING];
858       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
859         element_info[i].direction_graphic[ACTION_DIGGING][dir] =
860           element_info[diggable_like].direction_graphic[ACTION_DIGGING][dir];
861     }
862   }
863
864   /* set hardcoded definitions for some runtime elements without graphic */
865   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
866
867   /* set hardcoded definitions for some internal elements without graphic */
868   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
869   {
870     if (IS_EDITOR_CASCADE_INACTIVE(i))
871       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST;
872     else if (IS_EDITOR_CASCADE_ACTIVE(i))
873       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
874   }
875
876   /* now set all undefined/invalid graphics to -1 to set to default after it */
877   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
878   {
879     for (act = 0; act < NUM_ACTIONS; act++)
880     {
881       int graphic;
882
883       graphic = element_info[i].graphic[act];
884       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
885         element_info[i].graphic[act] = -1;
886
887       graphic = element_info[i].crumbled[act];
888       if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
889         element_info[i].crumbled[act] = -1;
890
891       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
892       {
893         graphic = element_info[i].direction_graphic[act][dir];
894         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
895           element_info[i].direction_graphic[act][dir] = -1;
896
897         graphic = element_info[i].direction_crumbled[act][dir];
898         if (graphic > 0 && graphic_info[graphic].bitmap == NULL)
899           element_info[i].direction_crumbled[act][dir] = -1;
900       }
901     }
902   }
903
904   UPDATE_BUSY_STATE();
905
906   /* adjust graphics with 2nd tile for movement according to direction
907      (do this before correcting '-1' values to minimize calculations) */
908   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
909   {
910     for (act = 0; act < NUM_ACTIONS; act++)
911     {
912       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
913       {
914         int graphic = element_info[i].direction_graphic[act][dir];
915         int move_dir = (act == ACTION_FALLING ? MV_BIT_DOWN : dir);
916
917         if (act == ACTION_FALLING)      /* special case */
918           graphic = element_info[i].graphic[act];
919
920         if (graphic != -1 &&
921             graphic_info[graphic].double_movement &&
922             graphic_info[graphic].swap_double_tiles != 0)
923         {
924           struct GraphicInfo *g = &graphic_info[graphic];
925           int src_x_front = g->src_x;
926           int src_y_front = g->src_y;
927           int src_x_back = g->src_x + g->offset2_x;
928           int src_y_back = g->src_y + g->offset2_y;
929           boolean frames_are_ordered_diagonally = (g->offset_x != 0 &&
930                                                    g->offset_y != 0);
931           boolean front_is_left_or_upper = (src_x_front < src_x_back ||
932                                             src_y_front < src_y_back);
933           boolean swap_movement_tiles_always = (g->swap_double_tiles == 1);
934           boolean swap_movement_tiles_autodetected =
935             (!frames_are_ordered_diagonally &&
936              ((move_dir == MV_BIT_LEFT  && !front_is_left_or_upper) ||
937               (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
938               (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
939               (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
940
941           /* swap frontside and backside graphic tile coordinates, if needed */
942           if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
943           {
944             /* get current (wrong) backside tile coordinates */
945             getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
946
947             /* set frontside tile coordinates to backside tile coordinates */
948             g->src_x = src_x_back;
949             g->src_y = src_y_back;
950
951             /* invert tile offset to point to new backside tile coordinates */
952             g->offset2_x *= -1;
953             g->offset2_y *= -1;
954
955             /* do not swap front and backside tiles again after correction */
956             g->swap_double_tiles = 0;
957           }
958         }
959       }
960     }
961   }
962
963   UPDATE_BUSY_STATE();
964
965   /* now set all '-1' values to element specific default values */
966   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
967   {
968     int default_graphic = element_info[i].graphic[ACTION_DEFAULT];
969     int default_crumbled = element_info[i].crumbled[ACTION_DEFAULT];
970     int default_direction_graphic[NUM_DIRECTIONS_FULL];
971     int default_direction_crumbled[NUM_DIRECTIONS_FULL];
972
973     if (default_graphic == -1)
974       default_graphic = IMG_UNKNOWN;
975
976     if (default_crumbled == -1)
977       default_crumbled = default_graphic;
978
979     for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
980     {
981       default_direction_graphic[dir] =
982         element_info[i].direction_graphic[ACTION_DEFAULT][dir];
983       default_direction_crumbled[dir] =
984         element_info[i].direction_crumbled[ACTION_DEFAULT][dir];
985
986       if (default_direction_graphic[dir] == -1)
987         default_direction_graphic[dir] = default_graphic;
988
989       if (default_direction_crumbled[dir] == -1)
990         default_direction_crumbled[dir] = default_direction_graphic[dir];
991     }
992
993     for (act = 0; act < NUM_ACTIONS; act++)
994     {
995       boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
996                             (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
997                             (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
998       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
999                              act == ACTION_TURNING_FROM_RIGHT ||
1000                              act == ACTION_TURNING_FROM_UP ||
1001                              act == ACTION_TURNING_FROM_DOWN);
1002
1003       /* generic default action graphic (defined by "[default]" directive) */
1004       int default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1005       int default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1006       int default_remove_graphic = IMG_EMPTY;
1007
1008       if (act_remove && default_action_graphic != -1)
1009         default_remove_graphic = default_action_graphic;
1010
1011       /* look for special default action graphic (classic game specific) */
1012       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].graphic[act] != -1)
1013         default_action_graphic = element_info[EL_BD_DEFAULT].graphic[act];
1014       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].graphic[act] != -1)
1015         default_action_graphic = element_info[EL_SP_DEFAULT].graphic[act];
1016       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].graphic[act] != -1)
1017         default_action_graphic = element_info[EL_SB_DEFAULT].graphic[act];
1018
1019       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].crumbled[act] != -1)
1020         default_action_crumbled = element_info[EL_BD_DEFAULT].crumbled[act];
1021       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].crumbled[act] != -1)
1022         default_action_crumbled = element_info[EL_SP_DEFAULT].crumbled[act];
1023       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
1024         default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
1025
1026       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1027       /* !!! make this better !!! */
1028       if (i == EL_EMPTY_SPACE)
1029       {
1030         default_action_graphic = element_info[EL_DEFAULT].graphic[act];
1031         default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
1032       }
1033
1034       if (default_action_graphic == -1)
1035         default_action_graphic = default_graphic;
1036
1037       if (default_action_crumbled == -1)
1038         default_action_crumbled = default_action_graphic;
1039
1040       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
1041       {
1042         /* use action graphic as the default direction graphic, if undefined */
1043         int default_action_direction_graphic = element_info[i].graphic[act];
1044         int default_action_direction_crumbled = element_info[i].crumbled[act];
1045
1046         /* no graphic for current action -- use default direction graphic */
1047         if (default_action_direction_graphic == -1)
1048           default_action_direction_graphic =
1049             (act_remove ? default_remove_graphic :
1050              act_turning ?
1051              element_info[i].direction_graphic[ACTION_TURNING][dir] :
1052              default_action_graphic != default_graphic ?
1053              default_action_graphic :
1054              default_direction_graphic[dir]);
1055
1056         if (element_info[i].direction_graphic[act][dir] == -1)
1057           element_info[i].direction_graphic[act][dir] =
1058             default_action_direction_graphic;
1059
1060         if (default_action_direction_crumbled == -1)
1061           default_action_direction_crumbled =
1062             element_info[i].direction_graphic[act][dir];
1063
1064         if (element_info[i].direction_crumbled[act][dir] == -1)
1065           element_info[i].direction_crumbled[act][dir] =
1066             default_action_direction_crumbled;
1067       }
1068
1069       /* no graphic for this specific action -- use default action graphic */
1070       if (element_info[i].graphic[act] == -1)
1071         element_info[i].graphic[act] =
1072           (act_remove ? default_remove_graphic :
1073            act_turning ? element_info[i].graphic[ACTION_TURNING] :
1074            default_action_graphic);
1075
1076       if (element_info[i].crumbled[act] == -1)
1077         element_info[i].crumbled[act] = element_info[i].graphic[act];
1078     }
1079   }
1080
1081   UPDATE_BUSY_STATE();
1082 }
1083
1084 void InitElementSpecialGraphicInfo()
1085 {
1086   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
1087   int num_property_mappings = getImageListPropertyMappingSize();
1088   int i, j;
1089
1090   /* always start with reliable default values */
1091   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1092     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1093       element_info[i].special_graphic[j] =
1094         element_info[i].graphic[ACTION_DEFAULT];
1095
1096   /* initialize special element/graphic mapping from static configuration */
1097   for (i = 0; element_to_special_graphic[i].element > -1; i++)
1098   {
1099     int element = element_to_special_graphic[i].element;
1100     int special = element_to_special_graphic[i].special;
1101     int graphic = element_to_special_graphic[i].graphic;
1102     int base_graphic = el2baseimg(element);
1103     boolean base_redefined =
1104       getImageListEntryFromImageID(base_graphic)->redefined;
1105     boolean special_redefined =
1106       getImageListEntryFromImageID(graphic)->redefined;
1107
1108     /* if the base graphic ("emerald", for example) has been redefined,
1109        but not the special graphic ("emerald.EDITOR", for example), do not
1110        use an existing (in this case considered obsolete) special graphic
1111        anymore, but use the automatically created (down-scaled) graphic */
1112     if (base_redefined && !special_redefined)
1113       continue;
1114
1115     element_info[element].special_graphic[special] = graphic;
1116   }
1117
1118   /* initialize special element/graphic mapping from dynamic configuration */
1119   for (i = 0; i < num_property_mappings; i++)
1120   {
1121     int element   = property_mapping[i].base_index;
1122     int action    = property_mapping[i].ext1_index;
1123     int direction = property_mapping[i].ext2_index;
1124     int special   = property_mapping[i].ext3_index;
1125     int graphic   = property_mapping[i].artwork_index;
1126
1127     /* for action ".active", replace element with active element, if exists */
1128     if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
1129     {
1130       element = ELEMENT_ACTIVE(element);
1131       action = -1;
1132     }
1133
1134     if (element >= MAX_NUM_ELEMENTS)
1135       continue;
1136
1137     /* do not change special graphic if action or direction was specified */
1138     if (action != -1 || direction != -1)
1139       continue;
1140
1141     if (IS_SPECIAL_GFX_ARG(special))
1142       element_info[element].special_graphic[special] = graphic;
1143   }
1144
1145   /* now set all undefined/invalid graphics to default */
1146   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1147     for (j = 0; j < NUM_SPECIAL_GFX_ARGS; j++)
1148       if (graphic_info[element_info[i].special_graphic[j]].bitmap == NULL)
1149         element_info[i].special_graphic[j] =
1150           element_info[i].graphic[ACTION_DEFAULT];
1151 }
1152
1153 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
1154 {
1155   if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
1156     return get_parameter_value(value_raw, suffix, type);
1157
1158   if (strEqual(value_raw, ARG_UNDEFINED))
1159     return ARG_UNDEFINED_VALUE;
1160
1161   if (type == TYPE_ELEMENT)
1162   {
1163     char *value = getHashEntry(element_token_hash, value_raw);
1164
1165     if (value == NULL)
1166     {
1167       Error(ERR_INFO_LINE, "-");
1168       Error(ERR_INFO, "warning: error found in config file:");
1169       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1170       Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
1171       Error(ERR_INFO, "custom graphic rejected for this element/action");
1172       Error(ERR_INFO, "fallback done to undefined element for this graphic");
1173       Error(ERR_INFO_LINE, "-");
1174     }
1175
1176     return (value != NULL ? atoi(value) : EL_UNDEFINED);
1177   }
1178   else if (type == TYPE_GRAPHIC)
1179   {
1180     char *value = getHashEntry(graphic_token_hash, value_raw);
1181     int fallback_graphic = IMG_CHAR_EXCLAM;
1182
1183     if (value == NULL)
1184     {
1185       Error(ERR_INFO_LINE, "-");
1186       Error(ERR_INFO, "warning: error found in config file:");
1187       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1188       Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
1189       Error(ERR_INFO, "custom graphic rejected for this element/action");
1190       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1191       Error(ERR_INFO_LINE, "-");
1192     }
1193
1194     return (value != NULL ? atoi(value) : fallback_graphic);
1195   }
1196
1197   return -1;
1198 }
1199
1200 static int get_scaled_graphic_width(int graphic)
1201 {
1202   int original_width = getOriginalImageWidthFromImageID(graphic);
1203   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1204
1205   return original_width * scale_up_factor;
1206 }
1207
1208 static int get_scaled_graphic_height(int graphic)
1209 {
1210   int original_height = getOriginalImageHeightFromImageID(graphic);
1211   int scale_up_factor = graphic_info[graphic].scale_up_factor;
1212
1213   return original_height * scale_up_factor;
1214 }
1215
1216 static void set_graphic_parameters_ext(int graphic, int *parameter,
1217                                        Bitmap **src_bitmaps)
1218 {
1219   struct GraphicInfo *g = &graphic_info[graphic];
1220   Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
1221   int anim_frames_per_row = 1, anim_frames_per_col = 1;
1222   int anim_frames_per_line = 1;
1223
1224   /* always start with reliable default values */
1225   g->src_image_width = 0;
1226   g->src_image_height = 0;
1227   g->src_x = 0;
1228   g->src_y = 0;
1229   g->width  = TILEX;                    /* default for element graphics */
1230   g->height = TILEY;                    /* default for element graphics */
1231   g->offset_x = 0;                      /* one or both of these values ... */
1232   g->offset_y = 0;                      /* ... will be corrected later */
1233   g->offset2_x = 0;                     /* one or both of these values ... */
1234   g->offset2_y = 0;                     /* ... will be corrected later */
1235   g->swap_double_tiles = -1;            /* auto-detect tile swapping */
1236   g->crumbled_like = -1;                /* do not use clone element */
1237   g->diggable_like = -1;                /* do not use clone element */
1238   g->border_size = TILEX / 8;           /* "CRUMBLED" border size */
1239   g->scale_up_factor = 1;               /* default: no scaling up */
1240   g->tile_size = TILESIZE;              /* default: standard tile size */
1241   g->clone_from = -1;                   /* do not use clone graphic */
1242   g->init_delay_fixed = 0;
1243   g->init_delay_random = 0;
1244   g->anim_delay_fixed = 0;
1245   g->anim_delay_random = 0;
1246   g->post_delay_fixed = 0;
1247   g->post_delay_random = 0;
1248   g->draw_order = 0;
1249   g->fade_mode = FADE_MODE_DEFAULT;
1250   g->fade_delay = -1;
1251   g->post_delay = -1;
1252   g->auto_delay = -1;
1253   g->align = ALIGN_CENTER;              /* default for title screens */
1254   g->valign = VALIGN_MIDDLE;            /* default for title screens */
1255   g->sort_priority = 0;                 /* default for title screens */
1256   g->class = 0;
1257   g->style = STYLE_DEFAULT;
1258
1259   g->bitmaps = src_bitmaps;
1260   g->bitmap = src_bitmap;
1261
1262   /* optional zoom factor for scaling up the image to a larger size */
1263   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
1264     g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
1265   if (g->scale_up_factor < 1)
1266     g->scale_up_factor = 1;             /* no scaling */
1267
1268   /* optional tile size for using non-standard image size */
1269   if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1270   {
1271     g->tile_size = parameter[GFX_ARG_TILE_SIZE];
1272
1273 #if 0
1274     // CHECK: should tile sizes less than standard tile size be allowed?
1275     if (g->tile_size < TILESIZE)
1276       g->tile_size = TILESIZE;          /* standard tile size */
1277 #endif
1278
1279     // when setting tile size, also set width and height accordingly
1280     g->width  = g->tile_size;
1281     g->height = g->tile_size;
1282   }
1283
1284   if (g->use_image_size)
1285   {
1286     /* set new default bitmap size (with scaling, but without small images) */
1287     g->width  = get_scaled_graphic_width(graphic);
1288     g->height = get_scaled_graphic_height(graphic);
1289   }
1290
1291   /* optional width and height of each animation frame */
1292   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
1293     g->width = parameter[GFX_ARG_WIDTH];
1294   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
1295     g->height = parameter[GFX_ARG_HEIGHT];
1296
1297   /* optional x and y tile position of animation frame sequence */
1298   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
1299     g->src_x = parameter[GFX_ARG_XPOS] * g->width;
1300   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
1301     g->src_y = parameter[GFX_ARG_YPOS] * g->height;
1302
1303   /* optional x and y pixel position of animation frame sequence */
1304   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
1305     g->src_x = parameter[GFX_ARG_X];
1306   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
1307     g->src_y = parameter[GFX_ARG_Y];
1308
1309   if (src_bitmap)
1310   {
1311     if (g->width <= 0)
1312     {
1313       Error(ERR_INFO_LINE, "-");
1314       Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
1315             g->width, getTokenFromImageID(graphic), TILEX);
1316       Error(ERR_INFO_LINE, "-");
1317
1318       g->width = TILEX;         /* will be checked to be inside bitmap later */
1319     }
1320
1321     if (g->height <= 0)
1322     {
1323       Error(ERR_INFO_LINE, "-");
1324       Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
1325             g->height, getTokenFromImageID(graphic), TILEY);
1326       Error(ERR_INFO_LINE, "-");
1327
1328       g->height = TILEY;        /* will be checked to be inside bitmap later */
1329     }
1330   }
1331
1332   if (src_bitmap)
1333   {
1334     /* get final bitmap size (with scaling, but without small images) */
1335     int src_image_width  = get_scaled_graphic_width(graphic);
1336     int src_image_height = get_scaled_graphic_height(graphic);
1337
1338     if (src_image_width == 0 || src_image_height == 0)
1339     {
1340       /* only happens when loaded outside artwork system (like "global.busy") */
1341       src_image_width  = src_bitmap->width;
1342       src_image_height = src_bitmap->height;
1343     }
1344
1345     if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
1346     {
1347       anim_frames_per_row = src_image_width  / g->tile_size;
1348       anim_frames_per_col = src_image_height / g->tile_size;
1349     }
1350     else
1351     {
1352       anim_frames_per_row = src_image_width  / g->width;
1353       anim_frames_per_col = src_image_height / g->height;
1354     }
1355
1356     g->src_image_width  = src_image_width;
1357     g->src_image_height = src_image_height;
1358   }
1359
1360   /* correct x or y offset dependent of vertical or horizontal frame order */
1361   if (parameter[GFX_ARG_VERTICAL])      /* frames are ordered vertically */
1362   {
1363     g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1364                    parameter[GFX_ARG_OFFSET] : g->height);
1365     anim_frames_per_line = anim_frames_per_col;
1366   }
1367   else                                  /* frames are ordered horizontally */
1368   {
1369     g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
1370                    parameter[GFX_ARG_OFFSET] : g->width);
1371     anim_frames_per_line = anim_frames_per_row;
1372   }
1373
1374   /* optionally, the x and y offset of frames can be specified directly */
1375   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
1376     g->offset_x = parameter[GFX_ARG_XOFFSET];
1377   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
1378     g->offset_y = parameter[GFX_ARG_YOFFSET];
1379
1380   /* optionally, moving animations may have separate start and end graphics */
1381   g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
1382
1383   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
1384     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
1385
1386   /* correct x or y offset2 dependent of vertical or horizontal frame order */
1387   if (parameter[GFX_ARG_2ND_VERTICAL])  /* frames are ordered vertically */
1388     g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1389                     parameter[GFX_ARG_2ND_OFFSET] : g->height);
1390   else                                  /* frames are ordered horizontally */
1391     g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
1392                     parameter[GFX_ARG_2ND_OFFSET] : g->width);
1393
1394   /* optionally, the x and y offset of 2nd graphic can be specified directly */
1395   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
1396     g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
1397   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
1398     g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
1399
1400   /* optionally, the second movement tile can be specified as start tile */
1401   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
1402     g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
1403
1404   /* automatically determine correct number of frames, if not defined */
1405   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
1406     g->anim_frames = parameter[GFX_ARG_FRAMES];
1407   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
1408     g->anim_frames = anim_frames_per_row;
1409   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
1410     g->anim_frames = anim_frames_per_col;
1411   else
1412     g->anim_frames = 1;
1413
1414   if (g->anim_frames == 0)              /* frames must be at least 1 */
1415     g->anim_frames = 1;
1416
1417   g->anim_frames_per_line =
1418     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
1419      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
1420
1421   g->anim_delay = parameter[GFX_ARG_DELAY];
1422   if (g->anim_delay == 0)               /* delay must be at least 1 */
1423     g->anim_delay = 1;
1424
1425   g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
1426
1427   /* automatically determine correct start frame, if not defined */
1428   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
1429     g->anim_start_frame = 0;
1430   else if (g->anim_mode & ANIM_REVERSE)
1431     g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
1432   else
1433     g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
1434
1435   /* animation synchronized with global frame counter, not move position */
1436   g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
1437
1438   /* optional element for cloning crumble graphics */
1439   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
1440     g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
1441
1442   /* optional element for cloning digging graphics */
1443   if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
1444     g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
1445
1446   /* optional border size for "crumbling" diggable graphics */
1447   if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
1448     g->border_size = parameter[GFX_ARG_BORDER_SIZE];
1449
1450   /* used for global animations and player "boring" and "sleeping" actions */
1451   if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1452     g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
1453   if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1454     g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
1455   if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1456     g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
1457   if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1458     g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
1459   if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
1460     g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
1461   if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
1462     g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
1463
1464   /* used for toon animations and global animations */
1465   g->step_offset  = parameter[GFX_ARG_STEP_OFFSET];
1466   g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
1467   g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
1468   g->step_delay   = parameter[GFX_ARG_STEP_DELAY];
1469   g->direction    = parameter[GFX_ARG_DIRECTION];
1470   g->position     = parameter[GFX_ARG_POSITION];
1471   g->x            = parameter[GFX_ARG_X];       // (may be uninitialized,
1472   g->y            = parameter[GFX_ARG_Y];       // unlike src_x and src_y)
1473
1474   /* this is only used for drawing font characters */
1475   g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
1476   g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
1477
1478   /* this is only used for drawing envelope graphics */
1479   g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
1480
1481   /* used for toon animations and global animations */
1482   if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
1483     g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
1484
1485   /* optional graphic for cloning all graphics settings */
1486   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
1487     g->clone_from = parameter[GFX_ARG_CLONE_FROM];
1488
1489   /* optional settings for drawing title screens and title messages */
1490   if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
1491     g->fade_mode = parameter[GFX_ARG_FADE_MODE];
1492   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
1493     g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
1494   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
1495     g->post_delay = parameter[GFX_ARG_POST_DELAY];
1496   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
1497     g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
1498   if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
1499     g->align = parameter[GFX_ARG_ALIGN];
1500   if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
1501     g->valign = parameter[GFX_ARG_VALIGN];
1502   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
1503     g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
1504
1505   if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
1506     g->class = parameter[GFX_ARG_CLASS];
1507   if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
1508     g->style = parameter[GFX_ARG_STYLE];
1509
1510   /* this is only used for drawing menu buttons and text */
1511   g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
1512   g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
1513   g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
1514   g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
1515 }
1516
1517 static void set_graphic_parameters(int graphic)
1518 {
1519   struct FileInfo *image = getImageListEntryFromImageID(graphic);
1520   char **parameter_raw = image->parameter;
1521   Bitmap **src_bitmaps = getBitmapsFromImageID(graphic);
1522   int parameter[NUM_GFX_ARGS];
1523   int i;
1524
1525   /* if fallback to default artwork is done, also use the default parameters */
1526   if (image->fallback_to_default)
1527     parameter_raw = image->default_parameter;
1528
1529   /* get integer values from string parameters */
1530   for (i = 0; i < NUM_GFX_ARGS; i++)
1531     parameter[i] = get_graphic_parameter_value(parameter_raw[i],
1532                                                image_config_suffix[i].token,
1533                                                image_config_suffix[i].type);
1534
1535   set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
1536
1537   UPDATE_BUSY_STATE();
1538 }
1539
1540 static void set_cloned_graphic_parameters(int graphic)
1541 {
1542   int fallback_graphic = IMG_CHAR_EXCLAM;
1543   int max_num_images = getImageListSize();
1544   int clone_graphic = graphic_info[graphic].clone_from;
1545   int num_references_followed = 1;
1546
1547   while (graphic_info[clone_graphic].clone_from != -1 &&
1548          num_references_followed < max_num_images)
1549   {
1550     clone_graphic = graphic_info[clone_graphic].clone_from;
1551
1552     num_references_followed++;
1553   }
1554
1555   if (num_references_followed >= max_num_images)
1556   {
1557     Error(ERR_INFO_LINE, "-");
1558     Error(ERR_INFO, "warning: error found in config file:");
1559     Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1560     Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
1561     Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
1562     Error(ERR_INFO, "custom graphic rejected for this element/action");
1563
1564     if (graphic == fallback_graphic)
1565       Error(ERR_EXIT, "no fallback graphic available");
1566
1567     Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1568     Error(ERR_INFO_LINE, "-");
1569
1570     graphic_info[graphic] = graphic_info[fallback_graphic];
1571   }
1572   else
1573   {
1574     graphic_info[graphic] = graphic_info[clone_graphic];
1575     graphic_info[graphic].clone_from = clone_graphic;
1576   }
1577 }
1578
1579 static void InitGraphicInfo()
1580 {
1581   int fallback_graphic = IMG_CHAR_EXCLAM;
1582   int num_images = getImageListSize();
1583   int i;
1584
1585   /* use image size as default values for width and height for these images */
1586   static int full_size_graphics[] =
1587   {
1588     IMG_GLOBAL_BORDER,
1589     IMG_GLOBAL_BORDER_MAIN,
1590     IMG_GLOBAL_BORDER_SCORES,
1591     IMG_GLOBAL_BORDER_EDITOR,
1592     IMG_GLOBAL_BORDER_PLAYING,
1593     IMG_GLOBAL_DOOR,
1594
1595     IMG_BACKGROUND_ENVELOPE_1,
1596     IMG_BACKGROUND_ENVELOPE_2,
1597     IMG_BACKGROUND_ENVELOPE_3,
1598     IMG_BACKGROUND_ENVELOPE_4,
1599     IMG_BACKGROUND_REQUEST,
1600
1601     IMG_BACKGROUND,
1602     IMG_BACKGROUND_TITLE_INITIAL,
1603     IMG_BACKGROUND_TITLE,
1604     IMG_BACKGROUND_MAIN,
1605     IMG_BACKGROUND_LEVELS,
1606     IMG_BACKGROUND_LEVELNR,
1607     IMG_BACKGROUND_SCORES,
1608     IMG_BACKGROUND_EDITOR,
1609     IMG_BACKGROUND_INFO,
1610     IMG_BACKGROUND_INFO_ELEMENTS,
1611     IMG_BACKGROUND_INFO_MUSIC,
1612     IMG_BACKGROUND_INFO_CREDITS,
1613     IMG_BACKGROUND_INFO_PROGRAM,
1614     IMG_BACKGROUND_INFO_VERSION,
1615     IMG_BACKGROUND_INFO_LEVELSET,
1616     IMG_BACKGROUND_SETUP,
1617     IMG_BACKGROUND_PLAYING,
1618     IMG_BACKGROUND_DOOR,
1619     IMG_BACKGROUND_TAPE,
1620     IMG_BACKGROUND_PANEL,
1621     IMG_BACKGROUND_PALETTE,
1622     IMG_BACKGROUND_TOOLBOX,
1623
1624     IMG_TITLESCREEN_INITIAL_1,
1625     IMG_TITLESCREEN_INITIAL_2,
1626     IMG_TITLESCREEN_INITIAL_3,
1627     IMG_TITLESCREEN_INITIAL_4,
1628     IMG_TITLESCREEN_INITIAL_5,
1629     IMG_TITLESCREEN_1,
1630     IMG_TITLESCREEN_2,
1631     IMG_TITLESCREEN_3,
1632     IMG_TITLESCREEN_4,
1633     IMG_TITLESCREEN_5,
1634
1635     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
1636     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
1637     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
1638     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
1639     IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
1640     IMG_BACKGROUND_TITLEMESSAGE_1,
1641     IMG_BACKGROUND_TITLEMESSAGE_2,
1642     IMG_BACKGROUND_TITLEMESSAGE_3,
1643     IMG_BACKGROUND_TITLEMESSAGE_4,
1644     IMG_BACKGROUND_TITLEMESSAGE_5,
1645
1646     -1
1647   };
1648
1649   checked_free(graphic_info);
1650
1651   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
1652
1653   /* initialize "use_image_size" flag with default value */
1654   for (i = 0; i < num_images; i++)
1655     graphic_info[i].use_image_size = FALSE;
1656
1657   /* initialize "use_image_size" flag from static configuration above */
1658   for (i = 0; full_size_graphics[i] != -1; i++)
1659     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
1660
1661   /* first set all graphic paramaters ... */
1662   for (i = 0; i < num_images; i++)
1663     set_graphic_parameters(i);
1664
1665   /* ... then copy these parameters for cloned graphics */
1666   for (i = 0; i < num_images; i++)
1667     if (graphic_info[i].clone_from != -1)
1668       set_cloned_graphic_parameters(i);
1669
1670   for (i = 0; i < num_images; i++)
1671   {
1672     Bitmap *src_bitmap;
1673     int src_x, src_y;
1674     int width, height;
1675     int first_frame, last_frame;
1676     int src_bitmap_width, src_bitmap_height;
1677
1678     /* now check if no animation frames are outside of the loaded image */
1679
1680     if (graphic_info[i].bitmap == NULL)
1681       continue;         /* skip check for optional images that are undefined */
1682
1683     /* get image size (this can differ from the standard element tile size!) */
1684     width  = graphic_info[i].width;
1685     height = graphic_info[i].height;
1686
1687     /* get final bitmap size (with scaling, but without small images) */
1688     src_bitmap_width  = graphic_info[i].src_image_width;
1689     src_bitmap_height = graphic_info[i].src_image_height;
1690
1691     /* check if first animation frame is inside specified bitmap */
1692
1693     first_frame = 0;
1694     getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
1695
1696     /* this avoids calculating wrong start position for out-of-bounds frame */
1697     src_x = graphic_info[i].src_x;
1698     src_y = graphic_info[i].src_y;
1699
1700     if (src_x < 0 || src_y < 0 ||
1701         src_x + width  > src_bitmap_width ||
1702         src_y + height > src_bitmap_height)
1703     {
1704       Error(ERR_INFO_LINE, "-");
1705       Error(ERR_INFO, "warning: error found in config file:");
1706       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1707       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1708       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1709       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1710       Error(ERR_INFO,
1711             "error: first animation frame out of bounds (%d, %d) [%d, %d]",
1712             src_x, src_y, src_bitmap_width, src_bitmap_height);
1713       Error(ERR_INFO, "custom graphic rejected for this element/action");
1714
1715       if (i == fallback_graphic)
1716         Error(ERR_EXIT, "no fallback graphic available");
1717
1718       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1719       Error(ERR_INFO_LINE, "-");
1720
1721       graphic_info[i] = graphic_info[fallback_graphic];
1722     }
1723
1724     /* check if last animation frame is inside specified bitmap */
1725
1726     last_frame = graphic_info[i].anim_frames - 1;
1727     getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
1728
1729     if (src_x < 0 || src_y < 0 ||
1730         src_x + width  > src_bitmap_width ||
1731         src_y + height > src_bitmap_height)
1732     {
1733       Error(ERR_INFO_LINE, "-");
1734       Error(ERR_INFO, "warning: error found in config file:");
1735       Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
1736       Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
1737       Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
1738       Error(ERR_INFO, "- frame size: %d, %d", width, height);
1739       Error(ERR_INFO,
1740             "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
1741             last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
1742       Error(ERR_INFO, "custom graphic rejected for this element/action");
1743
1744       if (i == fallback_graphic)
1745         Error(ERR_EXIT, "no fallback graphic available");
1746
1747       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
1748       Error(ERR_INFO_LINE, "-");
1749
1750       graphic_info[i] = graphic_info[fallback_graphic];
1751     }
1752   }
1753 }
1754
1755 static void InitGraphicCompatibilityInfo()
1756 {
1757   struct FileInfo *fi_global_door =
1758     getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
1759   int num_images = getImageListSize();
1760   int i;
1761
1762   /* the following compatibility handling is needed for the following case:
1763      versions up to 3.3.0.0 used one large bitmap "global.door" for various
1764      graphics mainly used for door and panel graphics, like editor, tape and
1765      in-game buttons with hard-coded bitmap positions and button sizes; as
1766      these graphics now have individual definitions, redefining "global.door"
1767      to change all these graphics at once like before does not work anymore
1768      (because all those individual definitions still have their default values);
1769      to solve this, remap all those individual definitions that are not
1770      redefined to the new bitmap of "global.door" if it was redefined */
1771
1772   /* special compatibility handling if image "global.door" was redefined */
1773   if (fi_global_door->redefined)
1774   {
1775     for (i = 0; i < num_images; i++)
1776     {
1777       struct FileInfo *fi = getImageListEntryFromImageID(i);
1778
1779       /* process only those images that still use the default settings */
1780       if (!fi->redefined)
1781       {
1782         /* process all images which default to same image as "global.door" */
1783         if (strEqual(fi->default_filename, fi_global_door->default_filename))
1784         {
1785           // printf("::: special treatment needed for token '%s'\n", fi->token);
1786
1787           graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
1788           graphic_info[i].bitmap  = graphic_info[IMG_GLOBAL_DOOR].bitmap;
1789         }
1790       }
1791     }
1792   }
1793
1794   InitGraphicCompatibilityInfo_Doors();
1795 }
1796
1797 static void InitElementSoundInfo()
1798 {
1799   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
1800   int num_property_mappings = getSoundListPropertyMappingSize();
1801   int i, j, act;
1802
1803   /* set values to -1 to identify later as "uninitialized" values */
1804   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1805     for (act = 0; act < NUM_ACTIONS; act++)
1806       element_info[i].sound[act] = -1;
1807
1808   /* initialize element/sound mapping from static configuration */
1809   for (i = 0; element_to_sound[i].element > -1; i++)
1810   {
1811     int element      = element_to_sound[i].element;
1812     int action       = element_to_sound[i].action;
1813     int sound        = element_to_sound[i].sound;
1814     boolean is_class = element_to_sound[i].is_class;
1815
1816     if (action < 0)
1817       action = ACTION_DEFAULT;
1818
1819     if (!is_class)
1820       element_info[element].sound[action] = sound;
1821     else
1822       for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1823         if (strEqual(element_info[j].class_name,
1824                      element_info[element].class_name))
1825           element_info[j].sound[action] = sound;
1826   }
1827
1828   /* initialize element class/sound mapping from dynamic configuration */
1829   for (i = 0; i < num_property_mappings; i++)
1830   {
1831     int element_class = property_mapping[i].base_index - MAX_NUM_ELEMENTS;
1832     int action        = property_mapping[i].ext1_index;
1833     int sound         = property_mapping[i].artwork_index;
1834
1835     if (element_class < 0 || element_class >= MAX_NUM_ELEMENTS)
1836       continue;
1837
1838     if (action < 0)
1839       action = ACTION_DEFAULT;
1840
1841     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1842       if (strEqual(element_info[j].class_name,
1843                    element_info[element_class].class_name))
1844         element_info[j].sound[action] = sound;
1845   }
1846
1847   /* initialize element/sound mapping from dynamic configuration */
1848   for (i = 0; i < num_property_mappings; i++)
1849   {
1850     int element = property_mapping[i].base_index;
1851     int action  = property_mapping[i].ext1_index;
1852     int sound   = property_mapping[i].artwork_index;
1853
1854     if (element >= MAX_NUM_ELEMENTS)
1855       continue;
1856
1857     if (action < 0)
1858       action = ACTION_DEFAULT;
1859
1860     element_info[element].sound[action] = sound;
1861   }
1862
1863   /* now set all '-1' values to element specific default values */
1864   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1865   {
1866     for (act = 0; act < NUM_ACTIONS; act++)
1867     {
1868       /* generic default action sound (defined by "[default]" directive) */
1869       int default_action_sound = element_info[EL_DEFAULT].sound[act];
1870
1871       /* look for special default action sound (classic game specific) */
1872       if (IS_BD_ELEMENT(i) && element_info[EL_BD_DEFAULT].sound[act] != -1)
1873         default_action_sound = element_info[EL_BD_DEFAULT].sound[act];
1874       if (IS_SP_ELEMENT(i) && element_info[EL_SP_DEFAULT].sound[act] != -1)
1875         default_action_sound = element_info[EL_SP_DEFAULT].sound[act];
1876       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
1877         default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
1878
1879       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
1880       /* !!! make this better !!! */
1881       if (i == EL_EMPTY_SPACE)
1882         default_action_sound = element_info[EL_DEFAULT].sound[act];
1883
1884       /* no sound for this specific action -- use default action sound */
1885       if (element_info[i].sound[act] == -1)
1886         element_info[i].sound[act] = default_action_sound;
1887     }
1888   }
1889
1890   /* copy sound settings to some elements that are only stored in level file
1891      in native R'n'D levels, but are used by game engine in native EM levels */
1892   for (i = 0; copy_properties[i][0] != -1; i++)
1893     for (j = 1; j <= 4; j++)
1894       for (act = 0; act < NUM_ACTIONS; act++)
1895         element_info[copy_properties[i][j]].sound[act] =
1896           element_info[copy_properties[i][0]].sound[act];
1897 }
1898
1899 static void InitGameModeSoundInfo()
1900 {
1901   int i;
1902
1903   /* set values to -1 to identify later as "uninitialized" values */
1904   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1905     menu.sound[i] = -1;
1906
1907   /* initialize gamemode/sound mapping from static configuration */
1908   for (i = 0; gamemode_to_sound[i].sound > -1; i++)
1909   {
1910     int gamemode = gamemode_to_sound[i].gamemode;
1911     int sound    = gamemode_to_sound[i].sound;
1912
1913     if (gamemode < 0)
1914       gamemode = GAME_MODE_DEFAULT;
1915
1916     menu.sound[gamemode] = sound;
1917   }
1918
1919   /* now set all '-1' values to levelset specific default values */
1920   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
1921     if (menu.sound[i] == -1)
1922       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
1923 }
1924
1925 static void set_sound_parameters(int sound, char **parameter_raw)
1926 {
1927   int parameter[NUM_SND_ARGS];
1928   int i;
1929
1930   /* get integer values from string parameters */
1931   for (i = 0; i < NUM_SND_ARGS; i++)
1932     parameter[i] =
1933       get_parameter_value(parameter_raw[i],
1934                           sound_config_suffix[i].token,
1935                           sound_config_suffix[i].type);
1936
1937   /* explicit loop mode setting in configuration overrides default value */
1938   if (parameter[SND_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
1939     sound_info[sound].loop = parameter[SND_ARG_MODE_LOOP];
1940
1941   /* sound volume to change the original volume when loading the sound file */
1942   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
1943
1944   /* sound priority to give certain sounds a higher or lower priority */
1945   sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
1946 }
1947
1948 static void InitSoundInfo()
1949 {
1950   int *sound_effect_properties;
1951   int num_sounds = getSoundListSize();
1952   int i, j;
1953
1954   checked_free(sound_info);
1955
1956   sound_effect_properties = checked_calloc(num_sounds * sizeof(int));
1957   sound_info = checked_calloc(num_sounds * sizeof(struct SoundInfo));
1958
1959   /* initialize sound effect for all elements to "no sound" */
1960   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1961     for (j = 0; j < NUM_ACTIONS; j++)
1962       element_info[i].sound[j] = SND_UNDEFINED;
1963
1964   for (i = 0; i < num_sounds; i++)
1965   {
1966     struct FileInfo *sound = getSoundListEntry(i);
1967     int len_effect_text = strlen(sound->token);
1968
1969     sound_effect_properties[i] = ACTION_OTHER;
1970     sound_info[i].loop = FALSE;         /* default: play sound only once */
1971
1972     /* determine all loop sounds and identify certain sound classes */
1973
1974     for (j = 0; element_action_info[j].suffix; j++)
1975     {
1976       int len_action_text = strlen(element_action_info[j].suffix);
1977
1978       if (len_action_text < len_effect_text &&
1979           strEqual(&sound->token[len_effect_text - len_action_text],
1980                    element_action_info[j].suffix))
1981       {
1982         sound_effect_properties[i] = element_action_info[j].value;
1983         sound_info[i].loop = element_action_info[j].is_loop_sound;
1984
1985         break;
1986       }
1987     }
1988
1989     /* associate elements and some selected sound actions */
1990
1991     for (j = 0; j < MAX_NUM_ELEMENTS; j++)
1992     {
1993       if (element_info[j].class_name)
1994       {
1995         int len_class_text = strlen(element_info[j].class_name);
1996
1997         if (len_class_text + 1 < len_effect_text &&
1998             strncmp(sound->token,
1999                     element_info[j].class_name, len_class_text) == 0 &&
2000             sound->token[len_class_text] == '.')
2001         {
2002           int sound_action_value = sound_effect_properties[i];
2003
2004           element_info[j].sound[sound_action_value] = i;
2005         }
2006       }
2007     }
2008
2009     set_sound_parameters(i, sound->parameter);
2010   }
2011
2012   free(sound_effect_properties);
2013 }
2014
2015 static void InitGameModeMusicInfo()
2016 {
2017   struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
2018   int num_property_mappings = getMusicListPropertyMappingSize();
2019   int default_levelset_music = -1;
2020   int i;
2021
2022   /* set values to -1 to identify later as "uninitialized" values */
2023   for (i = 0; i < MAX_LEVELS; i++)
2024     levelset.music[i] = -1;
2025   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2026     menu.music[i] = -1;
2027
2028   /* initialize gamemode/music mapping from static configuration */
2029   for (i = 0; gamemode_to_music[i].music > -1; i++)
2030   {
2031     int gamemode = gamemode_to_music[i].gamemode;
2032     int music    = gamemode_to_music[i].music;
2033
2034     if (gamemode < 0)
2035       gamemode = GAME_MODE_DEFAULT;
2036
2037     menu.music[gamemode] = music;
2038   }
2039
2040   /* initialize gamemode/music mapping from dynamic configuration */
2041   for (i = 0; i < num_property_mappings; i++)
2042   {
2043     int prefix   = property_mapping[i].base_index;
2044     int gamemode = property_mapping[i].ext2_index;
2045     int level    = property_mapping[i].ext3_index;
2046     int music    = property_mapping[i].artwork_index;
2047
2048     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
2049       continue;
2050
2051     if (gamemode < 0)
2052       gamemode = GAME_MODE_DEFAULT;
2053
2054     /* level specific music only allowed for in-game music */
2055     if (level != -1 && gamemode == GAME_MODE_DEFAULT)
2056       gamemode = GAME_MODE_PLAYING;
2057
2058     if (level == -1)
2059     {
2060       level = 0;
2061       default_levelset_music = music;
2062     }
2063
2064     if (gamemode == GAME_MODE_PLAYING || gamemode == GAME_MODE_DEFAULT)
2065       levelset.music[level] = music;
2066     if (gamemode != GAME_MODE_PLAYING)
2067       menu.music[gamemode] = music;
2068   }
2069
2070   /* now set all '-1' values to menu specific default values */
2071   /* (undefined values of "levelset.music[]" might stay at "-1" to
2072      allow dynamic selection of music files from music directory!) */
2073   for (i = 0; i < MAX_LEVELS; i++)
2074     if (levelset.music[i] == -1)
2075       levelset.music[i] = default_levelset_music;
2076   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
2077     if (menu.music[i] == -1)
2078       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
2079 }
2080
2081 static void set_music_parameters(int music, char **parameter_raw)
2082 {
2083   int parameter[NUM_MUS_ARGS];
2084   int i;
2085
2086   /* get integer values from string parameters */
2087   for (i = 0; i < NUM_MUS_ARGS; i++)
2088     parameter[i] =
2089       get_parameter_value(parameter_raw[i],
2090                           music_config_suffix[i].token,
2091                           music_config_suffix[i].type);
2092
2093   /* explicit loop mode setting in configuration overrides default value */
2094   if (parameter[MUS_ARG_MODE_LOOP] != ARG_UNDEFINED_VALUE)
2095     music_info[music].loop = parameter[MUS_ARG_MODE_LOOP];
2096 }
2097
2098 static void InitMusicInfo()
2099 {
2100   int num_music = getMusicListSize();
2101   int i, j;
2102
2103   checked_free(music_info);
2104
2105   music_info = checked_calloc(num_music * sizeof(struct MusicInfo));
2106
2107   for (i = 0; i < num_music; i++)
2108   {
2109     struct FileInfo *music = getMusicListEntry(i);
2110     int len_music_text = strlen(music->token);
2111
2112     music_info[i].loop = TRUE;          /* default: play music in loop mode */
2113
2114     /* determine all loop music */
2115
2116     for (j = 0; music_prefix_info[j].prefix; j++)
2117     {
2118       int len_prefix_text = strlen(music_prefix_info[j].prefix);
2119
2120       if (len_prefix_text < len_music_text &&
2121           strncmp(music->token,
2122                   music_prefix_info[j].prefix, len_prefix_text) == 0)
2123       {
2124         music_info[i].loop = music_prefix_info[j].is_loop_music;
2125
2126         break;
2127       }
2128     }
2129
2130     set_music_parameters(i, music->parameter);
2131   }
2132 }
2133
2134 static void ReinitializeGraphics()
2135 {
2136   print_timestamp_init("ReinitializeGraphics");
2137
2138   InitGfxTileSizeInfo(game.tile_size, TILESIZE);
2139
2140   InitGraphicInfo();                    /* graphic properties mapping */
2141   print_timestamp_time("InitGraphicInfo");
2142   InitElementGraphicInfo();             /* element game graphic mapping */
2143   print_timestamp_time("InitElementGraphicInfo");
2144   InitElementSpecialGraphicInfo();      /* element special graphic mapping */
2145   print_timestamp_time("InitElementSpecialGraphicInfo");
2146
2147   InitElementSmallImages();             /* scale elements to all needed sizes */
2148   print_timestamp_time("InitElementSmallImages");
2149   InitScaledImages();                   /* scale all other images, if needed */
2150   print_timestamp_time("InitScaledImages");
2151   InitBitmapPointers();                 /* set standard size bitmap pointers */
2152   print_timestamp_time("InitBitmapPointers");
2153   InitFontGraphicInfo();                /* initialize text drawing functions */
2154   print_timestamp_time("InitFontGraphicInfo");
2155   InitGlobalAnimGraphicInfo();          /* initialize global animation config */
2156   print_timestamp_time("InitGlobalAnimGraphicInfo");
2157
2158   InitImageTextures();                  /* create textures for certain images */
2159   print_timestamp_time("InitImageTextures");
2160
2161   InitGraphicInfo_EM();                 /* graphic mapping for EM engine */
2162   print_timestamp_time("InitGraphicInfo_EM");
2163
2164   InitGraphicCompatibilityInfo();
2165   print_timestamp_time("InitGraphicCompatibilityInfo");
2166
2167   SetMainBackgroundImage(IMG_BACKGROUND);
2168   print_timestamp_time("SetMainBackgroundImage");
2169   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2170   print_timestamp_time("SetDoorBackgroundImage");
2171
2172   InitGadgets();
2173   print_timestamp_time("InitGadgets");
2174   InitDoors();
2175   print_timestamp_time("InitDoors");
2176
2177   print_timestamp_done("ReinitializeGraphics");
2178 }
2179
2180 static void ReinitializeSounds()
2181 {
2182   InitSoundInfo();              /* sound properties mapping */
2183   InitElementSoundInfo();       /* element game sound mapping */
2184   InitGameModeSoundInfo();      /* game mode sound mapping */
2185   InitGlobalAnimSoundInfo();    /* global animation sound settings */
2186
2187   InitPlayLevelSound();         /* internal game sound settings */
2188 }
2189
2190 static void ReinitializeMusic()
2191 {
2192   InitMusicInfo();              /* music properties mapping */
2193   InitGameModeMusicInfo();      /* game mode music mapping */
2194   InitGlobalAnimMusicInfo();    /* global animation music settings */
2195 }
2196
2197 static int get_special_property_bit(int element, int property_bit_nr)
2198 {
2199   struct PropertyBitInfo
2200   {
2201     int element;
2202     int bit_nr;
2203   };
2204
2205   static struct PropertyBitInfo pb_can_move_into_acid[] =
2206   {
2207     /* the player may be able fall into acid when gravity is activated */
2208     { EL_PLAYER_1,              0       },
2209     { EL_PLAYER_2,              0       },
2210     { EL_PLAYER_3,              0       },
2211     { EL_PLAYER_4,              0       },
2212     { EL_SP_MURPHY,             0       },
2213     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2214
2215     /* all elements that can move may be able to also move into acid */
2216     { EL_BUG,                   1       },
2217     { EL_BUG_LEFT,              1       },
2218     { EL_BUG_RIGHT,             1       },
2219     { EL_BUG_UP,                1       },
2220     { EL_BUG_DOWN,              1       },
2221     { EL_SPACESHIP,             2       },
2222     { EL_SPACESHIP_LEFT,        2       },
2223     { EL_SPACESHIP_RIGHT,       2       },
2224     { EL_SPACESHIP_UP,          2       },
2225     { EL_SPACESHIP_DOWN,        2       },
2226     { EL_BD_BUTTERFLY,          3       },
2227     { EL_BD_BUTTERFLY_LEFT,     3       },
2228     { EL_BD_BUTTERFLY_RIGHT,    3       },
2229     { EL_BD_BUTTERFLY_UP,       3       },
2230     { EL_BD_BUTTERFLY_DOWN,     3       },
2231     { EL_BD_FIREFLY,            4       },
2232     { EL_BD_FIREFLY_LEFT,       4       },
2233     { EL_BD_FIREFLY_RIGHT,      4       },
2234     { EL_BD_FIREFLY_UP,         4       },
2235     { EL_BD_FIREFLY_DOWN,       4       },
2236     { EL_YAMYAM,                5       },
2237     { EL_YAMYAM_LEFT,           5       },
2238     { EL_YAMYAM_RIGHT,          5       },
2239     { EL_YAMYAM_UP,             5       },
2240     { EL_YAMYAM_DOWN,           5       },
2241     { EL_DARK_YAMYAM,           6       },
2242     { EL_ROBOT,                 7       },
2243     { EL_PACMAN,                8       },
2244     { EL_PACMAN_LEFT,           8       },
2245     { EL_PACMAN_RIGHT,          8       },
2246     { EL_PACMAN_UP,             8       },
2247     { EL_PACMAN_DOWN,           8       },
2248     { EL_MOLE,                  9       },
2249     { EL_MOLE_LEFT,             9       },
2250     { EL_MOLE_RIGHT,            9       },
2251     { EL_MOLE_UP,               9       },
2252     { EL_MOLE_DOWN,             9       },
2253     { EL_PENGUIN,               10      },
2254     { EL_PIG,                   11      },
2255     { EL_DRAGON,                12      },
2256     { EL_SATELLITE,             13      },
2257     { EL_SP_SNIKSNAK,           14      },
2258     { EL_SP_ELECTRON,           15      },
2259     { EL_BALLOON,               16      },
2260     { EL_SPRING,                17      },
2261     { EL_EMC_ANDROID,           18      },
2262
2263     { -1,                       -1      },
2264   };
2265
2266   static struct PropertyBitInfo pb_dont_collide_with[] =
2267   {
2268     { EL_SP_SNIKSNAK,           0       },
2269     { EL_SP_ELECTRON,           1       },
2270
2271     { -1,                       -1      },
2272   };
2273
2274   static struct
2275   {
2276     int bit_nr;
2277     struct PropertyBitInfo *pb_info;
2278   } pb_definition[] =
2279   {
2280     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2281     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2282
2283     { -1,                       NULL                    },
2284   };
2285
2286   struct PropertyBitInfo *pb_info = NULL;
2287   int i;
2288
2289   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2290     if (pb_definition[i].bit_nr == property_bit_nr)
2291       pb_info = pb_definition[i].pb_info;
2292
2293   if (pb_info == NULL)
2294     return -1;
2295
2296   for (i = 0; pb_info[i].element != -1; i++)
2297     if (pb_info[i].element == element)
2298       return pb_info[i].bit_nr;
2299
2300   return -1;
2301 }
2302
2303 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2304                          boolean property_value)
2305 {
2306   int bit_nr = get_special_property_bit(element, property_bit_nr);
2307
2308   if (bit_nr > -1)
2309   {
2310     if (property_value)
2311       *bitfield |=  (1 << bit_nr);
2312     else
2313       *bitfield &= ~(1 << bit_nr);
2314   }
2315 }
2316
2317 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2318 {
2319   int bit_nr = get_special_property_bit(element, property_bit_nr);
2320
2321   if (bit_nr > -1)
2322     return ((*bitfield & (1 << bit_nr)) != 0);
2323
2324   return FALSE;
2325 }
2326
2327 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2328 {
2329   static int group_nr;
2330   static struct ElementGroupInfo *group;
2331   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2332   int i;
2333
2334   if (actual_group == NULL)                     /* not yet initialized */
2335     return;
2336
2337   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2338   {
2339     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2340           group_element - EL_GROUP_START + 1);
2341
2342     /* replace element which caused too deep recursion by question mark */
2343     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2344
2345     return;
2346   }
2347
2348   if (recursion_depth == 0)                     /* initialization */
2349   {
2350     group = actual_group;
2351     group_nr = GROUP_NR(group_element);
2352
2353     group->num_elements_resolved = 0;
2354     group->choice_pos = 0;
2355
2356     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2357       element_info[i].in_group[group_nr] = FALSE;
2358   }
2359
2360   for (i = 0; i < actual_group->num_elements; i++)
2361   {
2362     int element = actual_group->element[i];
2363
2364     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2365       break;
2366
2367     if (IS_GROUP_ELEMENT(element))
2368       ResolveGroupElementExt(element, recursion_depth + 1);
2369     else
2370     {
2371       group->element_resolved[group->num_elements_resolved++] = element;
2372       element_info[element].in_group[group_nr] = TRUE;
2373     }
2374   }
2375 }
2376
2377 void ResolveGroupElement(int group_element)
2378 {
2379   ResolveGroupElementExt(group_element, 0);
2380 }
2381
2382 void InitElementPropertiesStatic()
2383 {
2384   static boolean clipboard_elements_initialized = FALSE;
2385
2386   static int ep_diggable[] =
2387   {
2388     EL_SAND,
2389     EL_SP_BASE,
2390     EL_SP_BUGGY_BASE,
2391     EL_SP_BUGGY_BASE_ACTIVATING,
2392     EL_TRAP,
2393     EL_INVISIBLE_SAND,
2394     EL_INVISIBLE_SAND_ACTIVE,
2395     EL_EMC_GRASS,
2396
2397     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2398     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2399 #if 0
2400     EL_LANDMINE,
2401     EL_DC_LANDMINE,
2402     EL_TRAP_ACTIVE,
2403     EL_SP_BUGGY_BASE_ACTIVE,
2404     EL_EMC_PLANT,
2405 #endif
2406
2407     -1
2408   };
2409
2410   static int ep_collectible_only[] =
2411   {
2412     EL_BD_DIAMOND,
2413     EL_EMERALD,
2414     EL_DIAMOND,
2415     EL_EMERALD_YELLOW,
2416     EL_EMERALD_RED,
2417     EL_EMERALD_PURPLE,
2418     EL_KEY_1,
2419     EL_KEY_2,
2420     EL_KEY_3,
2421     EL_KEY_4,
2422     EL_EM_KEY_1,
2423     EL_EM_KEY_2,
2424     EL_EM_KEY_3,
2425     EL_EM_KEY_4,
2426     EL_EMC_KEY_5,
2427     EL_EMC_KEY_6,
2428     EL_EMC_KEY_7,
2429     EL_EMC_KEY_8,
2430     EL_DYNAMITE,
2431     EL_EM_DYNAMITE,
2432     EL_DYNABOMB_INCREASE_NUMBER,
2433     EL_DYNABOMB_INCREASE_SIZE,
2434     EL_DYNABOMB_INCREASE_POWER,
2435     EL_SP_INFOTRON,
2436     EL_SP_DISK_RED,
2437     EL_PEARL,
2438     EL_CRYSTAL,
2439     EL_DC_KEY_WHITE,
2440     EL_SHIELD_NORMAL,
2441     EL_SHIELD_DEADLY,
2442     EL_EXTRA_TIME,
2443     EL_ENVELOPE_1,
2444     EL_ENVELOPE_2,
2445     EL_ENVELOPE_3,
2446     EL_ENVELOPE_4,
2447     EL_SPEED_PILL,
2448     EL_EMC_LENSES,
2449     EL_EMC_MAGNIFIER,
2450
2451 #if 0
2452     /* !!! handle separately !!! */
2453     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2454 #endif
2455
2456     -1
2457   };
2458
2459   static int ep_dont_run_into[] =
2460   {
2461     /* same elements as in 'ep_dont_touch' */
2462     EL_BUG,
2463     EL_SPACESHIP,
2464     EL_BD_BUTTERFLY,
2465     EL_BD_FIREFLY,
2466
2467     /* same elements as in 'ep_dont_collide_with' */
2468     EL_YAMYAM,
2469     EL_DARK_YAMYAM,
2470     EL_ROBOT,
2471     EL_PACMAN,
2472     EL_SP_SNIKSNAK,
2473     EL_SP_ELECTRON,
2474
2475     /* new elements */
2476     EL_AMOEBA_DROP,
2477     EL_ACID,
2478
2479     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2480 #if 1
2481     EL_LANDMINE,
2482     EL_DC_LANDMINE,
2483     EL_TRAP_ACTIVE,
2484     EL_SP_BUGGY_BASE_ACTIVE,
2485     EL_EMC_PLANT,
2486 #endif
2487
2488     -1
2489   };
2490
2491   static int ep_dont_collide_with[] =
2492   {
2493     /* same elements as in 'ep_dont_touch' */
2494     EL_BUG,
2495     EL_SPACESHIP,
2496     EL_BD_BUTTERFLY,
2497     EL_BD_FIREFLY,
2498
2499     /* new elements */
2500     EL_YAMYAM,
2501     EL_DARK_YAMYAM,
2502     EL_ROBOT,
2503     EL_PACMAN,
2504     EL_SP_SNIKSNAK,
2505     EL_SP_ELECTRON,
2506
2507     -1
2508   };
2509
2510   static int ep_dont_touch[] =
2511   {
2512     EL_BUG,
2513     EL_SPACESHIP,
2514     EL_BD_BUTTERFLY,
2515     EL_BD_FIREFLY,
2516
2517     -1
2518   };
2519
2520   static int ep_indestructible[] =
2521   {
2522     EL_STEELWALL,
2523     EL_ACID,
2524     EL_ACID_POOL_TOPLEFT,
2525     EL_ACID_POOL_TOPRIGHT,
2526     EL_ACID_POOL_BOTTOMLEFT,
2527     EL_ACID_POOL_BOTTOM,
2528     EL_ACID_POOL_BOTTOMRIGHT,
2529     EL_SP_HARDWARE_GRAY,
2530     EL_SP_HARDWARE_GREEN,
2531     EL_SP_HARDWARE_BLUE,
2532     EL_SP_HARDWARE_RED,
2533     EL_SP_HARDWARE_YELLOW,
2534     EL_SP_HARDWARE_BASE_1,
2535     EL_SP_HARDWARE_BASE_2,
2536     EL_SP_HARDWARE_BASE_3,
2537     EL_SP_HARDWARE_BASE_4,
2538     EL_SP_HARDWARE_BASE_5,
2539     EL_SP_HARDWARE_BASE_6,
2540     EL_INVISIBLE_STEELWALL,
2541     EL_INVISIBLE_STEELWALL_ACTIVE,
2542     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2543     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2544     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2545     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2546     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2547     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2548     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2549     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2550     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2551     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2552     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2553     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2554     EL_LIGHT_SWITCH,
2555     EL_LIGHT_SWITCH_ACTIVE,
2556     EL_SIGN_EXCLAMATION,
2557     EL_SIGN_RADIOACTIVITY,
2558     EL_SIGN_STOP,
2559     EL_SIGN_WHEELCHAIR,
2560     EL_SIGN_PARKING,
2561     EL_SIGN_NO_ENTRY,
2562     EL_SIGN_UNUSED_1,
2563     EL_SIGN_GIVE_WAY,
2564     EL_SIGN_ENTRY_FORBIDDEN,
2565     EL_SIGN_EMERGENCY_EXIT,
2566     EL_SIGN_YIN_YANG,
2567     EL_SIGN_UNUSED_2,
2568     EL_SIGN_SPERMS,
2569     EL_SIGN_BULLET,
2570     EL_SIGN_HEART,
2571     EL_SIGN_CROSS,
2572     EL_SIGN_FRANKIE,
2573     EL_STEEL_EXIT_CLOSED,
2574     EL_STEEL_EXIT_OPEN,
2575     EL_STEEL_EXIT_OPENING,
2576     EL_STEEL_EXIT_CLOSING,
2577     EL_EM_STEEL_EXIT_CLOSED,
2578     EL_EM_STEEL_EXIT_OPEN,
2579     EL_EM_STEEL_EXIT_OPENING,
2580     EL_EM_STEEL_EXIT_CLOSING,
2581     EL_DC_STEELWALL_1_LEFT,
2582     EL_DC_STEELWALL_1_RIGHT,
2583     EL_DC_STEELWALL_1_TOP,
2584     EL_DC_STEELWALL_1_BOTTOM,
2585     EL_DC_STEELWALL_1_HORIZONTAL,
2586     EL_DC_STEELWALL_1_VERTICAL,
2587     EL_DC_STEELWALL_1_TOPLEFT,
2588     EL_DC_STEELWALL_1_TOPRIGHT,
2589     EL_DC_STEELWALL_1_BOTTOMLEFT,
2590     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2591     EL_DC_STEELWALL_1_TOPLEFT_2,
2592     EL_DC_STEELWALL_1_TOPRIGHT_2,
2593     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2594     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2595     EL_DC_STEELWALL_2_LEFT,
2596     EL_DC_STEELWALL_2_RIGHT,
2597     EL_DC_STEELWALL_2_TOP,
2598     EL_DC_STEELWALL_2_BOTTOM,
2599     EL_DC_STEELWALL_2_HORIZONTAL,
2600     EL_DC_STEELWALL_2_VERTICAL,
2601     EL_DC_STEELWALL_2_MIDDLE,
2602     EL_DC_STEELWALL_2_SINGLE,
2603     EL_STEELWALL_SLIPPERY,
2604     EL_EMC_STEELWALL_1,
2605     EL_EMC_STEELWALL_2,
2606     EL_EMC_STEELWALL_3,
2607     EL_EMC_STEELWALL_4,
2608     EL_CRYSTAL,
2609     EL_GATE_1,
2610     EL_GATE_2,
2611     EL_GATE_3,
2612     EL_GATE_4,
2613     EL_GATE_1_GRAY,
2614     EL_GATE_2_GRAY,
2615     EL_GATE_3_GRAY,
2616     EL_GATE_4_GRAY,
2617     EL_GATE_1_GRAY_ACTIVE,
2618     EL_GATE_2_GRAY_ACTIVE,
2619     EL_GATE_3_GRAY_ACTIVE,
2620     EL_GATE_4_GRAY_ACTIVE,
2621     EL_EM_GATE_1,
2622     EL_EM_GATE_2,
2623     EL_EM_GATE_3,
2624     EL_EM_GATE_4,
2625     EL_EM_GATE_1_GRAY,
2626     EL_EM_GATE_2_GRAY,
2627     EL_EM_GATE_3_GRAY,
2628     EL_EM_GATE_4_GRAY,
2629     EL_EM_GATE_1_GRAY_ACTIVE,
2630     EL_EM_GATE_2_GRAY_ACTIVE,
2631     EL_EM_GATE_3_GRAY_ACTIVE,
2632     EL_EM_GATE_4_GRAY_ACTIVE,
2633     EL_EMC_GATE_5,
2634     EL_EMC_GATE_6,
2635     EL_EMC_GATE_7,
2636     EL_EMC_GATE_8,
2637     EL_EMC_GATE_5_GRAY,
2638     EL_EMC_GATE_6_GRAY,
2639     EL_EMC_GATE_7_GRAY,
2640     EL_EMC_GATE_8_GRAY,
2641     EL_EMC_GATE_5_GRAY_ACTIVE,
2642     EL_EMC_GATE_6_GRAY_ACTIVE,
2643     EL_EMC_GATE_7_GRAY_ACTIVE,
2644     EL_EMC_GATE_8_GRAY_ACTIVE,
2645     EL_DC_GATE_WHITE,
2646     EL_DC_GATE_WHITE_GRAY,
2647     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2648     EL_DC_GATE_FAKE_GRAY,
2649     EL_SWITCHGATE_OPEN,
2650     EL_SWITCHGATE_OPENING,
2651     EL_SWITCHGATE_CLOSED,
2652     EL_SWITCHGATE_CLOSING,
2653     EL_DC_SWITCHGATE_SWITCH_UP,
2654     EL_DC_SWITCHGATE_SWITCH_DOWN,
2655     EL_TIMEGATE_OPEN,
2656     EL_TIMEGATE_OPENING,
2657     EL_TIMEGATE_CLOSED,
2658     EL_TIMEGATE_CLOSING,
2659     EL_DC_TIMEGATE_SWITCH,
2660     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2661     EL_TUBE_ANY,
2662     EL_TUBE_VERTICAL,
2663     EL_TUBE_HORIZONTAL,
2664     EL_TUBE_VERTICAL_LEFT,
2665     EL_TUBE_VERTICAL_RIGHT,
2666     EL_TUBE_HORIZONTAL_UP,
2667     EL_TUBE_HORIZONTAL_DOWN,
2668     EL_TUBE_LEFT_UP,
2669     EL_TUBE_LEFT_DOWN,
2670     EL_TUBE_RIGHT_UP,
2671     EL_TUBE_RIGHT_DOWN,
2672     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2673     EL_EXPANDABLE_STEELWALL_VERTICAL,
2674     EL_EXPANDABLE_STEELWALL_ANY,
2675
2676     -1
2677   };
2678
2679   static int ep_slippery[] =
2680   {
2681     EL_WALL_SLIPPERY,
2682     EL_BD_WALL,
2683     EL_ROCK,
2684     EL_BD_ROCK,
2685     EL_EMERALD,
2686     EL_BD_DIAMOND,
2687     EL_EMERALD_YELLOW,
2688     EL_EMERALD_RED,
2689     EL_EMERALD_PURPLE,
2690     EL_DIAMOND,
2691     EL_BOMB,
2692     EL_NUT,
2693     EL_ROBOT_WHEEL_ACTIVE,
2694     EL_ROBOT_WHEEL,
2695     EL_TIME_ORB_FULL,
2696     EL_TIME_ORB_EMPTY,
2697     EL_LAMP_ACTIVE,
2698     EL_LAMP,
2699     EL_ACID_POOL_TOPLEFT,
2700     EL_ACID_POOL_TOPRIGHT,
2701     EL_SATELLITE,
2702     EL_SP_ZONK,
2703     EL_SP_INFOTRON,
2704     EL_SP_CHIP_SINGLE,
2705     EL_SP_CHIP_LEFT,
2706     EL_SP_CHIP_RIGHT,
2707     EL_SP_CHIP_TOP,
2708     EL_SP_CHIP_BOTTOM,
2709     EL_SPEED_PILL,
2710     EL_STEELWALL_SLIPPERY,
2711     EL_PEARL,
2712     EL_CRYSTAL,
2713     EL_EMC_WALL_SLIPPERY_1,
2714     EL_EMC_WALL_SLIPPERY_2,
2715     EL_EMC_WALL_SLIPPERY_3,
2716     EL_EMC_WALL_SLIPPERY_4,
2717     EL_EMC_MAGIC_BALL,
2718     EL_EMC_MAGIC_BALL_ACTIVE,
2719
2720     -1
2721   };
2722
2723   static int ep_can_change[] =
2724   {
2725     -1
2726   };
2727
2728   static int ep_can_move[] =
2729   {
2730     /* same elements as in 'pb_can_move_into_acid' */
2731     EL_BUG,
2732     EL_SPACESHIP,
2733     EL_BD_BUTTERFLY,
2734     EL_BD_FIREFLY,
2735     EL_YAMYAM,
2736     EL_DARK_YAMYAM,
2737     EL_ROBOT,
2738     EL_PACMAN,
2739     EL_MOLE,
2740     EL_PENGUIN,
2741     EL_PIG,
2742     EL_DRAGON,
2743     EL_SATELLITE,
2744     EL_SP_SNIKSNAK,
2745     EL_SP_ELECTRON,
2746     EL_BALLOON,
2747     EL_SPRING,
2748     EL_EMC_ANDROID,
2749
2750     -1
2751   };
2752
2753   static int ep_can_fall[] =
2754   {
2755     EL_ROCK,
2756     EL_BD_ROCK,
2757     EL_EMERALD,
2758     EL_BD_DIAMOND,
2759     EL_EMERALD_YELLOW,
2760     EL_EMERALD_RED,
2761     EL_EMERALD_PURPLE,
2762     EL_DIAMOND,
2763     EL_BOMB,
2764     EL_NUT,
2765     EL_AMOEBA_DROP,
2766     EL_QUICKSAND_FULL,
2767     EL_QUICKSAND_FAST_FULL,
2768     EL_MAGIC_WALL_FULL,
2769     EL_BD_MAGIC_WALL_FULL,
2770     EL_DC_MAGIC_WALL_FULL,
2771     EL_TIME_ORB_FULL,
2772     EL_TIME_ORB_EMPTY,
2773     EL_SP_ZONK,
2774     EL_SP_INFOTRON,
2775     EL_SP_DISK_ORANGE,
2776     EL_PEARL,
2777     EL_CRYSTAL,
2778     EL_SPRING,
2779     EL_DX_SUPABOMB,
2780
2781     -1
2782   };
2783
2784   static int ep_can_smash_player[] =
2785   {
2786     EL_ROCK,
2787     EL_BD_ROCK,
2788     EL_EMERALD,
2789     EL_BD_DIAMOND,
2790     EL_EMERALD_YELLOW,
2791     EL_EMERALD_RED,
2792     EL_EMERALD_PURPLE,
2793     EL_DIAMOND,
2794     EL_BOMB,
2795     EL_NUT,
2796     EL_AMOEBA_DROP,
2797     EL_TIME_ORB_FULL,
2798     EL_TIME_ORB_EMPTY,
2799     EL_SP_ZONK,
2800     EL_SP_INFOTRON,
2801     EL_SP_DISK_ORANGE,
2802     EL_PEARL,
2803     EL_CRYSTAL,
2804     EL_SPRING,
2805     EL_DX_SUPABOMB,
2806
2807     -1
2808   };
2809
2810   static int ep_can_smash_enemies[] =
2811   {
2812     EL_ROCK,
2813     EL_BD_ROCK,
2814     EL_SP_ZONK,
2815
2816     -1
2817   };
2818
2819   static int ep_can_smash_everything[] =
2820   {
2821     EL_ROCK,
2822     EL_BD_ROCK,
2823     EL_SP_ZONK,
2824
2825     -1
2826   };
2827
2828   static int ep_explodes_by_fire[] =
2829   {
2830     /* same elements as in 'ep_explodes_impact' */
2831     EL_BOMB,
2832     EL_SP_DISK_ORANGE,
2833     EL_DX_SUPABOMB,
2834
2835     /* same elements as in 'ep_explodes_smashed' */
2836     EL_SATELLITE,
2837     EL_PIG,
2838     EL_DRAGON,
2839     EL_MOLE,
2840
2841     /* new elements */
2842     EL_DYNAMITE,
2843     EL_DYNAMITE_ACTIVE,
2844     EL_EM_DYNAMITE,
2845     EL_EM_DYNAMITE_ACTIVE,
2846     EL_DYNABOMB_PLAYER_1_ACTIVE,
2847     EL_DYNABOMB_PLAYER_2_ACTIVE,
2848     EL_DYNABOMB_PLAYER_3_ACTIVE,
2849     EL_DYNABOMB_PLAYER_4_ACTIVE,
2850     EL_DYNABOMB_INCREASE_NUMBER,
2851     EL_DYNABOMB_INCREASE_SIZE,
2852     EL_DYNABOMB_INCREASE_POWER,
2853     EL_SP_DISK_RED_ACTIVE,
2854     EL_BUG,
2855     EL_PENGUIN,
2856     EL_SP_DISK_RED,
2857     EL_SP_DISK_YELLOW,
2858     EL_SP_SNIKSNAK,
2859     EL_SP_ELECTRON,
2860 #if 0
2861     EL_BLACK_ORB,
2862 #endif
2863
2864     -1
2865   };
2866
2867   static int ep_explodes_smashed[] =
2868   {
2869     /* same elements as in 'ep_explodes_impact' */
2870     EL_BOMB,
2871     EL_SP_DISK_ORANGE,
2872     EL_DX_SUPABOMB,
2873
2874     /* new elements */
2875     EL_SATELLITE,
2876     EL_PIG,
2877     EL_DRAGON,
2878     EL_MOLE,
2879
2880     -1
2881   };
2882
2883   static int ep_explodes_impact[] =
2884   {
2885     EL_BOMB,
2886     EL_SP_DISK_ORANGE,
2887     EL_DX_SUPABOMB,
2888
2889     -1
2890   };
2891
2892   static int ep_walkable_over[] =
2893   {
2894     EL_EMPTY_SPACE,
2895     EL_SP_EMPTY_SPACE,
2896     EL_SOKOBAN_FIELD_EMPTY,
2897     EL_EXIT_OPEN,
2898     EL_EM_EXIT_OPEN,
2899     EL_EM_EXIT_OPENING,
2900     EL_SP_EXIT_OPEN,
2901     EL_SP_EXIT_OPENING,
2902     EL_STEEL_EXIT_OPEN,
2903     EL_EM_STEEL_EXIT_OPEN,
2904     EL_EM_STEEL_EXIT_OPENING,
2905     EL_GATE_1,
2906     EL_GATE_2,
2907     EL_GATE_3,
2908     EL_GATE_4,
2909     EL_GATE_1_GRAY,
2910     EL_GATE_2_GRAY,
2911     EL_GATE_3_GRAY,
2912     EL_GATE_4_GRAY,
2913     EL_GATE_1_GRAY_ACTIVE,
2914     EL_GATE_2_GRAY_ACTIVE,
2915     EL_GATE_3_GRAY_ACTIVE,
2916     EL_GATE_4_GRAY_ACTIVE,
2917     EL_PENGUIN,
2918     EL_PIG,
2919     EL_DRAGON,
2920
2921     -1
2922   };
2923
2924   static int ep_walkable_inside[] =
2925   {
2926     EL_TUBE_ANY,
2927     EL_TUBE_VERTICAL,
2928     EL_TUBE_HORIZONTAL,
2929     EL_TUBE_VERTICAL_LEFT,
2930     EL_TUBE_VERTICAL_RIGHT,
2931     EL_TUBE_HORIZONTAL_UP,
2932     EL_TUBE_HORIZONTAL_DOWN,
2933     EL_TUBE_LEFT_UP,
2934     EL_TUBE_LEFT_DOWN,
2935     EL_TUBE_RIGHT_UP,
2936     EL_TUBE_RIGHT_DOWN,
2937
2938     -1
2939   };
2940
2941   static int ep_walkable_under[] =
2942   {
2943     -1
2944   };
2945
2946   static int ep_passable_over[] =
2947   {
2948     EL_EM_GATE_1,
2949     EL_EM_GATE_2,
2950     EL_EM_GATE_3,
2951     EL_EM_GATE_4,
2952     EL_EM_GATE_1_GRAY,
2953     EL_EM_GATE_2_GRAY,
2954     EL_EM_GATE_3_GRAY,
2955     EL_EM_GATE_4_GRAY,
2956     EL_EM_GATE_1_GRAY_ACTIVE,
2957     EL_EM_GATE_2_GRAY_ACTIVE,
2958     EL_EM_GATE_3_GRAY_ACTIVE,
2959     EL_EM_GATE_4_GRAY_ACTIVE,
2960     EL_EMC_GATE_5,
2961     EL_EMC_GATE_6,
2962     EL_EMC_GATE_7,
2963     EL_EMC_GATE_8,
2964     EL_EMC_GATE_5_GRAY,
2965     EL_EMC_GATE_6_GRAY,
2966     EL_EMC_GATE_7_GRAY,
2967     EL_EMC_GATE_8_GRAY,
2968     EL_EMC_GATE_5_GRAY_ACTIVE,
2969     EL_EMC_GATE_6_GRAY_ACTIVE,
2970     EL_EMC_GATE_7_GRAY_ACTIVE,
2971     EL_EMC_GATE_8_GRAY_ACTIVE,
2972     EL_DC_GATE_WHITE,
2973     EL_DC_GATE_WHITE_GRAY,
2974     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2975     EL_SWITCHGATE_OPEN,
2976     EL_TIMEGATE_OPEN,
2977
2978     -1
2979   };
2980
2981   static int ep_passable_inside[] =
2982   {
2983     EL_SP_PORT_LEFT,
2984     EL_SP_PORT_RIGHT,
2985     EL_SP_PORT_UP,
2986     EL_SP_PORT_DOWN,
2987     EL_SP_PORT_HORIZONTAL,
2988     EL_SP_PORT_VERTICAL,
2989     EL_SP_PORT_ANY,
2990     EL_SP_GRAVITY_PORT_LEFT,
2991     EL_SP_GRAVITY_PORT_RIGHT,
2992     EL_SP_GRAVITY_PORT_UP,
2993     EL_SP_GRAVITY_PORT_DOWN,
2994     EL_SP_GRAVITY_ON_PORT_LEFT,
2995     EL_SP_GRAVITY_ON_PORT_RIGHT,
2996     EL_SP_GRAVITY_ON_PORT_UP,
2997     EL_SP_GRAVITY_ON_PORT_DOWN,
2998     EL_SP_GRAVITY_OFF_PORT_LEFT,
2999     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3000     EL_SP_GRAVITY_OFF_PORT_UP,
3001     EL_SP_GRAVITY_OFF_PORT_DOWN,
3002
3003     -1
3004   };
3005
3006   static int ep_passable_under[] =
3007   {
3008     -1
3009   };
3010
3011   static int ep_droppable[] =
3012   {
3013     -1
3014   };
3015
3016   static int ep_explodes_1x1_old[] =
3017   {
3018     -1
3019   };
3020
3021   static int ep_pushable[] =
3022   {
3023     EL_ROCK,
3024     EL_BOMB,
3025     EL_DX_SUPABOMB,
3026     EL_NUT,
3027     EL_TIME_ORB_EMPTY,
3028     EL_SP_ZONK,
3029     EL_SP_DISK_ORANGE,
3030     EL_SPRING,
3031     EL_BD_ROCK,
3032     EL_SOKOBAN_OBJECT,
3033     EL_SOKOBAN_FIELD_FULL,
3034     EL_SATELLITE,
3035     EL_SP_DISK_YELLOW,
3036     EL_BALLOON,
3037     EL_EMC_ANDROID,
3038
3039     -1
3040   };
3041
3042   static int ep_explodes_cross_old[] =
3043   {
3044     -1
3045   };
3046
3047   static int ep_protected[] =
3048   {
3049     /* same elements as in 'ep_walkable_inside' */
3050     EL_TUBE_ANY,
3051     EL_TUBE_VERTICAL,
3052     EL_TUBE_HORIZONTAL,
3053     EL_TUBE_VERTICAL_LEFT,
3054     EL_TUBE_VERTICAL_RIGHT,
3055     EL_TUBE_HORIZONTAL_UP,
3056     EL_TUBE_HORIZONTAL_DOWN,
3057     EL_TUBE_LEFT_UP,
3058     EL_TUBE_LEFT_DOWN,
3059     EL_TUBE_RIGHT_UP,
3060     EL_TUBE_RIGHT_DOWN,
3061
3062     /* same elements as in 'ep_passable_over' */
3063     EL_EM_GATE_1,
3064     EL_EM_GATE_2,
3065     EL_EM_GATE_3,
3066     EL_EM_GATE_4,
3067     EL_EM_GATE_1_GRAY,
3068     EL_EM_GATE_2_GRAY,
3069     EL_EM_GATE_3_GRAY,
3070     EL_EM_GATE_4_GRAY,
3071     EL_EM_GATE_1_GRAY_ACTIVE,
3072     EL_EM_GATE_2_GRAY_ACTIVE,
3073     EL_EM_GATE_3_GRAY_ACTIVE,
3074     EL_EM_GATE_4_GRAY_ACTIVE,
3075     EL_EMC_GATE_5,
3076     EL_EMC_GATE_6,
3077     EL_EMC_GATE_7,
3078     EL_EMC_GATE_8,
3079     EL_EMC_GATE_5_GRAY,
3080     EL_EMC_GATE_6_GRAY,
3081     EL_EMC_GATE_7_GRAY,
3082     EL_EMC_GATE_8_GRAY,
3083     EL_EMC_GATE_5_GRAY_ACTIVE,
3084     EL_EMC_GATE_6_GRAY_ACTIVE,
3085     EL_EMC_GATE_7_GRAY_ACTIVE,
3086     EL_EMC_GATE_8_GRAY_ACTIVE,
3087     EL_DC_GATE_WHITE,
3088     EL_DC_GATE_WHITE_GRAY,
3089     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3090     EL_SWITCHGATE_OPEN,
3091     EL_TIMEGATE_OPEN,
3092
3093     /* same elements as in 'ep_passable_inside' */
3094     EL_SP_PORT_LEFT,
3095     EL_SP_PORT_RIGHT,
3096     EL_SP_PORT_UP,
3097     EL_SP_PORT_DOWN,
3098     EL_SP_PORT_HORIZONTAL,
3099     EL_SP_PORT_VERTICAL,
3100     EL_SP_PORT_ANY,
3101     EL_SP_GRAVITY_PORT_LEFT,
3102     EL_SP_GRAVITY_PORT_RIGHT,
3103     EL_SP_GRAVITY_PORT_UP,
3104     EL_SP_GRAVITY_PORT_DOWN,
3105     EL_SP_GRAVITY_ON_PORT_LEFT,
3106     EL_SP_GRAVITY_ON_PORT_RIGHT,
3107     EL_SP_GRAVITY_ON_PORT_UP,
3108     EL_SP_GRAVITY_ON_PORT_DOWN,
3109     EL_SP_GRAVITY_OFF_PORT_LEFT,
3110     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3111     EL_SP_GRAVITY_OFF_PORT_UP,
3112     EL_SP_GRAVITY_OFF_PORT_DOWN,
3113
3114     -1
3115   };
3116
3117   static int ep_throwable[] =
3118   {
3119     -1
3120   };
3121
3122   static int ep_can_explode[] =
3123   {
3124     /* same elements as in 'ep_explodes_impact' */
3125     EL_BOMB,
3126     EL_SP_DISK_ORANGE,
3127     EL_DX_SUPABOMB,
3128
3129     /* same elements as in 'ep_explodes_smashed' */
3130     EL_SATELLITE,
3131     EL_PIG,
3132     EL_DRAGON,
3133     EL_MOLE,
3134
3135     /* elements that can explode by explosion or by dragonfire */
3136     EL_DYNAMITE,
3137     EL_DYNAMITE_ACTIVE,
3138     EL_EM_DYNAMITE,
3139     EL_EM_DYNAMITE_ACTIVE,
3140     EL_DYNABOMB_PLAYER_1_ACTIVE,
3141     EL_DYNABOMB_PLAYER_2_ACTIVE,
3142     EL_DYNABOMB_PLAYER_3_ACTIVE,
3143     EL_DYNABOMB_PLAYER_4_ACTIVE,
3144     EL_DYNABOMB_INCREASE_NUMBER,
3145     EL_DYNABOMB_INCREASE_SIZE,
3146     EL_DYNABOMB_INCREASE_POWER,
3147     EL_SP_DISK_RED_ACTIVE,
3148     EL_BUG,
3149     EL_PENGUIN,
3150     EL_SP_DISK_RED,
3151     EL_SP_DISK_YELLOW,
3152     EL_SP_SNIKSNAK,
3153     EL_SP_ELECTRON,
3154
3155     /* elements that can explode only by explosion */
3156     EL_BLACK_ORB,
3157
3158     -1
3159   };
3160
3161   static int ep_gravity_reachable[] =
3162   {
3163     EL_SAND,
3164     EL_SP_BASE,
3165     EL_TRAP,
3166     EL_INVISIBLE_SAND,
3167     EL_INVISIBLE_SAND_ACTIVE,
3168     EL_SP_PORT_LEFT,
3169     EL_SP_PORT_RIGHT,
3170     EL_SP_PORT_UP,
3171     EL_SP_PORT_DOWN,
3172     EL_SP_PORT_HORIZONTAL,
3173     EL_SP_PORT_VERTICAL,
3174     EL_SP_PORT_ANY,
3175     EL_SP_GRAVITY_PORT_LEFT,
3176     EL_SP_GRAVITY_PORT_RIGHT,
3177     EL_SP_GRAVITY_PORT_UP,
3178     EL_SP_GRAVITY_PORT_DOWN,
3179     EL_SP_GRAVITY_ON_PORT_LEFT,
3180     EL_SP_GRAVITY_ON_PORT_RIGHT,
3181     EL_SP_GRAVITY_ON_PORT_UP,
3182     EL_SP_GRAVITY_ON_PORT_DOWN,
3183     EL_SP_GRAVITY_OFF_PORT_LEFT,
3184     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3185     EL_SP_GRAVITY_OFF_PORT_UP,
3186     EL_SP_GRAVITY_OFF_PORT_DOWN,
3187     EL_EMC_GRASS,
3188
3189     -1
3190   };
3191
3192   static int ep_player[] =
3193   {
3194     EL_PLAYER_1,
3195     EL_PLAYER_2,
3196     EL_PLAYER_3,
3197     EL_PLAYER_4,
3198     EL_SP_MURPHY,
3199     EL_SOKOBAN_FIELD_PLAYER,
3200     EL_TRIGGER_PLAYER,
3201
3202     -1
3203   };
3204
3205   static int ep_can_pass_magic_wall[] =
3206   {
3207     EL_ROCK,
3208     EL_BD_ROCK,
3209     EL_EMERALD,
3210     EL_BD_DIAMOND,
3211     EL_EMERALD_YELLOW,
3212     EL_EMERALD_RED,
3213     EL_EMERALD_PURPLE,
3214     EL_DIAMOND,
3215
3216     -1
3217   };
3218
3219   static int ep_can_pass_dc_magic_wall[] =
3220   {
3221     EL_ROCK,
3222     EL_BD_ROCK,
3223     EL_EMERALD,
3224     EL_BD_DIAMOND,
3225     EL_EMERALD_YELLOW,
3226     EL_EMERALD_RED,
3227     EL_EMERALD_PURPLE,
3228     EL_DIAMOND,
3229     EL_PEARL,
3230     EL_CRYSTAL,
3231
3232     -1
3233   };
3234
3235   static int ep_switchable[] =
3236   {
3237     EL_ROBOT_WHEEL,
3238     EL_SP_TERMINAL,
3239     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3240     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3241     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3242     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3243     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3244     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3245     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3246     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3247     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3248     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3249     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3250     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3251     EL_SWITCHGATE_SWITCH_UP,
3252     EL_SWITCHGATE_SWITCH_DOWN,
3253     EL_DC_SWITCHGATE_SWITCH_UP,
3254     EL_DC_SWITCHGATE_SWITCH_DOWN,
3255     EL_LIGHT_SWITCH,
3256     EL_LIGHT_SWITCH_ACTIVE,
3257     EL_TIMEGATE_SWITCH,
3258     EL_DC_TIMEGATE_SWITCH,
3259     EL_BALLOON_SWITCH_LEFT,
3260     EL_BALLOON_SWITCH_RIGHT,
3261     EL_BALLOON_SWITCH_UP,
3262     EL_BALLOON_SWITCH_DOWN,
3263     EL_BALLOON_SWITCH_ANY,
3264     EL_BALLOON_SWITCH_NONE,
3265     EL_LAMP,
3266     EL_TIME_ORB_FULL,
3267     EL_EMC_MAGIC_BALL_SWITCH,
3268     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3269
3270     -1
3271   };
3272
3273   static int ep_bd_element[] =
3274   {
3275     EL_EMPTY,
3276     EL_SAND,
3277     EL_WALL_SLIPPERY,
3278     EL_BD_WALL,
3279     EL_ROCK,
3280     EL_BD_ROCK,
3281     EL_BD_DIAMOND,
3282     EL_BD_MAGIC_WALL,
3283     EL_EXIT_CLOSED,
3284     EL_EXIT_OPEN,
3285     EL_STEELWALL,
3286     EL_PLAYER_1,
3287     EL_PLAYER_2,
3288     EL_PLAYER_3,
3289     EL_PLAYER_4,
3290     EL_BD_FIREFLY,
3291     EL_BD_FIREFLY_1,
3292     EL_BD_FIREFLY_2,
3293     EL_BD_FIREFLY_3,
3294     EL_BD_FIREFLY_4,
3295     EL_BD_BUTTERFLY,
3296     EL_BD_BUTTERFLY_1,
3297     EL_BD_BUTTERFLY_2,
3298     EL_BD_BUTTERFLY_3,
3299     EL_BD_BUTTERFLY_4,
3300     EL_BD_AMOEBA,
3301     EL_CHAR_QUESTION,
3302     EL_UNKNOWN,
3303
3304     -1
3305   };
3306
3307   static int ep_sp_element[] =
3308   {
3309     /* should always be valid */
3310     EL_EMPTY,
3311
3312     /* standard classic Supaplex elements */
3313     EL_SP_EMPTY,
3314     EL_SP_ZONK,
3315     EL_SP_BASE,
3316     EL_SP_MURPHY,
3317     EL_SP_INFOTRON,
3318     EL_SP_CHIP_SINGLE,
3319     EL_SP_HARDWARE_GRAY,
3320     EL_SP_EXIT_CLOSED,
3321     EL_SP_EXIT_OPEN,
3322     EL_SP_DISK_ORANGE,
3323     EL_SP_PORT_RIGHT,
3324     EL_SP_PORT_DOWN,
3325     EL_SP_PORT_LEFT,
3326     EL_SP_PORT_UP,
3327     EL_SP_GRAVITY_PORT_RIGHT,
3328     EL_SP_GRAVITY_PORT_DOWN,
3329     EL_SP_GRAVITY_PORT_LEFT,
3330     EL_SP_GRAVITY_PORT_UP,
3331     EL_SP_SNIKSNAK,
3332     EL_SP_DISK_YELLOW,
3333     EL_SP_TERMINAL,
3334     EL_SP_DISK_RED,
3335     EL_SP_PORT_VERTICAL,
3336     EL_SP_PORT_HORIZONTAL,
3337     EL_SP_PORT_ANY,
3338     EL_SP_ELECTRON,
3339     EL_SP_BUGGY_BASE,
3340     EL_SP_CHIP_LEFT,
3341     EL_SP_CHIP_RIGHT,
3342     EL_SP_HARDWARE_BASE_1,
3343     EL_SP_HARDWARE_GREEN,
3344     EL_SP_HARDWARE_BLUE,
3345     EL_SP_HARDWARE_RED,
3346     EL_SP_HARDWARE_YELLOW,
3347     EL_SP_HARDWARE_BASE_2,
3348     EL_SP_HARDWARE_BASE_3,
3349     EL_SP_HARDWARE_BASE_4,
3350     EL_SP_HARDWARE_BASE_5,
3351     EL_SP_HARDWARE_BASE_6,
3352     EL_SP_CHIP_TOP,
3353     EL_SP_CHIP_BOTTOM,
3354
3355     /* additional elements that appeared in newer Supaplex levels */
3356     EL_INVISIBLE_WALL,
3357
3358     /* additional gravity port elements (not switching, but setting gravity) */
3359     EL_SP_GRAVITY_ON_PORT_LEFT,
3360     EL_SP_GRAVITY_ON_PORT_RIGHT,
3361     EL_SP_GRAVITY_ON_PORT_UP,
3362     EL_SP_GRAVITY_ON_PORT_DOWN,
3363     EL_SP_GRAVITY_OFF_PORT_LEFT,
3364     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3365     EL_SP_GRAVITY_OFF_PORT_UP,
3366     EL_SP_GRAVITY_OFF_PORT_DOWN,
3367
3368     /* more than one Murphy in a level results in an inactive clone */
3369     EL_SP_MURPHY_CLONE,
3370
3371     /* runtime Supaplex elements */
3372     EL_SP_DISK_RED_ACTIVE,
3373     EL_SP_TERMINAL_ACTIVE,
3374     EL_SP_BUGGY_BASE_ACTIVATING,
3375     EL_SP_BUGGY_BASE_ACTIVE,
3376     EL_SP_EXIT_OPENING,
3377     EL_SP_EXIT_CLOSING,
3378
3379     -1
3380   };
3381
3382   static int ep_sb_element[] =
3383   {
3384     EL_EMPTY,
3385     EL_STEELWALL,
3386     EL_SOKOBAN_OBJECT,
3387     EL_SOKOBAN_FIELD_EMPTY,
3388     EL_SOKOBAN_FIELD_FULL,
3389     EL_SOKOBAN_FIELD_PLAYER,
3390     EL_PLAYER_1,
3391     EL_PLAYER_2,
3392     EL_PLAYER_3,
3393     EL_PLAYER_4,
3394     EL_INVISIBLE_STEELWALL,
3395
3396     -1
3397   };
3398
3399   static int ep_gem[] =
3400   {
3401     EL_BD_DIAMOND,
3402     EL_EMERALD,
3403     EL_EMERALD_YELLOW,
3404     EL_EMERALD_RED,
3405     EL_EMERALD_PURPLE,
3406     EL_DIAMOND,
3407
3408     -1
3409   };
3410
3411   static int ep_food_dark_yamyam[] =
3412   {
3413     EL_SAND,
3414     EL_BUG,
3415     EL_SPACESHIP,
3416     EL_BD_BUTTERFLY,
3417     EL_BD_FIREFLY,
3418     EL_YAMYAM,
3419     EL_ROBOT,
3420     EL_PACMAN,
3421     EL_AMOEBA_DROP,
3422     EL_AMOEBA_DEAD,
3423     EL_AMOEBA_WET,
3424     EL_AMOEBA_DRY,
3425     EL_AMOEBA_FULL,
3426     EL_BD_AMOEBA,
3427     EL_EMERALD,
3428     EL_BD_DIAMOND,
3429     EL_EMERALD_YELLOW,
3430     EL_EMERALD_RED,
3431     EL_EMERALD_PURPLE,
3432     EL_DIAMOND,
3433     EL_PEARL,
3434     EL_CRYSTAL,
3435
3436     -1
3437   };
3438
3439   static int ep_food_penguin[] =
3440   {
3441     EL_EMERALD,
3442     EL_BD_DIAMOND,
3443     EL_EMERALD_YELLOW,
3444     EL_EMERALD_RED,
3445     EL_EMERALD_PURPLE,
3446     EL_DIAMOND,
3447     EL_PEARL,
3448     EL_CRYSTAL,
3449
3450     -1
3451   };
3452
3453   static int ep_food_pig[] =
3454   {
3455     EL_EMERALD,
3456     EL_BD_DIAMOND,
3457     EL_EMERALD_YELLOW,
3458     EL_EMERALD_RED,
3459     EL_EMERALD_PURPLE,
3460     EL_DIAMOND,
3461
3462     -1
3463   };
3464
3465   static int ep_historic_wall[] =
3466   {
3467     EL_STEELWALL,
3468     EL_GATE_1,
3469     EL_GATE_2,
3470     EL_GATE_3,
3471     EL_GATE_4,
3472     EL_GATE_1_GRAY,
3473     EL_GATE_2_GRAY,
3474     EL_GATE_3_GRAY,
3475     EL_GATE_4_GRAY,
3476     EL_GATE_1_GRAY_ACTIVE,
3477     EL_GATE_2_GRAY_ACTIVE,
3478     EL_GATE_3_GRAY_ACTIVE,
3479     EL_GATE_4_GRAY_ACTIVE,
3480     EL_EM_GATE_1,
3481     EL_EM_GATE_2,
3482     EL_EM_GATE_3,
3483     EL_EM_GATE_4,
3484     EL_EM_GATE_1_GRAY,
3485     EL_EM_GATE_2_GRAY,
3486     EL_EM_GATE_3_GRAY,
3487     EL_EM_GATE_4_GRAY,
3488     EL_EM_GATE_1_GRAY_ACTIVE,
3489     EL_EM_GATE_2_GRAY_ACTIVE,
3490     EL_EM_GATE_3_GRAY_ACTIVE,
3491     EL_EM_GATE_4_GRAY_ACTIVE,
3492     EL_EXIT_CLOSED,
3493     EL_EXIT_OPENING,
3494     EL_EXIT_OPEN,
3495     EL_WALL,
3496     EL_WALL_SLIPPERY,
3497     EL_EXPANDABLE_WALL,
3498     EL_EXPANDABLE_WALL_HORIZONTAL,
3499     EL_EXPANDABLE_WALL_VERTICAL,
3500     EL_EXPANDABLE_WALL_ANY,
3501     EL_EXPANDABLE_WALL_GROWING,
3502     EL_BD_EXPANDABLE_WALL,
3503     EL_BD_WALL,
3504     EL_SP_CHIP_SINGLE,
3505     EL_SP_CHIP_LEFT,
3506     EL_SP_CHIP_RIGHT,
3507     EL_SP_CHIP_TOP,
3508     EL_SP_CHIP_BOTTOM,
3509     EL_SP_HARDWARE_GRAY,
3510     EL_SP_HARDWARE_GREEN,
3511     EL_SP_HARDWARE_BLUE,
3512     EL_SP_HARDWARE_RED,
3513     EL_SP_HARDWARE_YELLOW,
3514     EL_SP_HARDWARE_BASE_1,
3515     EL_SP_HARDWARE_BASE_2,
3516     EL_SP_HARDWARE_BASE_3,
3517     EL_SP_HARDWARE_BASE_4,
3518     EL_SP_HARDWARE_BASE_5,
3519     EL_SP_HARDWARE_BASE_6,
3520     EL_SP_TERMINAL,
3521     EL_SP_TERMINAL_ACTIVE,
3522     EL_SP_EXIT_CLOSED,
3523     EL_SP_EXIT_OPEN,
3524     EL_INVISIBLE_STEELWALL,
3525     EL_INVISIBLE_STEELWALL_ACTIVE,
3526     EL_INVISIBLE_WALL,
3527     EL_INVISIBLE_WALL_ACTIVE,
3528     EL_STEELWALL_SLIPPERY,
3529     EL_EMC_STEELWALL_1,
3530     EL_EMC_STEELWALL_2,
3531     EL_EMC_STEELWALL_3,
3532     EL_EMC_STEELWALL_4,
3533     EL_EMC_WALL_1,
3534     EL_EMC_WALL_2,
3535     EL_EMC_WALL_3,
3536     EL_EMC_WALL_4,
3537     EL_EMC_WALL_5,
3538     EL_EMC_WALL_6,
3539     EL_EMC_WALL_7,
3540     EL_EMC_WALL_8,
3541
3542     -1
3543   };
3544
3545   static int ep_historic_solid[] =
3546   {
3547     EL_WALL,
3548     EL_EXPANDABLE_WALL,
3549     EL_EXPANDABLE_WALL_HORIZONTAL,
3550     EL_EXPANDABLE_WALL_VERTICAL,
3551     EL_EXPANDABLE_WALL_ANY,
3552     EL_BD_EXPANDABLE_WALL,
3553     EL_BD_WALL,
3554     EL_WALL_SLIPPERY,
3555     EL_EXIT_CLOSED,
3556     EL_EXIT_OPENING,
3557     EL_EXIT_OPEN,
3558     EL_AMOEBA_DEAD,
3559     EL_AMOEBA_WET,
3560     EL_AMOEBA_DRY,
3561     EL_AMOEBA_FULL,
3562     EL_BD_AMOEBA,
3563     EL_QUICKSAND_EMPTY,
3564     EL_QUICKSAND_FULL,
3565     EL_QUICKSAND_FILLING,
3566     EL_QUICKSAND_EMPTYING,
3567     EL_MAGIC_WALL,
3568     EL_MAGIC_WALL_ACTIVE,
3569     EL_MAGIC_WALL_EMPTYING,
3570     EL_MAGIC_WALL_FILLING,
3571     EL_MAGIC_WALL_FULL,
3572     EL_MAGIC_WALL_DEAD,
3573     EL_BD_MAGIC_WALL,
3574     EL_BD_MAGIC_WALL_ACTIVE,
3575     EL_BD_MAGIC_WALL_EMPTYING,
3576     EL_BD_MAGIC_WALL_FULL,
3577     EL_BD_MAGIC_WALL_FILLING,
3578     EL_BD_MAGIC_WALL_DEAD,
3579     EL_GAME_OF_LIFE,
3580     EL_BIOMAZE,
3581     EL_SP_CHIP_SINGLE,
3582     EL_SP_CHIP_LEFT,
3583     EL_SP_CHIP_RIGHT,
3584     EL_SP_CHIP_TOP,
3585     EL_SP_CHIP_BOTTOM,
3586     EL_SP_TERMINAL,
3587     EL_SP_TERMINAL_ACTIVE,
3588     EL_SP_EXIT_CLOSED,
3589     EL_SP_EXIT_OPEN,
3590     EL_INVISIBLE_WALL,
3591     EL_INVISIBLE_WALL_ACTIVE,
3592     EL_SWITCHGATE_SWITCH_UP,
3593     EL_SWITCHGATE_SWITCH_DOWN,
3594     EL_DC_SWITCHGATE_SWITCH_UP,
3595     EL_DC_SWITCHGATE_SWITCH_DOWN,
3596     EL_TIMEGATE_SWITCH,
3597     EL_TIMEGATE_SWITCH_ACTIVE,
3598     EL_DC_TIMEGATE_SWITCH,
3599     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3600     EL_EMC_WALL_1,
3601     EL_EMC_WALL_2,
3602     EL_EMC_WALL_3,
3603     EL_EMC_WALL_4,
3604     EL_EMC_WALL_5,
3605     EL_EMC_WALL_6,
3606     EL_EMC_WALL_7,
3607     EL_EMC_WALL_8,
3608     EL_WALL_PEARL,
3609     EL_WALL_CRYSTAL,
3610
3611     /* the following elements are a direct copy of "indestructible" elements,
3612        except "EL_ACID", which is "indestructible", but not "solid"! */
3613 #if 0
3614     EL_ACID,
3615 #endif
3616     EL_STEELWALL,
3617     EL_ACID_POOL_TOPLEFT,
3618     EL_ACID_POOL_TOPRIGHT,
3619     EL_ACID_POOL_BOTTOMLEFT,
3620     EL_ACID_POOL_BOTTOM,
3621     EL_ACID_POOL_BOTTOMRIGHT,
3622     EL_SP_HARDWARE_GRAY,
3623     EL_SP_HARDWARE_GREEN,
3624     EL_SP_HARDWARE_BLUE,
3625     EL_SP_HARDWARE_RED,
3626     EL_SP_HARDWARE_YELLOW,
3627     EL_SP_HARDWARE_BASE_1,
3628     EL_SP_HARDWARE_BASE_2,
3629     EL_SP_HARDWARE_BASE_3,
3630     EL_SP_HARDWARE_BASE_4,
3631     EL_SP_HARDWARE_BASE_5,
3632     EL_SP_HARDWARE_BASE_6,
3633     EL_INVISIBLE_STEELWALL,
3634     EL_INVISIBLE_STEELWALL_ACTIVE,
3635     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3636     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3637     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3638     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3639     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3640     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3641     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3642     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3643     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3644     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3645     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3646     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3647     EL_LIGHT_SWITCH,
3648     EL_LIGHT_SWITCH_ACTIVE,
3649     EL_SIGN_EXCLAMATION,
3650     EL_SIGN_RADIOACTIVITY,
3651     EL_SIGN_STOP,
3652     EL_SIGN_WHEELCHAIR,
3653     EL_SIGN_PARKING,
3654     EL_SIGN_NO_ENTRY,
3655     EL_SIGN_UNUSED_1,
3656     EL_SIGN_GIVE_WAY,
3657     EL_SIGN_ENTRY_FORBIDDEN,
3658     EL_SIGN_EMERGENCY_EXIT,
3659     EL_SIGN_YIN_YANG,
3660     EL_SIGN_UNUSED_2,
3661     EL_SIGN_SPERMS,
3662     EL_SIGN_BULLET,
3663     EL_SIGN_HEART,
3664     EL_SIGN_CROSS,
3665     EL_SIGN_FRANKIE,
3666     EL_STEEL_EXIT_CLOSED,
3667     EL_STEEL_EXIT_OPEN,
3668     EL_DC_STEELWALL_1_LEFT,
3669     EL_DC_STEELWALL_1_RIGHT,
3670     EL_DC_STEELWALL_1_TOP,
3671     EL_DC_STEELWALL_1_BOTTOM,
3672     EL_DC_STEELWALL_1_HORIZONTAL,
3673     EL_DC_STEELWALL_1_VERTICAL,
3674     EL_DC_STEELWALL_1_TOPLEFT,
3675     EL_DC_STEELWALL_1_TOPRIGHT,
3676     EL_DC_STEELWALL_1_BOTTOMLEFT,
3677     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3678     EL_DC_STEELWALL_1_TOPLEFT_2,
3679     EL_DC_STEELWALL_1_TOPRIGHT_2,
3680     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3681     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3682     EL_DC_STEELWALL_2_LEFT,
3683     EL_DC_STEELWALL_2_RIGHT,
3684     EL_DC_STEELWALL_2_TOP,
3685     EL_DC_STEELWALL_2_BOTTOM,
3686     EL_DC_STEELWALL_2_HORIZONTAL,
3687     EL_DC_STEELWALL_2_VERTICAL,
3688     EL_DC_STEELWALL_2_MIDDLE,
3689     EL_DC_STEELWALL_2_SINGLE,
3690     EL_STEELWALL_SLIPPERY,
3691     EL_EMC_STEELWALL_1,
3692     EL_EMC_STEELWALL_2,
3693     EL_EMC_STEELWALL_3,
3694     EL_EMC_STEELWALL_4,
3695     EL_CRYSTAL,
3696     EL_GATE_1,
3697     EL_GATE_2,
3698     EL_GATE_3,
3699     EL_GATE_4,
3700     EL_GATE_1_GRAY,
3701     EL_GATE_2_GRAY,
3702     EL_GATE_3_GRAY,
3703     EL_GATE_4_GRAY,
3704     EL_GATE_1_GRAY_ACTIVE,
3705     EL_GATE_2_GRAY_ACTIVE,
3706     EL_GATE_3_GRAY_ACTIVE,
3707     EL_GATE_4_GRAY_ACTIVE,
3708     EL_EM_GATE_1,
3709     EL_EM_GATE_2,
3710     EL_EM_GATE_3,
3711     EL_EM_GATE_4,
3712     EL_EM_GATE_1_GRAY,
3713     EL_EM_GATE_2_GRAY,
3714     EL_EM_GATE_3_GRAY,
3715     EL_EM_GATE_4_GRAY,
3716     EL_EM_GATE_1_GRAY_ACTIVE,
3717     EL_EM_GATE_2_GRAY_ACTIVE,
3718     EL_EM_GATE_3_GRAY_ACTIVE,
3719     EL_EM_GATE_4_GRAY_ACTIVE,
3720     EL_SWITCHGATE_OPEN,
3721     EL_SWITCHGATE_OPENING,
3722     EL_SWITCHGATE_CLOSED,
3723     EL_SWITCHGATE_CLOSING,
3724     EL_TIMEGATE_OPEN,
3725     EL_TIMEGATE_OPENING,
3726     EL_TIMEGATE_CLOSED,
3727     EL_TIMEGATE_CLOSING,
3728     EL_TUBE_ANY,
3729     EL_TUBE_VERTICAL,
3730     EL_TUBE_HORIZONTAL,
3731     EL_TUBE_VERTICAL_LEFT,
3732     EL_TUBE_VERTICAL_RIGHT,
3733     EL_TUBE_HORIZONTAL_UP,
3734     EL_TUBE_HORIZONTAL_DOWN,
3735     EL_TUBE_LEFT_UP,
3736     EL_TUBE_LEFT_DOWN,
3737     EL_TUBE_RIGHT_UP,
3738     EL_TUBE_RIGHT_DOWN,
3739
3740     -1
3741   };
3742
3743   static int ep_classic_enemy[] =
3744   {
3745     EL_BUG,
3746     EL_SPACESHIP,
3747     EL_BD_BUTTERFLY,
3748     EL_BD_FIREFLY,
3749
3750     EL_YAMYAM,
3751     EL_DARK_YAMYAM,
3752     EL_ROBOT,
3753     EL_PACMAN,
3754     EL_SP_SNIKSNAK,
3755     EL_SP_ELECTRON,
3756
3757     -1
3758   };
3759
3760   static int ep_belt[] =
3761   {
3762     EL_CONVEYOR_BELT_1_LEFT,
3763     EL_CONVEYOR_BELT_1_MIDDLE,
3764     EL_CONVEYOR_BELT_1_RIGHT,
3765     EL_CONVEYOR_BELT_2_LEFT,
3766     EL_CONVEYOR_BELT_2_MIDDLE,
3767     EL_CONVEYOR_BELT_2_RIGHT,
3768     EL_CONVEYOR_BELT_3_LEFT,
3769     EL_CONVEYOR_BELT_3_MIDDLE,
3770     EL_CONVEYOR_BELT_3_RIGHT,
3771     EL_CONVEYOR_BELT_4_LEFT,
3772     EL_CONVEYOR_BELT_4_MIDDLE,
3773     EL_CONVEYOR_BELT_4_RIGHT,
3774
3775     -1
3776   };
3777
3778   static int ep_belt_active[] =
3779   {
3780     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3781     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3782     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3783     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3784     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3785     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3786     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3787     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3788     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3789     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3790     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3791     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3792
3793     -1
3794   };
3795
3796   static int ep_belt_switch[] =
3797   {
3798     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3799     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3800     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3801     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3802     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3803     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3804     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3805     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3806     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3807     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3808     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3809     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3810
3811     -1
3812   };
3813
3814   static int ep_tube[] =
3815   {
3816     EL_TUBE_LEFT_UP,
3817     EL_TUBE_LEFT_DOWN,
3818     EL_TUBE_RIGHT_UP,
3819     EL_TUBE_RIGHT_DOWN,
3820     EL_TUBE_HORIZONTAL,
3821     EL_TUBE_HORIZONTAL_UP,
3822     EL_TUBE_HORIZONTAL_DOWN,
3823     EL_TUBE_VERTICAL,
3824     EL_TUBE_VERTICAL_LEFT,
3825     EL_TUBE_VERTICAL_RIGHT,
3826     EL_TUBE_ANY,
3827
3828     -1
3829   };
3830
3831   static int ep_acid_pool[] =
3832   {
3833     EL_ACID_POOL_TOPLEFT,
3834     EL_ACID_POOL_TOPRIGHT,
3835     EL_ACID_POOL_BOTTOMLEFT,
3836     EL_ACID_POOL_BOTTOM,
3837     EL_ACID_POOL_BOTTOMRIGHT,
3838
3839     -1
3840   };
3841
3842   static int ep_keygate[] =
3843   {
3844     EL_GATE_1,
3845     EL_GATE_2,
3846     EL_GATE_3,
3847     EL_GATE_4,
3848     EL_GATE_1_GRAY,
3849     EL_GATE_2_GRAY,
3850     EL_GATE_3_GRAY,
3851     EL_GATE_4_GRAY,
3852     EL_GATE_1_GRAY_ACTIVE,
3853     EL_GATE_2_GRAY_ACTIVE,
3854     EL_GATE_3_GRAY_ACTIVE,
3855     EL_GATE_4_GRAY_ACTIVE,
3856     EL_EM_GATE_1,
3857     EL_EM_GATE_2,
3858     EL_EM_GATE_3,
3859     EL_EM_GATE_4,
3860     EL_EM_GATE_1_GRAY,
3861     EL_EM_GATE_2_GRAY,
3862     EL_EM_GATE_3_GRAY,
3863     EL_EM_GATE_4_GRAY,
3864     EL_EM_GATE_1_GRAY_ACTIVE,
3865     EL_EM_GATE_2_GRAY_ACTIVE,
3866     EL_EM_GATE_3_GRAY_ACTIVE,
3867     EL_EM_GATE_4_GRAY_ACTIVE,
3868     EL_EMC_GATE_5,
3869     EL_EMC_GATE_6,
3870     EL_EMC_GATE_7,
3871     EL_EMC_GATE_8,
3872     EL_EMC_GATE_5_GRAY,
3873     EL_EMC_GATE_6_GRAY,
3874     EL_EMC_GATE_7_GRAY,
3875     EL_EMC_GATE_8_GRAY,
3876     EL_EMC_GATE_5_GRAY_ACTIVE,
3877     EL_EMC_GATE_6_GRAY_ACTIVE,
3878     EL_EMC_GATE_7_GRAY_ACTIVE,
3879     EL_EMC_GATE_8_GRAY_ACTIVE,
3880     EL_DC_GATE_WHITE,
3881     EL_DC_GATE_WHITE_GRAY,
3882     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3883
3884     -1
3885   };
3886
3887   static int ep_amoeboid[] =
3888   {
3889     EL_AMOEBA_DEAD,
3890     EL_AMOEBA_WET,
3891     EL_AMOEBA_DRY,
3892     EL_AMOEBA_FULL,
3893     EL_BD_AMOEBA,
3894     EL_EMC_DRIPPER,
3895
3896     -1
3897   };
3898
3899   static int ep_amoebalive[] =
3900   {
3901     EL_AMOEBA_WET,
3902     EL_AMOEBA_DRY,
3903     EL_AMOEBA_FULL,
3904     EL_BD_AMOEBA,
3905     EL_EMC_DRIPPER,
3906
3907     -1
3908   };
3909
3910   static int ep_has_editor_content[] =
3911   {
3912     EL_PLAYER_1,
3913     EL_PLAYER_2,
3914     EL_PLAYER_3,
3915     EL_PLAYER_4,
3916     EL_SOKOBAN_FIELD_PLAYER,
3917     EL_SP_MURPHY,
3918     EL_YAMYAM,
3919     EL_YAMYAM_LEFT,
3920     EL_YAMYAM_RIGHT,
3921     EL_YAMYAM_UP,
3922     EL_YAMYAM_DOWN,
3923     EL_AMOEBA_WET,
3924     EL_AMOEBA_DRY,
3925     EL_AMOEBA_FULL,
3926     EL_BD_AMOEBA,
3927     EL_EMC_MAGIC_BALL,
3928     EL_EMC_ANDROID,
3929
3930     -1
3931   };
3932
3933   static int ep_can_turn_each_move[] =
3934   {
3935     /* !!! do something with this one !!! */
3936     -1
3937   };
3938
3939   static int ep_can_grow[] =
3940   {
3941     EL_BD_AMOEBA,
3942     EL_AMOEBA_DROP,
3943     EL_AMOEBA_WET,
3944     EL_AMOEBA_DRY,
3945     EL_AMOEBA_FULL,
3946     EL_GAME_OF_LIFE,
3947     EL_BIOMAZE,
3948     EL_EMC_DRIPPER,
3949
3950     -1
3951   };
3952
3953   static int ep_active_bomb[] =
3954   {
3955     EL_DYNAMITE_ACTIVE,
3956     EL_EM_DYNAMITE_ACTIVE,
3957     EL_DYNABOMB_PLAYER_1_ACTIVE,
3958     EL_DYNABOMB_PLAYER_2_ACTIVE,
3959     EL_DYNABOMB_PLAYER_3_ACTIVE,
3960     EL_DYNABOMB_PLAYER_4_ACTIVE,
3961     EL_SP_DISK_RED_ACTIVE,
3962
3963     -1
3964   };
3965
3966   static int ep_inactive[] =
3967   {
3968     EL_EMPTY,
3969     EL_SAND,
3970     EL_WALL,
3971     EL_BD_WALL,
3972     EL_WALL_SLIPPERY,
3973     EL_STEELWALL,
3974     EL_AMOEBA_DEAD,
3975     EL_QUICKSAND_EMPTY,
3976     EL_QUICKSAND_FAST_EMPTY,
3977     EL_STONEBLOCK,
3978     EL_ROBOT_WHEEL,
3979     EL_KEY_1,
3980     EL_KEY_2,
3981     EL_KEY_3,
3982     EL_KEY_4,
3983     EL_EM_KEY_1,
3984     EL_EM_KEY_2,
3985     EL_EM_KEY_3,
3986     EL_EM_KEY_4,
3987     EL_EMC_KEY_5,
3988     EL_EMC_KEY_6,
3989     EL_EMC_KEY_7,
3990     EL_EMC_KEY_8,
3991     EL_GATE_1,
3992     EL_GATE_2,
3993     EL_GATE_3,
3994     EL_GATE_4,
3995     EL_GATE_1_GRAY,