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