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