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