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