fixed custom graphics for dragon flames not being correctly scaled up/down
[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 "cartoons.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   InitToons();
2125   print_timestamp_time("InitToons");
2126   InitDoors();
2127   print_timestamp_time("InitDoors");
2128
2129   print_timestamp_done("ReinitializeGraphics");
2130 }
2131
2132 static void ReinitializeSounds()
2133 {
2134   InitSoundInfo();              /* sound properties mapping */
2135   InitElementSoundInfo();       /* element game sound mapping */
2136   InitGameModeSoundInfo();      /* game mode sound mapping */
2137   InitGlobalAnimSoundInfo();    /* global animation sound settings */
2138
2139   InitPlayLevelSound();         /* internal game sound settings */
2140 }
2141
2142 static void ReinitializeMusic()
2143 {
2144   InitMusicInfo();              /* music properties mapping */
2145   InitGameModeMusicInfo();      /* game mode music mapping */
2146 }
2147
2148 static int get_special_property_bit(int element, int property_bit_nr)
2149 {
2150   struct PropertyBitInfo
2151   {
2152     int element;
2153     int bit_nr;
2154   };
2155
2156   static struct PropertyBitInfo pb_can_move_into_acid[] =
2157   {
2158     /* the player may be able fall into acid when gravity is activated */
2159     { EL_PLAYER_1,              0       },
2160     { EL_PLAYER_2,              0       },
2161     { EL_PLAYER_3,              0       },
2162     { EL_PLAYER_4,              0       },
2163     { EL_SP_MURPHY,             0       },
2164     { EL_SOKOBAN_FIELD_PLAYER,  0       },
2165
2166     /* all elements that can move may be able to also move into acid */
2167     { EL_BUG,                   1       },
2168     { EL_BUG_LEFT,              1       },
2169     { EL_BUG_RIGHT,             1       },
2170     { EL_BUG_UP,                1       },
2171     { EL_BUG_DOWN,              1       },
2172     { EL_SPACESHIP,             2       },
2173     { EL_SPACESHIP_LEFT,        2       },
2174     { EL_SPACESHIP_RIGHT,       2       },
2175     { EL_SPACESHIP_UP,          2       },
2176     { EL_SPACESHIP_DOWN,        2       },
2177     { EL_BD_BUTTERFLY,          3       },
2178     { EL_BD_BUTTERFLY_LEFT,     3       },
2179     { EL_BD_BUTTERFLY_RIGHT,    3       },
2180     { EL_BD_BUTTERFLY_UP,       3       },
2181     { EL_BD_BUTTERFLY_DOWN,     3       },
2182     { EL_BD_FIREFLY,            4       },
2183     { EL_BD_FIREFLY_LEFT,       4       },
2184     { EL_BD_FIREFLY_RIGHT,      4       },
2185     { EL_BD_FIREFLY_UP,         4       },
2186     { EL_BD_FIREFLY_DOWN,       4       },
2187     { EL_YAMYAM,                5       },
2188     { EL_YAMYAM_LEFT,           5       },
2189     { EL_YAMYAM_RIGHT,          5       },
2190     { EL_YAMYAM_UP,             5       },
2191     { EL_YAMYAM_DOWN,           5       },
2192     { EL_DARK_YAMYAM,           6       },
2193     { EL_ROBOT,                 7       },
2194     { EL_PACMAN,                8       },
2195     { EL_PACMAN_LEFT,           8       },
2196     { EL_PACMAN_RIGHT,          8       },
2197     { EL_PACMAN_UP,             8       },
2198     { EL_PACMAN_DOWN,           8       },
2199     { EL_MOLE,                  9       },
2200     { EL_MOLE_LEFT,             9       },
2201     { EL_MOLE_RIGHT,            9       },
2202     { EL_MOLE_UP,               9       },
2203     { EL_MOLE_DOWN,             9       },
2204     { EL_PENGUIN,               10      },
2205     { EL_PIG,                   11      },
2206     { EL_DRAGON,                12      },
2207     { EL_SATELLITE,             13      },
2208     { EL_SP_SNIKSNAK,           14      },
2209     { EL_SP_ELECTRON,           15      },
2210     { EL_BALLOON,               16      },
2211     { EL_SPRING,                17      },
2212     { EL_EMC_ANDROID,           18      },
2213
2214     { -1,                       -1      },
2215   };
2216
2217   static struct PropertyBitInfo pb_dont_collide_with[] =
2218   {
2219     { EL_SP_SNIKSNAK,           0       },
2220     { EL_SP_ELECTRON,           1       },
2221
2222     { -1,                       -1      },
2223   };
2224
2225   static struct
2226   {
2227     int bit_nr;
2228     struct PropertyBitInfo *pb_info;
2229   } pb_definition[] =
2230   {
2231     { EP_CAN_MOVE_INTO_ACID,    pb_can_move_into_acid   },
2232     { EP_DONT_COLLIDE_WITH,     pb_dont_collide_with    },
2233
2234     { -1,                       NULL                    },
2235   };
2236
2237   struct PropertyBitInfo *pb_info = NULL;
2238   int i;
2239
2240   for (i = 0; pb_definition[i].bit_nr != -1; i++)
2241     if (pb_definition[i].bit_nr == property_bit_nr)
2242       pb_info = pb_definition[i].pb_info;
2243
2244   if (pb_info == NULL)
2245     return -1;
2246
2247   for (i = 0; pb_info[i].element != -1; i++)
2248     if (pb_info[i].element == element)
2249       return pb_info[i].bit_nr;
2250
2251   return -1;
2252 }
2253
2254 void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
2255                          boolean property_value)
2256 {
2257   int bit_nr = get_special_property_bit(element, property_bit_nr);
2258
2259   if (bit_nr > -1)
2260   {
2261     if (property_value)
2262       *bitfield |=  (1 << bit_nr);
2263     else
2264       *bitfield &= ~(1 << bit_nr);
2265   }
2266 }
2267
2268 boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
2269 {
2270   int bit_nr = get_special_property_bit(element, property_bit_nr);
2271
2272   if (bit_nr > -1)
2273     return ((*bitfield & (1 << bit_nr)) != 0);
2274
2275   return FALSE;
2276 }
2277
2278 static void ResolveGroupElementExt(int group_element, int recursion_depth)
2279 {
2280   static int group_nr;
2281   static struct ElementGroupInfo *group;
2282   struct ElementGroupInfo *actual_group = element_info[group_element].group;
2283   int i;
2284
2285   if (actual_group == NULL)                     /* not yet initialized */
2286     return;
2287
2288   if (recursion_depth > NUM_GROUP_ELEMENTS)     /* recursion too deep */
2289   {
2290     Error(ERR_WARN, "recursion too deep when resolving group element %d",
2291           group_element - EL_GROUP_START + 1);
2292
2293     /* replace element which caused too deep recursion by question mark */
2294     group->element_resolved[group->num_elements_resolved++] = EL_UNKNOWN;
2295
2296     return;
2297   }
2298
2299   if (recursion_depth == 0)                     /* initialization */
2300   {
2301     group = actual_group;
2302     group_nr = GROUP_NR(group_element);
2303
2304     group->num_elements_resolved = 0;
2305     group->choice_pos = 0;
2306
2307     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
2308       element_info[i].in_group[group_nr] = FALSE;
2309   }
2310
2311   for (i = 0; i < actual_group->num_elements; i++)
2312   {
2313     int element = actual_group->element[i];
2314
2315     if (group->num_elements_resolved == NUM_FILE_ELEMENTS)
2316       break;
2317
2318     if (IS_GROUP_ELEMENT(element))
2319       ResolveGroupElementExt(element, recursion_depth + 1);
2320     else
2321     {
2322       group->element_resolved[group->num_elements_resolved++] = element;
2323       element_info[element].in_group[group_nr] = TRUE;
2324     }
2325   }
2326 }
2327
2328 void ResolveGroupElement(int group_element)
2329 {
2330   ResolveGroupElementExt(group_element, 0);
2331 }
2332
2333 void InitElementPropertiesStatic()
2334 {
2335   static boolean clipboard_elements_initialized = FALSE;
2336
2337   static int ep_diggable[] =
2338   {
2339     EL_SAND,
2340     EL_SP_BASE,
2341     EL_SP_BUGGY_BASE,
2342     EL_SP_BUGGY_BASE_ACTIVATING,
2343     EL_TRAP,
2344     EL_INVISIBLE_SAND,
2345     EL_INVISIBLE_SAND_ACTIVE,
2346     EL_EMC_GRASS,
2347
2348     /* !!! currently not diggable, but handled by 'ep_dont_run_into' !!! */
2349     /* (if amoeba can grow into anything diggable, maybe keep these out) */
2350 #if 0
2351     EL_LANDMINE,
2352     EL_DC_LANDMINE,
2353     EL_TRAP_ACTIVE,
2354     EL_SP_BUGGY_BASE_ACTIVE,
2355     EL_EMC_PLANT,
2356 #endif
2357
2358     -1
2359   };
2360
2361   static int ep_collectible_only[] =
2362   {
2363     EL_BD_DIAMOND,
2364     EL_EMERALD,
2365     EL_DIAMOND,
2366     EL_EMERALD_YELLOW,
2367     EL_EMERALD_RED,
2368     EL_EMERALD_PURPLE,
2369     EL_KEY_1,
2370     EL_KEY_2,
2371     EL_KEY_3,
2372     EL_KEY_4,
2373     EL_EM_KEY_1,
2374     EL_EM_KEY_2,
2375     EL_EM_KEY_3,
2376     EL_EM_KEY_4,
2377     EL_EMC_KEY_5,
2378     EL_EMC_KEY_6,
2379     EL_EMC_KEY_7,
2380     EL_EMC_KEY_8,
2381     EL_DYNAMITE,
2382     EL_EM_DYNAMITE,
2383     EL_DYNABOMB_INCREASE_NUMBER,
2384     EL_DYNABOMB_INCREASE_SIZE,
2385     EL_DYNABOMB_INCREASE_POWER,
2386     EL_SP_INFOTRON,
2387     EL_SP_DISK_RED,
2388     EL_PEARL,
2389     EL_CRYSTAL,
2390     EL_DC_KEY_WHITE,
2391     EL_SHIELD_NORMAL,
2392     EL_SHIELD_DEADLY,
2393     EL_EXTRA_TIME,
2394     EL_ENVELOPE_1,
2395     EL_ENVELOPE_2,
2396     EL_ENVELOPE_3,
2397     EL_ENVELOPE_4,
2398     EL_SPEED_PILL,
2399     EL_EMC_LENSES,
2400     EL_EMC_MAGNIFIER,
2401
2402 #if 0
2403     /* !!! handle separately !!! */
2404     EL_DC_LANDMINE,     /* deadly when running into, but can be snapped */
2405 #endif
2406
2407     -1
2408   };
2409
2410   static int ep_dont_run_into[] =
2411   {
2412     /* same elements as in 'ep_dont_touch' */
2413     EL_BUG,
2414     EL_SPACESHIP,
2415     EL_BD_BUTTERFLY,
2416     EL_BD_FIREFLY,
2417
2418     /* same elements as in 'ep_dont_collide_with' */
2419     EL_YAMYAM,
2420     EL_DARK_YAMYAM,
2421     EL_ROBOT,
2422     EL_PACMAN,
2423     EL_SP_SNIKSNAK,
2424     EL_SP_ELECTRON,
2425
2426     /* new elements */
2427     EL_AMOEBA_DROP,
2428     EL_ACID,
2429
2430     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
2431 #if 1
2432     EL_LANDMINE,
2433     EL_DC_LANDMINE,
2434     EL_TRAP_ACTIVE,
2435     EL_SP_BUGGY_BASE_ACTIVE,
2436     EL_EMC_PLANT,
2437 #endif
2438
2439     -1
2440   };
2441
2442   static int ep_dont_collide_with[] =
2443   {
2444     /* same elements as in 'ep_dont_touch' */
2445     EL_BUG,
2446     EL_SPACESHIP,
2447     EL_BD_BUTTERFLY,
2448     EL_BD_FIREFLY,
2449
2450     /* new elements */
2451     EL_YAMYAM,
2452     EL_DARK_YAMYAM,
2453     EL_ROBOT,
2454     EL_PACMAN,
2455     EL_SP_SNIKSNAK,
2456     EL_SP_ELECTRON,
2457
2458     -1
2459   };
2460
2461   static int ep_dont_touch[] =
2462   {
2463     EL_BUG,
2464     EL_SPACESHIP,
2465     EL_BD_BUTTERFLY,
2466     EL_BD_FIREFLY,
2467
2468     -1
2469   };
2470
2471   static int ep_indestructible[] =
2472   {
2473     EL_STEELWALL,
2474     EL_ACID,
2475     EL_ACID_POOL_TOPLEFT,
2476     EL_ACID_POOL_TOPRIGHT,
2477     EL_ACID_POOL_BOTTOMLEFT,
2478     EL_ACID_POOL_BOTTOM,
2479     EL_ACID_POOL_BOTTOMRIGHT,
2480     EL_SP_HARDWARE_GRAY,
2481     EL_SP_HARDWARE_GREEN,
2482     EL_SP_HARDWARE_BLUE,
2483     EL_SP_HARDWARE_RED,
2484     EL_SP_HARDWARE_YELLOW,
2485     EL_SP_HARDWARE_BASE_1,
2486     EL_SP_HARDWARE_BASE_2,
2487     EL_SP_HARDWARE_BASE_3,
2488     EL_SP_HARDWARE_BASE_4,
2489     EL_SP_HARDWARE_BASE_5,
2490     EL_SP_HARDWARE_BASE_6,
2491     EL_INVISIBLE_STEELWALL,
2492     EL_INVISIBLE_STEELWALL_ACTIVE,
2493     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
2494     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
2495     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
2496     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
2497     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
2498     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
2499     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
2500     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
2501     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
2502     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
2503     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
2504     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
2505     EL_LIGHT_SWITCH,
2506     EL_LIGHT_SWITCH_ACTIVE,
2507     EL_SIGN_EXCLAMATION,
2508     EL_SIGN_RADIOACTIVITY,
2509     EL_SIGN_STOP,
2510     EL_SIGN_WHEELCHAIR,
2511     EL_SIGN_PARKING,
2512     EL_SIGN_NO_ENTRY,
2513     EL_SIGN_UNUSED_1,
2514     EL_SIGN_GIVE_WAY,
2515     EL_SIGN_ENTRY_FORBIDDEN,
2516     EL_SIGN_EMERGENCY_EXIT,
2517     EL_SIGN_YIN_YANG,
2518     EL_SIGN_UNUSED_2,
2519     EL_SIGN_SPERMS,
2520     EL_SIGN_BULLET,
2521     EL_SIGN_HEART,
2522     EL_SIGN_CROSS,
2523     EL_SIGN_FRANKIE,
2524     EL_STEEL_EXIT_CLOSED,
2525     EL_STEEL_EXIT_OPEN,
2526     EL_STEEL_EXIT_OPENING,
2527     EL_STEEL_EXIT_CLOSING,
2528     EL_EM_STEEL_EXIT_CLOSED,
2529     EL_EM_STEEL_EXIT_OPEN,
2530     EL_EM_STEEL_EXIT_OPENING,
2531     EL_EM_STEEL_EXIT_CLOSING,
2532     EL_DC_STEELWALL_1_LEFT,
2533     EL_DC_STEELWALL_1_RIGHT,
2534     EL_DC_STEELWALL_1_TOP,
2535     EL_DC_STEELWALL_1_BOTTOM,
2536     EL_DC_STEELWALL_1_HORIZONTAL,
2537     EL_DC_STEELWALL_1_VERTICAL,
2538     EL_DC_STEELWALL_1_TOPLEFT,
2539     EL_DC_STEELWALL_1_TOPRIGHT,
2540     EL_DC_STEELWALL_1_BOTTOMLEFT,
2541     EL_DC_STEELWALL_1_BOTTOMRIGHT,
2542     EL_DC_STEELWALL_1_TOPLEFT_2,
2543     EL_DC_STEELWALL_1_TOPRIGHT_2,
2544     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
2545     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
2546     EL_DC_STEELWALL_2_LEFT,
2547     EL_DC_STEELWALL_2_RIGHT,
2548     EL_DC_STEELWALL_2_TOP,
2549     EL_DC_STEELWALL_2_BOTTOM,
2550     EL_DC_STEELWALL_2_HORIZONTAL,
2551     EL_DC_STEELWALL_2_VERTICAL,
2552     EL_DC_STEELWALL_2_MIDDLE,
2553     EL_DC_STEELWALL_2_SINGLE,
2554     EL_STEELWALL_SLIPPERY,
2555     EL_EMC_STEELWALL_1,
2556     EL_EMC_STEELWALL_2,
2557     EL_EMC_STEELWALL_3,
2558     EL_EMC_STEELWALL_4,
2559     EL_CRYSTAL,
2560     EL_GATE_1,
2561     EL_GATE_2,
2562     EL_GATE_3,
2563     EL_GATE_4,
2564     EL_GATE_1_GRAY,
2565     EL_GATE_2_GRAY,
2566     EL_GATE_3_GRAY,
2567     EL_GATE_4_GRAY,
2568     EL_GATE_1_GRAY_ACTIVE,
2569     EL_GATE_2_GRAY_ACTIVE,
2570     EL_GATE_3_GRAY_ACTIVE,
2571     EL_GATE_4_GRAY_ACTIVE,
2572     EL_EM_GATE_1,
2573     EL_EM_GATE_2,
2574     EL_EM_GATE_3,
2575     EL_EM_GATE_4,
2576     EL_EM_GATE_1_GRAY,
2577     EL_EM_GATE_2_GRAY,
2578     EL_EM_GATE_3_GRAY,
2579     EL_EM_GATE_4_GRAY,
2580     EL_EM_GATE_1_GRAY_ACTIVE,
2581     EL_EM_GATE_2_GRAY_ACTIVE,
2582     EL_EM_GATE_3_GRAY_ACTIVE,
2583     EL_EM_GATE_4_GRAY_ACTIVE,
2584     EL_EMC_GATE_5,
2585     EL_EMC_GATE_6,
2586     EL_EMC_GATE_7,
2587     EL_EMC_GATE_8,
2588     EL_EMC_GATE_5_GRAY,
2589     EL_EMC_GATE_6_GRAY,
2590     EL_EMC_GATE_7_GRAY,
2591     EL_EMC_GATE_8_GRAY,
2592     EL_EMC_GATE_5_GRAY_ACTIVE,
2593     EL_EMC_GATE_6_GRAY_ACTIVE,
2594     EL_EMC_GATE_7_GRAY_ACTIVE,
2595     EL_EMC_GATE_8_GRAY_ACTIVE,
2596     EL_DC_GATE_WHITE,
2597     EL_DC_GATE_WHITE_GRAY,
2598     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2599     EL_DC_GATE_FAKE_GRAY,
2600     EL_SWITCHGATE_OPEN,
2601     EL_SWITCHGATE_OPENING,
2602     EL_SWITCHGATE_CLOSED,
2603     EL_SWITCHGATE_CLOSING,
2604     EL_DC_SWITCHGATE_SWITCH_UP,
2605     EL_DC_SWITCHGATE_SWITCH_DOWN,
2606     EL_TIMEGATE_OPEN,
2607     EL_TIMEGATE_OPENING,
2608     EL_TIMEGATE_CLOSED,
2609     EL_TIMEGATE_CLOSING,
2610     EL_DC_TIMEGATE_SWITCH,
2611     EL_DC_TIMEGATE_SWITCH_ACTIVE,
2612     EL_TUBE_ANY,
2613     EL_TUBE_VERTICAL,
2614     EL_TUBE_HORIZONTAL,
2615     EL_TUBE_VERTICAL_LEFT,
2616     EL_TUBE_VERTICAL_RIGHT,
2617     EL_TUBE_HORIZONTAL_UP,
2618     EL_TUBE_HORIZONTAL_DOWN,
2619     EL_TUBE_LEFT_UP,
2620     EL_TUBE_LEFT_DOWN,
2621     EL_TUBE_RIGHT_UP,
2622     EL_TUBE_RIGHT_DOWN,
2623     EL_EXPANDABLE_STEELWALL_HORIZONTAL,
2624     EL_EXPANDABLE_STEELWALL_VERTICAL,
2625     EL_EXPANDABLE_STEELWALL_ANY,
2626
2627     -1
2628   };
2629
2630   static int ep_slippery[] =
2631   {
2632     EL_WALL_SLIPPERY,
2633     EL_BD_WALL,
2634     EL_ROCK,
2635     EL_BD_ROCK,
2636     EL_EMERALD,
2637     EL_BD_DIAMOND,
2638     EL_EMERALD_YELLOW,
2639     EL_EMERALD_RED,
2640     EL_EMERALD_PURPLE,
2641     EL_DIAMOND,
2642     EL_BOMB,
2643     EL_NUT,
2644     EL_ROBOT_WHEEL_ACTIVE,
2645     EL_ROBOT_WHEEL,
2646     EL_TIME_ORB_FULL,
2647     EL_TIME_ORB_EMPTY,
2648     EL_LAMP_ACTIVE,
2649     EL_LAMP,
2650     EL_ACID_POOL_TOPLEFT,
2651     EL_ACID_POOL_TOPRIGHT,
2652     EL_SATELLITE,
2653     EL_SP_ZONK,
2654     EL_SP_INFOTRON,
2655     EL_SP_CHIP_SINGLE,
2656     EL_SP_CHIP_LEFT,
2657     EL_SP_CHIP_RIGHT,
2658     EL_SP_CHIP_TOP,
2659     EL_SP_CHIP_BOTTOM,
2660     EL_SPEED_PILL,
2661     EL_STEELWALL_SLIPPERY,
2662     EL_PEARL,
2663     EL_CRYSTAL,
2664     EL_EMC_WALL_SLIPPERY_1,
2665     EL_EMC_WALL_SLIPPERY_2,
2666     EL_EMC_WALL_SLIPPERY_3,
2667     EL_EMC_WALL_SLIPPERY_4,
2668     EL_EMC_MAGIC_BALL,
2669     EL_EMC_MAGIC_BALL_ACTIVE,
2670
2671     -1
2672   };
2673
2674   static int ep_can_change[] =
2675   {
2676     -1
2677   };
2678
2679   static int ep_can_move[] =
2680   {
2681     /* same elements as in 'pb_can_move_into_acid' */
2682     EL_BUG,
2683     EL_SPACESHIP,
2684     EL_BD_BUTTERFLY,
2685     EL_BD_FIREFLY,
2686     EL_YAMYAM,
2687     EL_DARK_YAMYAM,
2688     EL_ROBOT,
2689     EL_PACMAN,
2690     EL_MOLE,
2691     EL_PENGUIN,
2692     EL_PIG,
2693     EL_DRAGON,
2694     EL_SATELLITE,
2695     EL_SP_SNIKSNAK,
2696     EL_SP_ELECTRON,
2697     EL_BALLOON,
2698     EL_SPRING,
2699     EL_EMC_ANDROID,
2700
2701     -1
2702   };
2703
2704   static int ep_can_fall[] =
2705   {
2706     EL_ROCK,
2707     EL_BD_ROCK,
2708     EL_EMERALD,
2709     EL_BD_DIAMOND,
2710     EL_EMERALD_YELLOW,
2711     EL_EMERALD_RED,
2712     EL_EMERALD_PURPLE,
2713     EL_DIAMOND,
2714     EL_BOMB,
2715     EL_NUT,
2716     EL_AMOEBA_DROP,
2717     EL_QUICKSAND_FULL,
2718     EL_QUICKSAND_FAST_FULL,
2719     EL_MAGIC_WALL_FULL,
2720     EL_BD_MAGIC_WALL_FULL,
2721     EL_DC_MAGIC_WALL_FULL,
2722     EL_TIME_ORB_FULL,
2723     EL_TIME_ORB_EMPTY,
2724     EL_SP_ZONK,
2725     EL_SP_INFOTRON,
2726     EL_SP_DISK_ORANGE,
2727     EL_PEARL,
2728     EL_CRYSTAL,
2729     EL_SPRING,
2730     EL_DX_SUPABOMB,
2731
2732     -1
2733   };
2734
2735   static int ep_can_smash_player[] =
2736   {
2737     EL_ROCK,
2738     EL_BD_ROCK,
2739     EL_EMERALD,
2740     EL_BD_DIAMOND,
2741     EL_EMERALD_YELLOW,
2742     EL_EMERALD_RED,
2743     EL_EMERALD_PURPLE,
2744     EL_DIAMOND,
2745     EL_BOMB,
2746     EL_NUT,
2747     EL_AMOEBA_DROP,
2748     EL_TIME_ORB_FULL,
2749     EL_TIME_ORB_EMPTY,
2750     EL_SP_ZONK,
2751     EL_SP_INFOTRON,
2752     EL_SP_DISK_ORANGE,
2753     EL_PEARL,
2754     EL_CRYSTAL,
2755     EL_SPRING,
2756     EL_DX_SUPABOMB,
2757
2758     -1
2759   };
2760
2761   static int ep_can_smash_enemies[] =
2762   {
2763     EL_ROCK,
2764     EL_BD_ROCK,
2765     EL_SP_ZONK,
2766
2767     -1
2768   };
2769
2770   static int ep_can_smash_everything[] =
2771   {
2772     EL_ROCK,
2773     EL_BD_ROCK,
2774     EL_SP_ZONK,
2775
2776     -1
2777   };
2778
2779   static int ep_explodes_by_fire[] =
2780   {
2781     /* same elements as in 'ep_explodes_impact' */
2782     EL_BOMB,
2783     EL_SP_DISK_ORANGE,
2784     EL_DX_SUPABOMB,
2785
2786     /* same elements as in 'ep_explodes_smashed' */
2787     EL_SATELLITE,
2788     EL_PIG,
2789     EL_DRAGON,
2790     EL_MOLE,
2791
2792     /* new elements */
2793     EL_DYNAMITE,
2794     EL_DYNAMITE_ACTIVE,
2795     EL_EM_DYNAMITE,
2796     EL_EM_DYNAMITE_ACTIVE,
2797     EL_DYNABOMB_PLAYER_1_ACTIVE,
2798     EL_DYNABOMB_PLAYER_2_ACTIVE,
2799     EL_DYNABOMB_PLAYER_3_ACTIVE,
2800     EL_DYNABOMB_PLAYER_4_ACTIVE,
2801     EL_DYNABOMB_INCREASE_NUMBER,
2802     EL_DYNABOMB_INCREASE_SIZE,
2803     EL_DYNABOMB_INCREASE_POWER,
2804     EL_SP_DISK_RED_ACTIVE,
2805     EL_BUG,
2806     EL_PENGUIN,
2807     EL_SP_DISK_RED,
2808     EL_SP_DISK_YELLOW,
2809     EL_SP_SNIKSNAK,
2810     EL_SP_ELECTRON,
2811 #if 0
2812     EL_BLACK_ORB,
2813 #endif
2814
2815     -1
2816   };
2817
2818   static int ep_explodes_smashed[] =
2819   {
2820     /* same elements as in 'ep_explodes_impact' */
2821     EL_BOMB,
2822     EL_SP_DISK_ORANGE,
2823     EL_DX_SUPABOMB,
2824
2825     /* new elements */
2826     EL_SATELLITE,
2827     EL_PIG,
2828     EL_DRAGON,
2829     EL_MOLE,
2830
2831     -1
2832   };
2833
2834   static int ep_explodes_impact[] =
2835   {
2836     EL_BOMB,
2837     EL_SP_DISK_ORANGE,
2838     EL_DX_SUPABOMB,
2839
2840     -1
2841   };
2842
2843   static int ep_walkable_over[] =
2844   {
2845     EL_EMPTY_SPACE,
2846     EL_SP_EMPTY_SPACE,
2847     EL_SOKOBAN_FIELD_EMPTY,
2848     EL_EXIT_OPEN,
2849     EL_EM_EXIT_OPEN,
2850     EL_EM_EXIT_OPENING,
2851     EL_SP_EXIT_OPEN,
2852     EL_SP_EXIT_OPENING,
2853     EL_STEEL_EXIT_OPEN,
2854     EL_EM_STEEL_EXIT_OPEN,
2855     EL_EM_STEEL_EXIT_OPENING,
2856     EL_GATE_1,
2857     EL_GATE_2,
2858     EL_GATE_3,
2859     EL_GATE_4,
2860     EL_GATE_1_GRAY,
2861     EL_GATE_2_GRAY,
2862     EL_GATE_3_GRAY,
2863     EL_GATE_4_GRAY,
2864     EL_GATE_1_GRAY_ACTIVE,
2865     EL_GATE_2_GRAY_ACTIVE,
2866     EL_GATE_3_GRAY_ACTIVE,
2867     EL_GATE_4_GRAY_ACTIVE,
2868     EL_PENGUIN,
2869     EL_PIG,
2870     EL_DRAGON,
2871
2872     -1
2873   };
2874
2875   static int ep_walkable_inside[] =
2876   {
2877     EL_TUBE_ANY,
2878     EL_TUBE_VERTICAL,
2879     EL_TUBE_HORIZONTAL,
2880     EL_TUBE_VERTICAL_LEFT,
2881     EL_TUBE_VERTICAL_RIGHT,
2882     EL_TUBE_HORIZONTAL_UP,
2883     EL_TUBE_HORIZONTAL_DOWN,
2884     EL_TUBE_LEFT_UP,
2885     EL_TUBE_LEFT_DOWN,
2886     EL_TUBE_RIGHT_UP,
2887     EL_TUBE_RIGHT_DOWN,
2888
2889     -1
2890   };
2891
2892   static int ep_walkable_under[] =
2893   {
2894     -1
2895   };
2896
2897   static int ep_passable_over[] =
2898   {
2899     EL_EM_GATE_1,
2900     EL_EM_GATE_2,
2901     EL_EM_GATE_3,
2902     EL_EM_GATE_4,
2903     EL_EM_GATE_1_GRAY,
2904     EL_EM_GATE_2_GRAY,
2905     EL_EM_GATE_3_GRAY,
2906     EL_EM_GATE_4_GRAY,
2907     EL_EM_GATE_1_GRAY_ACTIVE,
2908     EL_EM_GATE_2_GRAY_ACTIVE,
2909     EL_EM_GATE_3_GRAY_ACTIVE,
2910     EL_EM_GATE_4_GRAY_ACTIVE,
2911     EL_EMC_GATE_5,
2912     EL_EMC_GATE_6,
2913     EL_EMC_GATE_7,
2914     EL_EMC_GATE_8,
2915     EL_EMC_GATE_5_GRAY,
2916     EL_EMC_GATE_6_GRAY,
2917     EL_EMC_GATE_7_GRAY,
2918     EL_EMC_GATE_8_GRAY,
2919     EL_EMC_GATE_5_GRAY_ACTIVE,
2920     EL_EMC_GATE_6_GRAY_ACTIVE,
2921     EL_EMC_GATE_7_GRAY_ACTIVE,
2922     EL_EMC_GATE_8_GRAY_ACTIVE,
2923     EL_DC_GATE_WHITE,
2924     EL_DC_GATE_WHITE_GRAY,
2925     EL_DC_GATE_WHITE_GRAY_ACTIVE,
2926     EL_SWITCHGATE_OPEN,
2927     EL_TIMEGATE_OPEN,
2928
2929     -1
2930   };
2931
2932   static int ep_passable_inside[] =
2933   {
2934     EL_SP_PORT_LEFT,
2935     EL_SP_PORT_RIGHT,
2936     EL_SP_PORT_UP,
2937     EL_SP_PORT_DOWN,
2938     EL_SP_PORT_HORIZONTAL,
2939     EL_SP_PORT_VERTICAL,
2940     EL_SP_PORT_ANY,
2941     EL_SP_GRAVITY_PORT_LEFT,
2942     EL_SP_GRAVITY_PORT_RIGHT,
2943     EL_SP_GRAVITY_PORT_UP,
2944     EL_SP_GRAVITY_PORT_DOWN,
2945     EL_SP_GRAVITY_ON_PORT_LEFT,
2946     EL_SP_GRAVITY_ON_PORT_RIGHT,
2947     EL_SP_GRAVITY_ON_PORT_UP,
2948     EL_SP_GRAVITY_ON_PORT_DOWN,
2949     EL_SP_GRAVITY_OFF_PORT_LEFT,
2950     EL_SP_GRAVITY_OFF_PORT_RIGHT,
2951     EL_SP_GRAVITY_OFF_PORT_UP,
2952     EL_SP_GRAVITY_OFF_PORT_DOWN,
2953
2954     -1
2955   };
2956
2957   static int ep_passable_under[] =
2958   {
2959     -1
2960   };
2961
2962   static int ep_droppable[] =
2963   {
2964     -1
2965   };
2966
2967   static int ep_explodes_1x1_old[] =
2968   {
2969     -1
2970   };
2971
2972   static int ep_pushable[] =
2973   {
2974     EL_ROCK,
2975     EL_BOMB,
2976     EL_DX_SUPABOMB,
2977     EL_NUT,
2978     EL_TIME_ORB_EMPTY,
2979     EL_SP_ZONK,
2980     EL_SP_DISK_ORANGE,
2981     EL_SPRING,
2982     EL_BD_ROCK,
2983     EL_SOKOBAN_OBJECT,
2984     EL_SOKOBAN_FIELD_FULL,
2985     EL_SATELLITE,
2986     EL_SP_DISK_YELLOW,
2987     EL_BALLOON,
2988     EL_EMC_ANDROID,
2989
2990     -1
2991   };
2992
2993   static int ep_explodes_cross_old[] =
2994   {
2995     -1
2996   };
2997
2998   static int ep_protected[] =
2999   {
3000     /* same elements as in 'ep_walkable_inside' */
3001     EL_TUBE_ANY,
3002     EL_TUBE_VERTICAL,
3003     EL_TUBE_HORIZONTAL,
3004     EL_TUBE_VERTICAL_LEFT,
3005     EL_TUBE_VERTICAL_RIGHT,
3006     EL_TUBE_HORIZONTAL_UP,
3007     EL_TUBE_HORIZONTAL_DOWN,
3008     EL_TUBE_LEFT_UP,
3009     EL_TUBE_LEFT_DOWN,
3010     EL_TUBE_RIGHT_UP,
3011     EL_TUBE_RIGHT_DOWN,
3012
3013     /* same elements as in 'ep_passable_over' */
3014     EL_EM_GATE_1,
3015     EL_EM_GATE_2,
3016     EL_EM_GATE_3,
3017     EL_EM_GATE_4,
3018     EL_EM_GATE_1_GRAY,
3019     EL_EM_GATE_2_GRAY,
3020     EL_EM_GATE_3_GRAY,
3021     EL_EM_GATE_4_GRAY,
3022     EL_EM_GATE_1_GRAY_ACTIVE,
3023     EL_EM_GATE_2_GRAY_ACTIVE,
3024     EL_EM_GATE_3_GRAY_ACTIVE,
3025     EL_EM_GATE_4_GRAY_ACTIVE,
3026     EL_EMC_GATE_5,
3027     EL_EMC_GATE_6,
3028     EL_EMC_GATE_7,
3029     EL_EMC_GATE_8,
3030     EL_EMC_GATE_5_GRAY,
3031     EL_EMC_GATE_6_GRAY,
3032     EL_EMC_GATE_7_GRAY,
3033     EL_EMC_GATE_8_GRAY,
3034     EL_EMC_GATE_5_GRAY_ACTIVE,
3035     EL_EMC_GATE_6_GRAY_ACTIVE,
3036     EL_EMC_GATE_7_GRAY_ACTIVE,
3037     EL_EMC_GATE_8_GRAY_ACTIVE,
3038     EL_DC_GATE_WHITE,
3039     EL_DC_GATE_WHITE_GRAY,
3040     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3041     EL_SWITCHGATE_OPEN,
3042     EL_TIMEGATE_OPEN,
3043
3044     /* same elements as in 'ep_passable_inside' */
3045     EL_SP_PORT_LEFT,
3046     EL_SP_PORT_RIGHT,
3047     EL_SP_PORT_UP,
3048     EL_SP_PORT_DOWN,
3049     EL_SP_PORT_HORIZONTAL,
3050     EL_SP_PORT_VERTICAL,
3051     EL_SP_PORT_ANY,
3052     EL_SP_GRAVITY_PORT_LEFT,
3053     EL_SP_GRAVITY_PORT_RIGHT,
3054     EL_SP_GRAVITY_PORT_UP,
3055     EL_SP_GRAVITY_PORT_DOWN,
3056     EL_SP_GRAVITY_ON_PORT_LEFT,
3057     EL_SP_GRAVITY_ON_PORT_RIGHT,
3058     EL_SP_GRAVITY_ON_PORT_UP,
3059     EL_SP_GRAVITY_ON_PORT_DOWN,
3060     EL_SP_GRAVITY_OFF_PORT_LEFT,
3061     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3062     EL_SP_GRAVITY_OFF_PORT_UP,
3063     EL_SP_GRAVITY_OFF_PORT_DOWN,
3064
3065     -1
3066   };
3067
3068   static int ep_throwable[] =
3069   {
3070     -1
3071   };
3072
3073   static int ep_can_explode[] =
3074   {
3075     /* same elements as in 'ep_explodes_impact' */
3076     EL_BOMB,
3077     EL_SP_DISK_ORANGE,
3078     EL_DX_SUPABOMB,
3079
3080     /* same elements as in 'ep_explodes_smashed' */
3081     EL_SATELLITE,
3082     EL_PIG,
3083     EL_DRAGON,
3084     EL_MOLE,
3085
3086     /* elements that can explode by explosion or by dragonfire */
3087     EL_DYNAMITE,
3088     EL_DYNAMITE_ACTIVE,
3089     EL_EM_DYNAMITE,
3090     EL_EM_DYNAMITE_ACTIVE,
3091     EL_DYNABOMB_PLAYER_1_ACTIVE,
3092     EL_DYNABOMB_PLAYER_2_ACTIVE,
3093     EL_DYNABOMB_PLAYER_3_ACTIVE,
3094     EL_DYNABOMB_PLAYER_4_ACTIVE,
3095     EL_DYNABOMB_INCREASE_NUMBER,
3096     EL_DYNABOMB_INCREASE_SIZE,
3097     EL_DYNABOMB_INCREASE_POWER,
3098     EL_SP_DISK_RED_ACTIVE,
3099     EL_BUG,
3100     EL_PENGUIN,
3101     EL_SP_DISK_RED,
3102     EL_SP_DISK_YELLOW,
3103     EL_SP_SNIKSNAK,
3104     EL_SP_ELECTRON,
3105
3106     /* elements that can explode only by explosion */
3107     EL_BLACK_ORB,
3108
3109     -1
3110   };
3111
3112   static int ep_gravity_reachable[] =
3113   {
3114     EL_SAND,
3115     EL_SP_BASE,
3116     EL_TRAP,
3117     EL_INVISIBLE_SAND,
3118     EL_INVISIBLE_SAND_ACTIVE,
3119     EL_SP_PORT_LEFT,
3120     EL_SP_PORT_RIGHT,
3121     EL_SP_PORT_UP,
3122     EL_SP_PORT_DOWN,
3123     EL_SP_PORT_HORIZONTAL,
3124     EL_SP_PORT_VERTICAL,
3125     EL_SP_PORT_ANY,
3126     EL_SP_GRAVITY_PORT_LEFT,
3127     EL_SP_GRAVITY_PORT_RIGHT,
3128     EL_SP_GRAVITY_PORT_UP,
3129     EL_SP_GRAVITY_PORT_DOWN,
3130     EL_SP_GRAVITY_ON_PORT_LEFT,
3131     EL_SP_GRAVITY_ON_PORT_RIGHT,
3132     EL_SP_GRAVITY_ON_PORT_UP,
3133     EL_SP_GRAVITY_ON_PORT_DOWN,
3134     EL_SP_GRAVITY_OFF_PORT_LEFT,
3135     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3136     EL_SP_GRAVITY_OFF_PORT_UP,
3137     EL_SP_GRAVITY_OFF_PORT_DOWN,
3138     EL_EMC_GRASS,
3139
3140     -1
3141   };
3142
3143   static int ep_player[] =
3144   {
3145     EL_PLAYER_1,
3146     EL_PLAYER_2,
3147     EL_PLAYER_3,
3148     EL_PLAYER_4,
3149     EL_SP_MURPHY,
3150     EL_SOKOBAN_FIELD_PLAYER,
3151     EL_TRIGGER_PLAYER,
3152
3153     -1
3154   };
3155
3156   static int ep_can_pass_magic_wall[] =
3157   {
3158     EL_ROCK,
3159     EL_BD_ROCK,
3160     EL_EMERALD,
3161     EL_BD_DIAMOND,
3162     EL_EMERALD_YELLOW,
3163     EL_EMERALD_RED,
3164     EL_EMERALD_PURPLE,
3165     EL_DIAMOND,
3166
3167     -1
3168   };
3169
3170   static int ep_can_pass_dc_magic_wall[] =
3171   {
3172     EL_ROCK,
3173     EL_BD_ROCK,
3174     EL_EMERALD,
3175     EL_BD_DIAMOND,
3176     EL_EMERALD_YELLOW,
3177     EL_EMERALD_RED,
3178     EL_EMERALD_PURPLE,
3179     EL_DIAMOND,
3180     EL_PEARL,
3181     EL_CRYSTAL,
3182
3183     -1
3184   };
3185
3186   static int ep_switchable[] =
3187   {
3188     EL_ROBOT_WHEEL,
3189     EL_SP_TERMINAL,
3190     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3191     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3192     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3193     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3194     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3195     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3196     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3197     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3198     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3199     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3200     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3201     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3202     EL_SWITCHGATE_SWITCH_UP,
3203     EL_SWITCHGATE_SWITCH_DOWN,
3204     EL_DC_SWITCHGATE_SWITCH_UP,
3205     EL_DC_SWITCHGATE_SWITCH_DOWN,
3206     EL_LIGHT_SWITCH,
3207     EL_LIGHT_SWITCH_ACTIVE,
3208     EL_TIMEGATE_SWITCH,
3209     EL_DC_TIMEGATE_SWITCH,
3210     EL_BALLOON_SWITCH_LEFT,
3211     EL_BALLOON_SWITCH_RIGHT,
3212     EL_BALLOON_SWITCH_UP,
3213     EL_BALLOON_SWITCH_DOWN,
3214     EL_BALLOON_SWITCH_ANY,
3215     EL_BALLOON_SWITCH_NONE,
3216     EL_LAMP,
3217     EL_TIME_ORB_FULL,
3218     EL_EMC_MAGIC_BALL_SWITCH,
3219     EL_EMC_MAGIC_BALL_SWITCH_ACTIVE,
3220
3221     -1
3222   };
3223
3224   static int ep_bd_element[] =
3225   {
3226     EL_EMPTY,
3227     EL_SAND,
3228     EL_WALL_SLIPPERY,
3229     EL_BD_WALL,
3230     EL_ROCK,
3231     EL_BD_ROCK,
3232     EL_BD_DIAMOND,
3233     EL_BD_MAGIC_WALL,
3234     EL_EXIT_CLOSED,
3235     EL_EXIT_OPEN,
3236     EL_STEELWALL,
3237     EL_PLAYER_1,
3238     EL_PLAYER_2,
3239     EL_PLAYER_3,
3240     EL_PLAYER_4,
3241     EL_BD_FIREFLY,
3242     EL_BD_FIREFLY_1,
3243     EL_BD_FIREFLY_2,
3244     EL_BD_FIREFLY_3,
3245     EL_BD_FIREFLY_4,
3246     EL_BD_BUTTERFLY,
3247     EL_BD_BUTTERFLY_1,
3248     EL_BD_BUTTERFLY_2,
3249     EL_BD_BUTTERFLY_3,
3250     EL_BD_BUTTERFLY_4,
3251     EL_BD_AMOEBA,
3252     EL_CHAR_QUESTION,
3253     EL_UNKNOWN,
3254
3255     -1
3256   };
3257
3258   static int ep_sp_element[] =
3259   {
3260     /* should always be valid */
3261     EL_EMPTY,
3262
3263     /* standard classic Supaplex elements */
3264     EL_SP_EMPTY,
3265     EL_SP_ZONK,
3266     EL_SP_BASE,
3267     EL_SP_MURPHY,
3268     EL_SP_INFOTRON,
3269     EL_SP_CHIP_SINGLE,
3270     EL_SP_HARDWARE_GRAY,
3271     EL_SP_EXIT_CLOSED,
3272     EL_SP_EXIT_OPEN,
3273     EL_SP_DISK_ORANGE,
3274     EL_SP_PORT_RIGHT,
3275     EL_SP_PORT_DOWN,
3276     EL_SP_PORT_LEFT,
3277     EL_SP_PORT_UP,
3278     EL_SP_GRAVITY_PORT_RIGHT,
3279     EL_SP_GRAVITY_PORT_DOWN,
3280     EL_SP_GRAVITY_PORT_LEFT,
3281     EL_SP_GRAVITY_PORT_UP,
3282     EL_SP_SNIKSNAK,
3283     EL_SP_DISK_YELLOW,
3284     EL_SP_TERMINAL,
3285     EL_SP_DISK_RED,
3286     EL_SP_PORT_VERTICAL,
3287     EL_SP_PORT_HORIZONTAL,
3288     EL_SP_PORT_ANY,
3289     EL_SP_ELECTRON,
3290     EL_SP_BUGGY_BASE,
3291     EL_SP_CHIP_LEFT,
3292     EL_SP_CHIP_RIGHT,
3293     EL_SP_HARDWARE_BASE_1,
3294     EL_SP_HARDWARE_GREEN,
3295     EL_SP_HARDWARE_BLUE,
3296     EL_SP_HARDWARE_RED,
3297     EL_SP_HARDWARE_YELLOW,
3298     EL_SP_HARDWARE_BASE_2,
3299     EL_SP_HARDWARE_BASE_3,
3300     EL_SP_HARDWARE_BASE_4,
3301     EL_SP_HARDWARE_BASE_5,
3302     EL_SP_HARDWARE_BASE_6,
3303     EL_SP_CHIP_TOP,
3304     EL_SP_CHIP_BOTTOM,
3305
3306     /* additional elements that appeared in newer Supaplex levels */
3307     EL_INVISIBLE_WALL,
3308
3309     /* additional gravity port elements (not switching, but setting gravity) */
3310     EL_SP_GRAVITY_ON_PORT_LEFT,
3311     EL_SP_GRAVITY_ON_PORT_RIGHT,
3312     EL_SP_GRAVITY_ON_PORT_UP,
3313     EL_SP_GRAVITY_ON_PORT_DOWN,
3314     EL_SP_GRAVITY_OFF_PORT_LEFT,
3315     EL_SP_GRAVITY_OFF_PORT_RIGHT,
3316     EL_SP_GRAVITY_OFF_PORT_UP,
3317     EL_SP_GRAVITY_OFF_PORT_DOWN,
3318
3319     /* more than one Murphy in a level results in an inactive clone */
3320     EL_SP_MURPHY_CLONE,
3321
3322     /* runtime Supaplex elements */
3323     EL_SP_DISK_RED_ACTIVE,
3324     EL_SP_TERMINAL_ACTIVE,
3325     EL_SP_BUGGY_BASE_ACTIVATING,
3326     EL_SP_BUGGY_BASE_ACTIVE,
3327     EL_SP_EXIT_OPENING,
3328     EL_SP_EXIT_CLOSING,
3329
3330     -1
3331   };
3332
3333   static int ep_sb_element[] =
3334   {
3335     EL_EMPTY,
3336     EL_STEELWALL,
3337     EL_SOKOBAN_OBJECT,
3338     EL_SOKOBAN_FIELD_EMPTY,
3339     EL_SOKOBAN_FIELD_FULL,
3340     EL_SOKOBAN_FIELD_PLAYER,
3341     EL_PLAYER_1,
3342     EL_PLAYER_2,
3343     EL_PLAYER_3,
3344     EL_PLAYER_4,
3345     EL_INVISIBLE_STEELWALL,
3346
3347     -1
3348   };
3349
3350   static int ep_gem[] =
3351   {
3352     EL_BD_DIAMOND,
3353     EL_EMERALD,
3354     EL_EMERALD_YELLOW,
3355     EL_EMERALD_RED,
3356     EL_EMERALD_PURPLE,
3357     EL_DIAMOND,
3358
3359     -1
3360   };
3361
3362   static int ep_food_dark_yamyam[] =
3363   {
3364     EL_SAND,
3365     EL_BUG,
3366     EL_SPACESHIP,
3367     EL_BD_BUTTERFLY,
3368     EL_BD_FIREFLY,
3369     EL_YAMYAM,
3370     EL_ROBOT,
3371     EL_PACMAN,
3372     EL_AMOEBA_DROP,
3373     EL_AMOEBA_DEAD,
3374     EL_AMOEBA_WET,
3375     EL_AMOEBA_DRY,
3376     EL_AMOEBA_FULL,
3377     EL_BD_AMOEBA,
3378     EL_EMERALD,
3379     EL_BD_DIAMOND,
3380     EL_EMERALD_YELLOW,
3381     EL_EMERALD_RED,
3382     EL_EMERALD_PURPLE,
3383     EL_DIAMOND,
3384     EL_PEARL,
3385     EL_CRYSTAL,
3386
3387     -1
3388   };
3389
3390   static int ep_food_penguin[] =
3391   {
3392     EL_EMERALD,
3393     EL_BD_DIAMOND,
3394     EL_EMERALD_YELLOW,
3395     EL_EMERALD_RED,
3396     EL_EMERALD_PURPLE,
3397     EL_DIAMOND,
3398     EL_PEARL,
3399     EL_CRYSTAL,
3400
3401     -1
3402   };
3403
3404   static int ep_food_pig[] =
3405   {
3406     EL_EMERALD,
3407     EL_BD_DIAMOND,
3408     EL_EMERALD_YELLOW,
3409     EL_EMERALD_RED,
3410     EL_EMERALD_PURPLE,
3411     EL_DIAMOND,
3412
3413     -1
3414   };
3415
3416   static int ep_historic_wall[] =
3417   {
3418     EL_STEELWALL,
3419     EL_GATE_1,
3420     EL_GATE_2,
3421     EL_GATE_3,
3422     EL_GATE_4,
3423     EL_GATE_1_GRAY,
3424     EL_GATE_2_GRAY,
3425     EL_GATE_3_GRAY,
3426     EL_GATE_4_GRAY,
3427     EL_GATE_1_GRAY_ACTIVE,
3428     EL_GATE_2_GRAY_ACTIVE,
3429     EL_GATE_3_GRAY_ACTIVE,
3430     EL_GATE_4_GRAY_ACTIVE,
3431     EL_EM_GATE_1,
3432     EL_EM_GATE_2,
3433     EL_EM_GATE_3,
3434     EL_EM_GATE_4,
3435     EL_EM_GATE_1_GRAY,
3436     EL_EM_GATE_2_GRAY,
3437     EL_EM_GATE_3_GRAY,
3438     EL_EM_GATE_4_GRAY,
3439     EL_EM_GATE_1_GRAY_ACTIVE,
3440     EL_EM_GATE_2_GRAY_ACTIVE,
3441     EL_EM_GATE_3_GRAY_ACTIVE,
3442     EL_EM_GATE_4_GRAY_ACTIVE,
3443     EL_EXIT_CLOSED,
3444     EL_EXIT_OPENING,
3445     EL_EXIT_OPEN,
3446     EL_WALL,
3447     EL_WALL_SLIPPERY,
3448     EL_EXPANDABLE_WALL,
3449     EL_EXPANDABLE_WALL_HORIZONTAL,
3450     EL_EXPANDABLE_WALL_VERTICAL,
3451     EL_EXPANDABLE_WALL_ANY,
3452     EL_EXPANDABLE_WALL_GROWING,
3453     EL_BD_EXPANDABLE_WALL,
3454     EL_BD_WALL,
3455     EL_SP_CHIP_SINGLE,
3456     EL_SP_CHIP_LEFT,
3457     EL_SP_CHIP_RIGHT,
3458     EL_SP_CHIP_TOP,
3459     EL_SP_CHIP_BOTTOM,
3460     EL_SP_HARDWARE_GRAY,
3461     EL_SP_HARDWARE_GREEN,
3462     EL_SP_HARDWARE_BLUE,
3463     EL_SP_HARDWARE_RED,
3464     EL_SP_HARDWARE_YELLOW,
3465     EL_SP_HARDWARE_BASE_1,
3466     EL_SP_HARDWARE_BASE_2,
3467     EL_SP_HARDWARE_BASE_3,
3468     EL_SP_HARDWARE_BASE_4,
3469     EL_SP_HARDWARE_BASE_5,
3470     EL_SP_HARDWARE_BASE_6,
3471     EL_SP_TERMINAL,
3472     EL_SP_TERMINAL_ACTIVE,
3473     EL_SP_EXIT_CLOSED,
3474     EL_SP_EXIT_OPEN,
3475     EL_INVISIBLE_STEELWALL,
3476     EL_INVISIBLE_STEELWALL_ACTIVE,
3477     EL_INVISIBLE_WALL,
3478     EL_INVISIBLE_WALL_ACTIVE,
3479     EL_STEELWALL_SLIPPERY,
3480     EL_EMC_STEELWALL_1,
3481     EL_EMC_STEELWALL_2,
3482     EL_EMC_STEELWALL_3,
3483     EL_EMC_STEELWALL_4,
3484     EL_EMC_WALL_1,
3485     EL_EMC_WALL_2,
3486     EL_EMC_WALL_3,
3487     EL_EMC_WALL_4,
3488     EL_EMC_WALL_5,
3489     EL_EMC_WALL_6,
3490     EL_EMC_WALL_7,
3491     EL_EMC_WALL_8,
3492
3493     -1
3494   };
3495
3496   static int ep_historic_solid[] =
3497   {
3498     EL_WALL,
3499     EL_EXPANDABLE_WALL,
3500     EL_EXPANDABLE_WALL_HORIZONTAL,
3501     EL_EXPANDABLE_WALL_VERTICAL,
3502     EL_EXPANDABLE_WALL_ANY,
3503     EL_BD_EXPANDABLE_WALL,
3504     EL_BD_WALL,
3505     EL_WALL_SLIPPERY,
3506     EL_EXIT_CLOSED,
3507     EL_EXIT_OPENING,
3508     EL_EXIT_OPEN,
3509     EL_AMOEBA_DEAD,
3510     EL_AMOEBA_WET,
3511     EL_AMOEBA_DRY,
3512     EL_AMOEBA_FULL,
3513     EL_BD_AMOEBA,
3514     EL_QUICKSAND_EMPTY,
3515     EL_QUICKSAND_FULL,
3516     EL_QUICKSAND_FILLING,
3517     EL_QUICKSAND_EMPTYING,
3518     EL_MAGIC_WALL,
3519     EL_MAGIC_WALL_ACTIVE,
3520     EL_MAGIC_WALL_EMPTYING,
3521     EL_MAGIC_WALL_FILLING,
3522     EL_MAGIC_WALL_FULL,
3523     EL_MAGIC_WALL_DEAD,
3524     EL_BD_MAGIC_WALL,
3525     EL_BD_MAGIC_WALL_ACTIVE,
3526     EL_BD_MAGIC_WALL_EMPTYING,
3527     EL_BD_MAGIC_WALL_FULL,
3528     EL_BD_MAGIC_WALL_FILLING,
3529     EL_BD_MAGIC_WALL_DEAD,
3530     EL_GAME_OF_LIFE,
3531     EL_BIOMAZE,
3532     EL_SP_CHIP_SINGLE,
3533     EL_SP_CHIP_LEFT,
3534     EL_SP_CHIP_RIGHT,
3535     EL_SP_CHIP_TOP,
3536     EL_SP_CHIP_BOTTOM,
3537     EL_SP_TERMINAL,
3538     EL_SP_TERMINAL_ACTIVE,
3539     EL_SP_EXIT_CLOSED,
3540     EL_SP_EXIT_OPEN,
3541     EL_INVISIBLE_WALL,
3542     EL_INVISIBLE_WALL_ACTIVE,
3543     EL_SWITCHGATE_SWITCH_UP,
3544     EL_SWITCHGATE_SWITCH_DOWN,
3545     EL_DC_SWITCHGATE_SWITCH_UP,
3546     EL_DC_SWITCHGATE_SWITCH_DOWN,
3547     EL_TIMEGATE_SWITCH,
3548     EL_TIMEGATE_SWITCH_ACTIVE,
3549     EL_DC_TIMEGATE_SWITCH,
3550     EL_DC_TIMEGATE_SWITCH_ACTIVE,
3551     EL_EMC_WALL_1,
3552     EL_EMC_WALL_2,
3553     EL_EMC_WALL_3,
3554     EL_EMC_WALL_4,
3555     EL_EMC_WALL_5,
3556     EL_EMC_WALL_6,
3557     EL_EMC_WALL_7,
3558     EL_EMC_WALL_8,
3559     EL_WALL_PEARL,
3560     EL_WALL_CRYSTAL,
3561
3562     /* the following elements are a direct copy of "indestructible" elements,
3563        except "EL_ACID", which is "indestructible", but not "solid"! */
3564 #if 0
3565     EL_ACID,
3566 #endif
3567     EL_STEELWALL,
3568     EL_ACID_POOL_TOPLEFT,
3569     EL_ACID_POOL_TOPRIGHT,
3570     EL_ACID_POOL_BOTTOMLEFT,
3571     EL_ACID_POOL_BOTTOM,
3572     EL_ACID_POOL_BOTTOMRIGHT,
3573     EL_SP_HARDWARE_GRAY,
3574     EL_SP_HARDWARE_GREEN,
3575     EL_SP_HARDWARE_BLUE,
3576     EL_SP_HARDWARE_RED,
3577     EL_SP_HARDWARE_YELLOW,
3578     EL_SP_HARDWARE_BASE_1,
3579     EL_SP_HARDWARE_BASE_2,
3580     EL_SP_HARDWARE_BASE_3,
3581     EL_SP_HARDWARE_BASE_4,
3582     EL_SP_HARDWARE_BASE_5,
3583     EL_SP_HARDWARE_BASE_6,
3584     EL_INVISIBLE_STEELWALL,
3585     EL_INVISIBLE_STEELWALL_ACTIVE,
3586     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3587     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3588     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3589     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3590     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3591     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3592     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3593     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3594     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3595     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3596     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3597     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3598     EL_LIGHT_SWITCH,
3599     EL_LIGHT_SWITCH_ACTIVE,
3600     EL_SIGN_EXCLAMATION,
3601     EL_SIGN_RADIOACTIVITY,
3602     EL_SIGN_STOP,
3603     EL_SIGN_WHEELCHAIR,
3604     EL_SIGN_PARKING,
3605     EL_SIGN_NO_ENTRY,
3606     EL_SIGN_UNUSED_1,
3607     EL_SIGN_GIVE_WAY,
3608     EL_SIGN_ENTRY_FORBIDDEN,
3609     EL_SIGN_EMERGENCY_EXIT,
3610     EL_SIGN_YIN_YANG,
3611     EL_SIGN_UNUSED_2,
3612     EL_SIGN_SPERMS,
3613     EL_SIGN_BULLET,
3614     EL_SIGN_HEART,
3615     EL_SIGN_CROSS,
3616     EL_SIGN_FRANKIE,
3617     EL_STEEL_EXIT_CLOSED,
3618     EL_STEEL_EXIT_OPEN,
3619     EL_DC_STEELWALL_1_LEFT,
3620     EL_DC_STEELWALL_1_RIGHT,
3621     EL_DC_STEELWALL_1_TOP,
3622     EL_DC_STEELWALL_1_BOTTOM,
3623     EL_DC_STEELWALL_1_HORIZONTAL,
3624     EL_DC_STEELWALL_1_VERTICAL,
3625     EL_DC_STEELWALL_1_TOPLEFT,
3626     EL_DC_STEELWALL_1_TOPRIGHT,
3627     EL_DC_STEELWALL_1_BOTTOMLEFT,
3628     EL_DC_STEELWALL_1_BOTTOMRIGHT,
3629     EL_DC_STEELWALL_1_TOPLEFT_2,
3630     EL_DC_STEELWALL_1_TOPRIGHT_2,
3631     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
3632     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
3633     EL_DC_STEELWALL_2_LEFT,
3634     EL_DC_STEELWALL_2_RIGHT,
3635     EL_DC_STEELWALL_2_TOP,
3636     EL_DC_STEELWALL_2_BOTTOM,
3637     EL_DC_STEELWALL_2_HORIZONTAL,
3638     EL_DC_STEELWALL_2_VERTICAL,
3639     EL_DC_STEELWALL_2_MIDDLE,
3640     EL_DC_STEELWALL_2_SINGLE,
3641     EL_STEELWALL_SLIPPERY,
3642     EL_EMC_STEELWALL_1,
3643     EL_EMC_STEELWALL_2,
3644     EL_EMC_STEELWALL_3,
3645     EL_EMC_STEELWALL_4,
3646     EL_CRYSTAL,
3647     EL_GATE_1,
3648     EL_GATE_2,
3649     EL_GATE_3,
3650     EL_GATE_4,
3651     EL_GATE_1_GRAY,
3652     EL_GATE_2_GRAY,
3653     EL_GATE_3_GRAY,
3654     EL_GATE_4_GRAY,
3655     EL_GATE_1_GRAY_ACTIVE,
3656     EL_GATE_2_GRAY_ACTIVE,
3657     EL_GATE_3_GRAY_ACTIVE,
3658     EL_GATE_4_GRAY_ACTIVE,
3659     EL_EM_GATE_1,
3660     EL_EM_GATE_2,
3661     EL_EM_GATE_3,
3662     EL_EM_GATE_4,
3663     EL_EM_GATE_1_GRAY,
3664     EL_EM_GATE_2_GRAY,
3665     EL_EM_GATE_3_GRAY,
3666     EL_EM_GATE_4_GRAY,
3667     EL_EM_GATE_1_GRAY_ACTIVE,
3668     EL_EM_GATE_2_GRAY_ACTIVE,
3669     EL_EM_GATE_3_GRAY_ACTIVE,
3670     EL_EM_GATE_4_GRAY_ACTIVE,
3671     EL_SWITCHGATE_OPEN,
3672     EL_SWITCHGATE_OPENING,
3673     EL_SWITCHGATE_CLOSED,
3674     EL_SWITCHGATE_CLOSING,
3675     EL_TIMEGATE_OPEN,
3676     EL_TIMEGATE_OPENING,
3677     EL_TIMEGATE_CLOSED,
3678     EL_TIMEGATE_CLOSING,
3679     EL_TUBE_ANY,
3680     EL_TUBE_VERTICAL,
3681     EL_TUBE_HORIZONTAL,
3682     EL_TUBE_VERTICAL_LEFT,
3683     EL_TUBE_VERTICAL_RIGHT,
3684     EL_TUBE_HORIZONTAL_UP,
3685     EL_TUBE_HORIZONTAL_DOWN,
3686     EL_TUBE_LEFT_UP,
3687     EL_TUBE_LEFT_DOWN,
3688     EL_TUBE_RIGHT_UP,
3689     EL_TUBE_RIGHT_DOWN,
3690
3691     -1
3692   };
3693
3694   static int ep_classic_enemy[] =
3695   {
3696     EL_BUG,
3697     EL_SPACESHIP,
3698     EL_BD_BUTTERFLY,
3699     EL_BD_FIREFLY,
3700
3701     EL_YAMYAM,
3702     EL_DARK_YAMYAM,
3703     EL_ROBOT,
3704     EL_PACMAN,
3705     EL_SP_SNIKSNAK,
3706     EL_SP_ELECTRON,
3707
3708     -1
3709   };
3710
3711   static int ep_belt[] =
3712   {
3713     EL_CONVEYOR_BELT_1_LEFT,
3714     EL_CONVEYOR_BELT_1_MIDDLE,
3715     EL_CONVEYOR_BELT_1_RIGHT,
3716     EL_CONVEYOR_BELT_2_LEFT,
3717     EL_CONVEYOR_BELT_2_MIDDLE,
3718     EL_CONVEYOR_BELT_2_RIGHT,
3719     EL_CONVEYOR_BELT_3_LEFT,
3720     EL_CONVEYOR_BELT_3_MIDDLE,
3721     EL_CONVEYOR_BELT_3_RIGHT,
3722     EL_CONVEYOR_BELT_4_LEFT,
3723     EL_CONVEYOR_BELT_4_MIDDLE,
3724     EL_CONVEYOR_BELT_4_RIGHT,
3725
3726     -1
3727   };
3728
3729   static int ep_belt_active[] =
3730   {
3731     EL_CONVEYOR_BELT_1_LEFT_ACTIVE,
3732     EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE,
3733     EL_CONVEYOR_BELT_1_RIGHT_ACTIVE,
3734     EL_CONVEYOR_BELT_2_LEFT_ACTIVE,
3735     EL_CONVEYOR_BELT_2_MIDDLE_ACTIVE,
3736     EL_CONVEYOR_BELT_2_RIGHT_ACTIVE,
3737     EL_CONVEYOR_BELT_3_LEFT_ACTIVE,
3738     EL_CONVEYOR_BELT_3_MIDDLE_ACTIVE,
3739     EL_CONVEYOR_BELT_3_RIGHT_ACTIVE,
3740     EL_CONVEYOR_BELT_4_LEFT_ACTIVE,
3741     EL_CONVEYOR_BELT_4_MIDDLE_ACTIVE,
3742     EL_CONVEYOR_BELT_4_RIGHT_ACTIVE,
3743
3744     -1
3745   };
3746
3747   static int ep_belt_switch[] =
3748   {
3749     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
3750     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
3751     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
3752     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
3753     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
3754     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
3755     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
3756     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
3757     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
3758     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
3759     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
3760     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
3761
3762     -1
3763   };
3764
3765   static int ep_tube[] =
3766   {
3767     EL_TUBE_LEFT_UP,
3768     EL_TUBE_LEFT_DOWN,
3769     EL_TUBE_RIGHT_UP,
3770     EL_TUBE_RIGHT_DOWN,
3771     EL_TUBE_HORIZONTAL,
3772     EL_TUBE_HORIZONTAL_UP,
3773     EL_TUBE_HORIZONTAL_DOWN,
3774     EL_TUBE_VERTICAL,
3775     EL_TUBE_VERTICAL_LEFT,
3776     EL_TUBE_VERTICAL_RIGHT,
3777     EL_TUBE_ANY,
3778
3779     -1
3780   };
3781
3782   static int ep_acid_pool[] =
3783   {
3784     EL_ACID_POOL_TOPLEFT,
3785     EL_ACID_POOL_TOPRIGHT,
3786     EL_ACID_POOL_BOTTOMLEFT,
3787     EL_ACID_POOL_BOTTOM,
3788     EL_ACID_POOL_BOTTOMRIGHT,
3789
3790     -1
3791   };
3792
3793   static int ep_keygate[] =
3794   {
3795     EL_GATE_1,
3796     EL_GATE_2,
3797     EL_GATE_3,
3798     EL_GATE_4,
3799     EL_GATE_1_GRAY,
3800     EL_GATE_2_GRAY,
3801     EL_GATE_3_GRAY,
3802     EL_GATE_4_GRAY,
3803     EL_GATE_1_GRAY_ACTIVE,
3804     EL_GATE_2_GRAY_ACTIVE,
3805     EL_GATE_3_GRAY_ACTIVE,
3806     EL_GATE_4_GRAY_ACTIVE,
3807     EL_EM_GATE_1,
3808     EL_EM_GATE_2,
3809     EL_EM_GATE_3,
3810     EL_EM_GATE_4,
3811     EL_EM_GATE_1_GRAY,
3812     EL_EM_GATE_2_GRAY,
3813     EL_EM_GATE_3_GRAY,
3814     EL_EM_GATE_4_GRAY,
3815     EL_EM_GATE_1_GRAY_ACTIVE,
3816     EL_EM_GATE_2_GRAY_ACTIVE,
3817     EL_EM_GATE_3_GRAY_ACTIVE,
3818     EL_EM_GATE_4_GRAY_ACTIVE,
3819     EL_EMC_GATE_5,
3820     EL_EMC_GATE_6,
3821     EL_EMC_GATE_7,
3822     EL_EMC_GATE_8,
3823     EL_EMC_GATE_5_GRAY,
3824     EL_EMC_GATE_6_GRAY,
3825     EL_EMC_GATE_7_GRAY,
3826     EL_EMC_GATE_8_GRAY,
3827     EL_EMC_GATE_5_GRAY_ACTIVE,
3828     EL_EMC_GATE_6_GRAY_ACTIVE,
3829     EL_EMC_GATE_7_GRAY_ACTIVE,
3830     EL_EMC_GATE_8_GRAY_ACTIVE,
3831     EL_DC_GATE_WHITE,
3832     EL_DC_GATE_WHITE_GRAY,
3833     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3834
3835     -1
3836   };
3837
3838   static int ep_amoeboid[] =
3839   {
3840     EL_AMOEBA_DEAD,
3841     EL_AMOEBA_WET,
3842     EL_AMOEBA_DRY,
3843     EL_AMOEBA_FULL,
3844     EL_BD_AMOEBA,
3845     EL_EMC_DRIPPER,
3846
3847     -1
3848   };
3849
3850   static int ep_amoebalive[] =
3851   {
3852     EL_AMOEBA_WET,
3853     EL_AMOEBA_DRY,
3854     EL_AMOEBA_FULL,
3855     EL_BD_AMOEBA,
3856     EL_EMC_DRIPPER,
3857
3858     -1
3859   };
3860
3861   static int ep_has_editor_content[] =
3862   {
3863     EL_PLAYER_1,
3864     EL_PLAYER_2,
3865     EL_PLAYER_3,
3866     EL_PLAYER_4,
3867     EL_SOKOBAN_FIELD_PLAYER,
3868     EL_SP_MURPHY,
3869     EL_YAMYAM,
3870     EL_YAMYAM_LEFT,
3871     EL_YAMYAM_RIGHT,
3872     EL_YAMYAM_UP,
3873     EL_YAMYAM_DOWN,
3874     EL_AMOEBA_WET,
3875     EL_AMOEBA_DRY,
3876     EL_AMOEBA_FULL,
3877     EL_BD_AMOEBA,
3878     EL_EMC_MAGIC_BALL,
3879     EL_EMC_ANDROID,
3880
3881     -1
3882   };
3883
3884   static int ep_can_turn_each_move[] =
3885   {
3886     /* !!! do something with this one !!! */
3887     -1
3888   };
3889
3890   static int ep_can_grow[] =
3891   {
3892     EL_BD_AMOEBA,
3893     EL_AMOEBA_DROP,
3894     EL_AMOEBA_WET,
3895     EL_AMOEBA_DRY,
3896     EL_AMOEBA_FULL,
3897     EL_GAME_OF_LIFE,
3898     EL_BIOMAZE,
3899     EL_EMC_DRIPPER,
3900
3901     -1
3902   };
3903
3904   static int ep_active_bomb[] =
3905   {
3906     EL_DYNAMITE_ACTIVE,
3907     EL_EM_DYNAMITE_ACTIVE,
3908     EL_DYNABOMB_PLAYER_1_ACTIVE,
3909     EL_DYNABOMB_PLAYER_2_ACTIVE,
3910     EL_DYNABOMB_PLAYER_3_ACTIVE,
3911     EL_DYNABOMB_PLAYER_4_ACTIVE,
3912     EL_SP_DISK_RED_ACTIVE,
3913
3914     -1
3915   };
3916
3917   static int ep_inactive[] =
3918   {
3919     EL_EMPTY,
3920     EL_SAND,
3921     EL_WALL,
3922     EL_BD_WALL,
3923     EL_WALL_SLIPPERY,
3924     EL_STEELWALL,
3925     EL_AMOEBA_DEAD,
3926     EL_QUICKSAND_EMPTY,
3927     EL_QUICKSAND_FAST_EMPTY,
3928     EL_STONEBLOCK,
3929     EL_ROBOT_WHEEL,
3930     EL_KEY_1,
3931     EL_KEY_2,
3932     EL_KEY_3,
3933     EL_KEY_4,
3934     EL_EM_KEY_1,
3935     EL_EM_KEY_2,
3936     EL_EM_KEY_3,
3937     EL_EM_KEY_4,
3938     EL_EMC_KEY_5,
3939     EL_EMC_KEY_6,
3940     EL_EMC_KEY_7,
3941     EL_EMC_KEY_8,
3942     EL_GATE_1,
3943     EL_GATE_2,
3944     EL_GATE_3,
3945     EL_GATE_4,
3946     EL_GATE_1_GRAY,
3947     EL_GATE_2_GRAY,
3948     EL_GATE_3_GRAY,
3949     EL_GATE_4_GRAY,
3950     EL_GATE_1_GRAY_ACTIVE,
3951     EL_GATE_2_GRAY_ACTIVE,
3952     EL_GATE_3_GRAY_ACTIVE,
3953     EL_GATE_4_GRAY_ACTIVE,
3954     EL_EM_GATE_1,
3955     EL_EM_GATE_2,
3956     EL_EM_GATE_3,
3957     EL_EM_GATE_4,
3958     EL_EM_GATE_1_GRAY,
3959     EL_EM_GATE_2_GRAY,
3960     EL_EM_GATE_3_GRAY,
3961     EL_EM_GATE_4_GRAY,
3962     EL_EM_GATE_1_GRAY_ACTIVE,
3963     EL_EM_GATE_2_GRAY_ACTIVE,
3964     EL_EM_GATE_3_GRAY_ACTIVE,
3965     EL_EM_GATE_4_GRAY_ACTIVE,
3966     EL_EMC_GATE_5,
3967     EL_EMC_GATE_6,
3968     EL_EMC_GATE_7,
3969     EL_EMC_GATE_8,
3970     EL_EMC_GATE_5_GRAY,
3971     EL_EMC_GATE_6_GRAY,
3972     EL_EMC_GATE_7_GRAY,
3973     EL_EMC_GATE_8_GRAY,
3974     EL_EMC_GATE_5_GRAY_ACTIVE,
3975     EL_EMC_GATE_6_GRAY_ACTIVE,
3976     EL_EMC_GATE_7_GRAY_ACTIVE,
3977     EL_EMC_GATE_8_GRAY_ACTIVE,
3978     EL_DC_GATE_WHITE,
3979     EL_DC_GATE_WHITE_GRAY,
3980     EL_DC_GATE_WHITE_GRAY_ACTIVE,
3981     EL_DC_GATE_FAKE_GRAY,
3982     EL_DYNAMITE,
3983     EL_EM_DYNAMITE,
3984     EL_INVISIBLE_STEELWALL,
3985     EL_INVISIBLE_WALL,
3986     EL_INVISIBLE_SAND,
3987     EL_LAMP,
3988     EL_LAMP_ACTIVE,
3989     EL_WALL_EMERALD,
3990     EL_WALL_DIAMOND,
3991     EL_WALL_BD_DIAMOND,
3992     EL_WALL_EMERALD_YELLOW,
3993     EL_DYNABOMB_INCREASE_NUMBER,
3994     EL_DYNABOMB_INCREASE_SIZE,
3995     EL_DYNABOMB_INCREASE_POWER,
3996 #if 0
3997     EL_SOKOBAN_OBJECT,
3998 #endif
3999     EL_SOKOBAN_FIELD_EMPTY,
4000     EL_SOKOBAN_FIELD_FULL,
4001     EL_WALL_EMERALD_RED,
4002     EL_WALL_EMERALD_PURPLE,
4003     EL_ACID_POOL_TOPLEFT,
4004     EL_ACID_POOL_TOPRIGHT,
4005     EL_ACID_POOL_BOTTOMLEFT,
4006     EL_ACID_POOL_BOTTOM,
4007     EL_ACID_POOL_BOTTOMRIGHT,
4008     EL_MAGIC_WALL,
4009     EL_MAGIC_WALL_DEAD,
4010     EL_BD_MAGIC_WALL,
4011     EL_BD_MAGIC_WALL_DEAD,
4012     EL_DC_MAGIC_WALL,
4013     EL_DC_MAGIC_WALL_DEAD,
4014     EL_AMOEBA_TO_DIAMOND,
4015     EL_BLOCKED,
4016     EL_SP_EMPTY,
4017     EL_SP_BASE,
4018     EL_SP_PORT_RIGHT,
4019     EL_SP_PORT_DOWN,
4020     EL_SP_PORT_LEFT,
4021     EL_SP_PORT_UP,
4022     EL_SP_GRAVITY_PORT_RIGHT,
4023     EL_SP_GRAVITY_PORT_DOWN,
4024     EL_SP_GRAVITY_PORT_LEFT,
4025     EL_SP_GRAVITY_PORT_UP,
4026     EL_SP_PORT_HORIZONTAL,
4027     EL_SP_PORT_VERTICAL,
4028     EL_SP_PORT_ANY,
4029     EL_SP_DISK_RED,
4030 #if 0
4031     EL_SP_DISK_YELLOW,
4032 #endif
4033     EL_SP_CHIP_SINGLE,
4034     EL_SP_CHIP_LEFT,
4035     EL_SP_CHIP_RIGHT,
4036     EL_SP_CHIP_TOP,
4037     EL_SP_CHIP_BOTTOM,
4038     EL_SP_HARDWARE_GRAY,
4039     EL_SP_HARDWARE_GREEN,
4040     EL_SP_HARDWARE_BLUE,
4041     EL_SP_HARDWARE_RED,
4042     EL_SP_HARDWARE_YELLOW,
4043     EL_SP_HARDWARE_BASE_1,
4044     EL_SP_HARDWARE_BASE_2,
4045     EL_SP_HARDWARE_BASE_3,
4046     EL_SP_HARDWARE_BASE_4,
4047     EL_SP_HARDWARE_BASE_5,
4048     EL_SP_HARDWARE_BASE_6,
4049     EL_SP_GRAVITY_ON_PORT_LEFT,
4050     EL_SP_GRAVITY_ON_PORT_RIGHT,
4051     EL_SP_GRAVITY_ON_PORT_UP,
4052     EL_SP_GRAVITY_ON_PORT_DOWN,
4053     EL_SP_GRAVITY_OFF_PORT_LEFT,
4054     EL_SP_GRAVITY_OFF_PORT_RIGHT,
4055     EL_SP_GRAVITY_OFF_PORT_UP,
4056     EL_SP_GRAVITY_OFF_PORT_DOWN,
4057     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
4058     EL_CONVEYOR_BELT_1_SWITCH_MIDDLE,
4059     EL_CONVEYOR_BELT_1_SWITCH_RIGHT,
4060     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
4061     EL_CONVEYOR_BELT_2_SWITCH_MIDDLE,
4062     EL_CONVEYOR_BELT_2_SWITCH_RIGHT,
4063     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
4064     EL_CONVEYOR_BELT_3_SWITCH_MIDDLE,
4065     EL_CONVEYOR_BELT_3_SWITCH_RIGHT,
4066     EL_CONVEYOR_BELT_4_SWITCH_LEFT,
4067     EL_CONVEYOR_BELT_4_SWITCH_MIDDLE,
4068     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
4069     EL_SIGN_EXCLAMATION,
4070     EL_SIGN_RADIOACTIVITY,
4071     EL_SIGN_STOP,
4072     EL_SIGN_WHEELCHAIR,
4073     EL_SIGN_PARKING,
4074     EL_SIGN_NO_ENTRY,
4075     EL_SIGN_UNUSED_1,
4076     EL_SIGN_GIVE_WAY,
4077     EL_SIGN_ENTRY_FORBIDDEN,
4078     EL_SIGN_EMERGENCY_EXIT,
4079     EL_SIGN_YIN_YANG,
4080     EL_SIGN_UNUSED_2,
4081     EL_SIGN_SPERMS,
4082     EL_SIGN_BULLET,
4083     EL_SIGN_HEART,
4084     EL_SIGN_CROSS,
4085     EL_SIGN_FRANKIE,
4086     EL_DC_STEELWALL_1_LEFT,
4087     EL_DC_STEELWALL_1_RIGHT,
4088     EL_DC_STEELWALL_1_TOP,
4089     EL_DC_STEELWALL_1_BOTTOM,
4090     EL_DC_STEELWALL_1_HORIZONTAL,
4091     EL_DC_STEELWALL_1_VERTICAL,
4092     EL_DC_STEELWALL_1_TOPLEFT,
4093     EL_DC_STEELWALL_1_TOPRIGHT,
4094     EL_DC_STEELWALL_1_BOTTOMLEFT,
4095     EL_DC_STEELWALL_1_BOTTOMRIGHT,
4096     EL_DC_STEELWALL_1_TOPLEFT_2,
4097     EL_DC_STEELWALL_1_TOPRIGHT_2,
4098     EL_DC_STEELWALL_1_BOTTOMLEFT_2,
4099     EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
4100     EL_DC_STEELWALL_2_LEFT,
4101     EL_DC_STEELWALL_2_RIGHT,
4102     EL_DC_STEELWALL_2_TOP,
4103     EL_DC_STEELWALL_2_BOTTOM,
4104     EL_DC_STEELWALL_2_HORIZONTAL,
4105     EL_DC_STEELWALL_2_VERTICAL,
4106     EL_DC_STEELWALL_2_MIDDLE,
4107     EL_DC_STEELWALL_2_SINGLE,
4108     EL_STEELWALL_SLIPPERY,
4109     EL_EMC_STEELWALL_1,
4110     EL_EMC_STEELWALL_2,
4111     EL_EMC_STEELWALL_3,
4112     EL_EMC_STEELWALL_4,
4113     EL_EMC_WALL_SLIPPERY_1,
4114     EL_EMC_WALL_SLIPPERY_2,
4115     EL_EMC_WALL_SLIPPERY_3,
4116     EL_EMC_WALL_SLIPPERY_4,
4117     EL_EMC_WALL_1,
4118     EL_EMC_WALL_2,
4119     EL_EMC_WALL_3,
4120     EL_EMC_WALL_4,
4121     EL_EMC_WALL_5,
4122     EL_EMC_WALL_6,
4123     EL_EMC_WALL_7,
4124     EL_EMC_WALL_8,
4125     EL_EMC_WALL_9,
4126     EL_EMC_WALL_10,
4127     EL_EMC_WALL_11,
4128     EL_EMC_WALL_12,
4129     EL_EMC_WALL_13,
4130     EL_EMC_WALL_14,
4131     EL_EMC_WALL_15,
4132     EL_EMC_WALL_16,
4133
4134     -1
4135   };
4136
4137   static int ep_em_slippery_wall[] =
4138   {
4139     -1
4140   };
4141
4142   static int ep_gfx_crumbled[] =
4143   {
4144     EL_SAND,
4145     EL_LANDMINE,
4146     EL_DC_LANDMINE,
4147     EL_TRAP,
4148     EL_TRAP_ACTIVE,
4149
4150     -1
4151   };
4152
4153   static int ep_editor_cascade_active[] =
4154   {
4155     EL_INTERNAL_CASCADE_BD_ACTIVE,
4156     EL_INTERNAL_CASCADE_EM_ACTIVE,
4157     EL_INTERNAL_CASCADE_EMC_ACTIVE,
4158     EL_INTERNAL_CASCADE_RND_ACTIVE,
4159     EL_INTERNAL_CASCADE_SB_ACTIVE,
4160     EL_INTERNAL_CASCADE_SP_ACTIVE,
4161     EL_INTERNAL_CASCADE_DC_ACTIVE,
4162     EL_INTERNAL_CASCADE_DX_ACTIVE,
4163     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
4164     EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
4165     EL_INTERNAL_CASCADE_CE_ACTIVE,
4166     EL_INTERNAL_CASCADE_GE_ACTIVE,
4167     EL_INTERNAL_CASCADE_REF_ACTIVE,
4168     EL_INTERNAL_CASCADE_USER_ACTIVE,
4169     EL_INTERNAL_CASCADE_DYNAMIC_ACTIVE,
4170
4171     -1
4172   };
4173
4174   static int ep_editor_cascade_inactive[] =
4175   {
4176     EL_INTERNAL_CASCADE_BD,
4177     EL_INTERNAL_CASCADE_EM,
4178     EL_INTERNAL_CASCADE_EMC,
4179     EL_INTERNAL_CASCADE_RND,
4180     EL_INTERNAL_CASCADE_SB,
4181     EL_INTERNAL_CASCADE_SP,
4182     EL_INTERNAL_CASCADE_DC,
4183     EL_INTERNAL_CASCADE_DX,
4184     EL_INTERNAL_CASCADE_CHARS,
4185     EL_INTERNAL_CASCADE_STEEL_CHARS,
4186     EL_INTERNAL_CASCADE_CE,
4187     EL_INTERNAL_CASCADE_GE,
4188     EL_INTERNAL_CASCADE_REF,
4189     EL_INTERNAL_CASCADE_USER,
4190     EL_INTERNAL_CASCADE_DYNAMIC,
4191
4192     -1
4193   };
4194
4195   static int ep_obsolete[] =
4196   {
4197     EL_PLAYER_OBSOLETE,
4198     EL_KEY_OBSOLETE,
4199     EL_EM_KEY_1_FILE_OBSOLETE,
4200     EL_EM_KEY_2_FILE_OBSOLETE,
4201     EL_EM_KEY_3_FILE_OBSOLETE,
4202     EL_EM_KEY_4_FILE_OBSOLETE,
4203     EL_ENVELOPE_OBSOLETE,
4204
4205     -1
4206   };
4207
4208   static struct
4209   {
4210     int *elements;
4211     int property;
4212   } element_properties[] =
4213   {
4214     { ep_diggable,                      EP_DIGGABLE                     },
4215     { ep_collectible_only,              EP_COLLECTIBLE_ONLY             },
4216     { ep_dont_run_into,                 EP_DONT_RUN_INTO                },
4217     { ep_dont_collide_with,             EP_DONT_COLLIDE_WITH            },
4218     { ep_dont_touch,                    EP_DONT_TOUCH                   },
4219     { ep_indestructible,                EP_INDESTRUCTIBLE               },
4220     { ep_slippery,                      EP_SLIPPERY                     },
4221     { ep_can_change,                    EP_CAN_CHANGE                   },
4222     { ep_can_move,                      EP_CAN_MOVE                     },
4223     { ep_can_fall,                      EP_CAN_FALL                     },
4224     { ep_can_smash_player,              EP_CAN_SMASH_PLAYER             },
4225     { ep_can_smash_enemies,             EP_CAN_SMASH_ENEMIES            },
4226     { ep_can_smash_everything,          EP_CAN_SMASH_EVERYTHING         },
4227     { ep_explodes_by_fire,              EP_EXPLODES_BY_FIRE             },
4228     { ep_explodes_smashed,              EP_EXPLODES_SMASHED             },
4229     { ep_explodes_impact,               EP_EXPLODES_IMPACT              },
4230     { ep_walkable_over,                 EP_WALKABLE_OVER                },
4231     { ep_walkable_inside,               EP_WALKABLE_INSIDE              },
4232     { ep_walkable_under,                EP_WALKABLE_UNDER               },
4233     { ep_passable_over,                 EP_PASSABLE_OVER                },
4234     { ep_passable_inside,               EP_PASSABLE_INSIDE              },
4235     { ep_passable_under,                EP_PASSABLE_UNDER               },
4236     { ep_droppable,                     EP_DROPPABLE                    },
4237     { ep_explodes_1x1_old,              EP_EXPLODES_1X1_OLD             },
4238     { ep_pushable,                      EP_PUSHABLE                     },
4239     { ep_explodes_cross_old,            EP_EXPLODES_CROSS_OLD           },
4240     { ep_protected,                     EP_PROTECTED                    },
4241     { ep_throwable,                     EP_THROWABLE                    },
4242     { ep_can_explode,                   EP_CAN_EXPLODE                  },
4243     { ep_gravity_reachable,             EP_GRAVITY_REACHABLE            },
4244
4245     { ep_player,                        EP_PLAYER                       },
4246     { ep_can_pass_magic_wall,           EP_CAN_PASS_MAGIC_WALL          },
4247     { ep_can_pass_dc_magic_wall,        EP_CAN_PASS_DC_MAGIC_WALL       },
4248     { ep_switchable,                    EP_SWITCHABLE                   },
4249     { ep_bd_element,                    EP_BD_ELEMENT                   },
4250     { ep_sp_element,                    EP_SP_ELEMENT                   },
4251     { ep_sb_element,                    EP_SB_ELEMENT                   },
4252     { ep_gem,                           EP_GEM                          },
4253     { ep_food_dark_yamyam,              EP_FOOD_DARK_YAMYAM             },
4254     { ep_food_penguin,                  EP_FOOD_PENGUIN                 },
4255     { ep_food_pig,                      EP_FOOD_PIG                     },
4256     { ep_historic_wall,                 EP_HISTORIC_WALL                },
4257     { ep_historic_solid,                EP_HISTORIC_SOLID               },
4258     { ep_classic_enemy,                 EP_CLASSIC_ENEMY                },
4259     { ep_belt,                          EP_BELT                         },
4260     { ep_belt_active,                   EP_BELT_ACTIVE                  },
4261     { ep_belt_switch,                   EP_BELT_SWITCH                  },
4262     { ep_tube,                          EP_TUBE                         },
4263     { ep_acid_pool,                     EP_ACID_POOL                    },
4264     { ep_keygate,                       EP_KEYGATE                      },
4265     { ep_amoeboid,                      EP_AMOEBOID                     },
4266     { ep_amoebalive,                    EP_AMOEBALIVE                   },
4267     { ep_has_editor_content,            EP_HAS_EDITOR_CONTENT           },
4268     { ep_can_turn_each_move,            EP_CAN_TURN_EACH_MOVE           },
4269     { ep_can_grow,                      EP_CAN_GROW                     },
4270     { ep_active_bomb,                   EP_ACTIVE_BOMB                  },
4271     { ep_inactive,                      EP_INACTIVE                     },
4272
4273     { ep_em_slippery_wall,              EP_EM_SLIPPERY_WALL             },
4274
4275     { ep_gfx_crumbled,                  EP_GFX_CRUMBLED                 },
4276
4277     { ep_editor_cascade_active,         EP_EDITOR_CASCADE_ACTIVE        },
4278     { ep_editor_cascade_inactive,       EP_EDITOR_CASCADE_INACTIVE      },
4279
4280     { ep_obsolete,                      EP_OBSOLETE                     },
4281
4282     { NULL,                             -1                              }
4283   };
4284
4285   int i, j, k;
4286
4287   /* always start with reliable default values (element has no properties) */
4288   /* (but never initialize clipboard elements after the very first time) */
4289   /* (to be able to use clipboard elements between several levels) */
4290   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4291     if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
4292       for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
4293         SET_PROPERTY(i, j, FALSE);
4294
4295   /* set all base element properties from above array definitions */
4296   for (i = 0; element_properties[i].elements != NULL; i++)
4297     for (j = 0; (element_properties[i].elements)[j] != -1; j++)
4298       SET_PROPERTY((element_properties[i].elements)[j],
4299                    element_properties[i].property, TRUE);
4300
4301   /* copy properties to some elements that are only stored in level file */
4302   for (i = 0; i < NUM_ELEMENT_PROPERTIES; i++)
4303     for (j = 0; copy_properties[j][0] != -1; j++)
4304       if (HAS_PROPERTY(copy_properties[j][0], i))
4305         for (k = 1; k <= 4; k++)
4306           SET_PROPERTY(copy_properties[j][k], i, TRUE);
4307
4308   /* set static element properties that are not listed in array definitions */
4309   for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
4310     SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
4311
4312   clipboard_elements_initialized = TRUE;
4313 }
4314
4315 void InitElementPropertiesEngine(int engine_version)
4316 {
4317   static int no_wall_properties[] =
4318   {
4319     EP_DIGGABLE,
4320     EP_COLLECTIBLE_ONLY,
4321     EP_DONT_RUN_INTO,
4322     EP_DONT_COLLIDE_WITH,
4323     EP_CAN_MOVE,
4324     EP_CAN_FALL,
4325     EP_CAN_SMASH_PLAYER,
4326     EP_CAN_SMASH_ENEMIES,
4327     EP_CAN_SMASH_EVERYTHING,
4328     EP_PUSHABLE,
4329
4330     EP_PLAYER,
4331     EP_GEM,
4332     EP_FOOD_DARK_YAMYAM,
4333     EP_FOOD_PENGUIN,
4334     EP_BELT,
4335     EP_BELT_ACTIVE,
4336     EP_TUBE,
4337     EP_AMOEBOID,
4338     EP_AMOEBALIVE,
4339     EP_ACTIVE_BOMB,
4340
4341     EP_ACCESSIBLE,
4342
4343     -1
4344   };
4345
4346   int i, j;
4347
4348   /* important: after initialization in InitElementPropertiesStatic(), the
4349      elements are not again initialized to a default value; therefore all
4350      changes have to make sure that they leave the element with a defined
4351      property (which means that conditional property changes must be set to
4352      a reliable default value before) */
4353
4354   /* resolve group elements */
4355   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4356     ResolveGroupElement(EL_GROUP_START + i);
4357
4358   /* set all special, combined or engine dependent element properties */
4359   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4360   {
4361     /* do not change (already initialized) clipboard elements here */
4362     if (IS_CLIPBOARD_ELEMENT(i))
4363       continue;
4364
4365     /* ---------- INACTIVE ------------------------------------------------- */
4366     SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
4367                                    i <= EL_CHAR_END) ||
4368                                   (i >= EL_STEEL_CHAR_START &&
4369                                    i <= EL_STEEL_CHAR_END)));
4370
4371     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
4372     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
4373                                   IS_WALKABLE_INSIDE(i) ||
4374                                   IS_WALKABLE_UNDER(i)));
4375
4376     SET_PROPERTY(i, EP_PASSABLE, (IS_PASSABLE_OVER(i) ||
4377                                   IS_PASSABLE_INSIDE(i) ||
4378                                   IS_PASSABLE_UNDER(i)));
4379
4380     SET_PROPERTY(i, EP_ACCESSIBLE_OVER, (IS_WALKABLE_OVER(i) ||
4381                                          IS_PASSABLE_OVER(i)));
4382
4383     SET_PROPERTY(i, EP_ACCESSIBLE_INSIDE, (IS_WALKABLE_INSIDE(i) ||
4384                                            IS_PASSABLE_INSIDE(i)));
4385
4386     SET_PROPERTY(i, EP_ACCESSIBLE_UNDER, (IS_WALKABLE_UNDER(i) ||
4387                                           IS_PASSABLE_UNDER(i)));
4388
4389     SET_PROPERTY(i, EP_ACCESSIBLE, (IS_WALKABLE(i) ||
4390                                     IS_PASSABLE(i)));
4391
4392     /* ---------- COLLECTIBLE ---------------------------------------------- */
4393     SET_PROPERTY(i, EP_COLLECTIBLE, (IS_COLLECTIBLE_ONLY(i) ||
4394                                      IS_DROPPABLE(i) ||
4395                                      IS_THROWABLE(i)));
4396
4397     /* ---------- SNAPPABLE ------------------------------------------------ */
4398     SET_PROPERTY(i, EP_SNAPPABLE, (IS_DIGGABLE(i) ||
4399                                    IS_COLLECTIBLE(i) ||
4400                                    IS_SWITCHABLE(i) ||
4401                                    i == EL_BD_ROCK));
4402
4403     /* ---------- WALL ----------------------------------------------------- */
4404     SET_PROPERTY(i, EP_WALL, TRUE);     /* default: element is wall */
4405
4406     for (j = 0; no_wall_properties[j] != -1; j++)
4407       if (HAS_PROPERTY(i, no_wall_properties[j]) ||
4408           i >= EL_FIRST_RUNTIME_UNREAL)
4409         SET_PROPERTY(i, EP_WALL, FALSE);
4410
4411     if (IS_HISTORIC_WALL(i))
4412       SET_PROPERTY(i, EP_WALL, TRUE);
4413
4414     /* ---------- SOLID_FOR_PUSHING ---------------------------------------- */
4415     if (engine_version < VERSION_IDENT(2,2,0,0))
4416       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, IS_HISTORIC_SOLID(i));
4417     else
4418       SET_PROPERTY(i, EP_SOLID_FOR_PUSHING, (!IS_WALKABLE(i) &&
4419                                              !IS_DIGGABLE(i) &&
4420                                              !IS_COLLECTIBLE(i)));
4421
4422     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
4423     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
4424       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
4425     else
4426       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, (IS_CUSTOM_ELEMENT(i) &&
4427                                             IS_INDESTRUCTIBLE(i)));
4428
4429     /* ---------- EXPLOSION_PROOF ------------------------------------------ */
4430     if (i == EL_FLAMES)
4431       SET_PROPERTY(i, EP_EXPLOSION_PROOF, TRUE);
4432     else if (engine_version < VERSION_IDENT(2,2,0,0))
4433       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
4434     else
4435       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
4436                                            (!IS_WALKABLE(i) ||
4437                                             IS_PROTECTED(i))));
4438
4439     if (IS_CUSTOM_ELEMENT(i))
4440     {
4441       /* these are additional properties which are initially false when set */
4442
4443       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
4444       if (DONT_TOUCH(i))
4445         SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
4446       if (DONT_COLLIDE_WITH(i))
4447         SET_PROPERTY(i, EP_DONT_RUN_INTO, TRUE);
4448
4449       /* ---------- CAN_SMASH_ENEMIES / CAN_SMASH_PLAYER ------------------- */
4450       if (CAN_SMASH_EVERYTHING(i))
4451         SET_PROPERTY(i, EP_CAN_SMASH_ENEMIES, TRUE);
4452       if (CAN_SMASH_ENEMIES(i))
4453         SET_PROPERTY(i, EP_CAN_SMASH_PLAYER, TRUE);
4454     }
4455
4456     /* ---------- CAN_SMASH ------------------------------------------------ */
4457     SET_PROPERTY(i, EP_CAN_SMASH, (CAN_SMASH_PLAYER(i) ||
4458                                    CAN_SMASH_ENEMIES(i) ||
4459                                    CAN_SMASH_EVERYTHING(i)));
4460
4461     /* ---------- CAN_EXPLODE_BY_FIRE -------------------------------------- */
4462     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_FIRE, (CAN_EXPLODE(i) &&
4463                                              EXPLODES_BY_FIRE(i)));
4464
4465     /* ---------- CAN_EXPLODE_SMASHED -------------------------------------- */
4466     SET_PROPERTY(i, EP_CAN_EXPLODE_SMASHED, (CAN_EXPLODE(i) &&
4467                                              EXPLODES_SMASHED(i)));
4468
4469     /* ---------- CAN_EXPLODE_IMPACT --------------------------------------- */
4470     SET_PROPERTY(i, EP_CAN_EXPLODE_IMPACT, (CAN_EXPLODE(i) &&
4471                                             EXPLODES_IMPACT(i)));
4472
4473     /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
4474     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
4475
4476     /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
4477     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
4478                                                   i == EL_BLACK_ORB));
4479
4480     /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
4481     SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
4482                                               CAN_MOVE(i) ||
4483                                               IS_CUSTOM_ELEMENT(i)));
4484
4485     /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
4486     SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
4487                                                  i == EL_SP_ELECTRON));
4488
4489     /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
4490     if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
4491       SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
4492                    getMoveIntoAcidProperty(&level, i));
4493
4494     /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
4495     if (MAYBE_DONT_COLLIDE_WITH(i))
4496       SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
4497                    getDontCollideWithProperty(&level, i));
4498
4499     /* ---------- SP_PORT -------------------------------------------------- */
4500     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
4501                                  IS_PASSABLE_INSIDE(i)));
4502
4503     /* ---------- CAN_BE_CLONED_BY_ANDROID --------------------------------- */
4504     for (j = 0; j < level.num_android_clone_elements; j++)
4505       SET_PROPERTY(i, EP_CAN_BE_CLONED_BY_ANDROID,
4506                    (i != EL_EMPTY &&
4507                     IS_EQUAL_OR_IN_GROUP(i, level.android_clone_element[j])));
4508
4509     /* ---------- CAN_CHANGE ----------------------------------------------- */
4510     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);      /* default: cannot change */
4511     for (j = 0; j < element_info[i].num_change_pages; j++)
4512       if (element_info[i].change_page[j].can_change)
4513         SET_PROPERTY(i, EP_CAN_CHANGE, TRUE);
4514
4515     /* ---------- HAS_ACTION ----------------------------------------------- */
4516     SET_PROPERTY(i, EP_HAS_ACTION, FALSE);      /* default: has no action */
4517     for (j = 0; j < element_info[i].num_change_pages; j++)
4518       if (element_info[i].change_page[j].has_action)
4519         SET_PROPERTY(i, EP_HAS_ACTION, TRUE);
4520
4521     /* ---------- CAN_CHANGE_OR_HAS_ACTION --------------------------------- */
4522     SET_PROPERTY(i, EP_CAN_CHANGE_OR_HAS_ACTION, (CAN_CHANGE(i) ||
4523                                                   HAS_ACTION(i)));
4524
4525     /* ---------- GFX_CRUMBLED --------------------------------------------- */
4526     SET_PROPERTY(i, EP_GFX_CRUMBLED,
4527                  element_info[i].crumbled[ACTION_DEFAULT] !=
4528                  element_info[i].graphic[ACTION_DEFAULT]);
4529
4530     /* ---------- EDITOR_CASCADE ------------------------------------------- */
4531     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
4532                                         IS_EDITOR_CASCADE_INACTIVE(i)));
4533   }
4534
4535   /* dynamically adjust element properties according to game engine version */
4536   {
4537     static int ep_em_slippery_wall[] =
4538     {
4539       EL_WALL,
4540       EL_STEELWALL,
4541       EL_EXPANDABLE_WALL,
4542       EL_EXPANDABLE_WALL_HORIZONTAL,
4543       EL_EXPANDABLE_WALL_VERTICAL,
4544       EL_EXPANDABLE_WALL_ANY,
4545       EL_EXPANDABLE_STEELWALL_HORIZONTAL,
4546       EL_EXPANDABLE_STEELWALL_VERTICAL,
4547       EL_EXPANDABLE_STEELWALL_ANY,
4548       EL_EXPANDABLE_STEELWALL_GROWING,
4549       -1
4550     };
4551
4552     static int ep_em_explodes_by_fire[] =
4553     {
4554       EL_EM_DYNAMITE,
4555       EL_EM_DYNAMITE_ACTIVE,
4556       EL_MOLE,
4557       -1
4558     };
4559
4560     /* special EM style gems behaviour */
4561     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
4562       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
4563                    level.em_slippery_gems);
4564
4565     /* "EL_EXPANDABLE_WALL_GROWING" wasn't slippery for EM gems in 2.0.1 */
4566     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
4567                  (level.em_slippery_gems &&
4568                   engine_version > VERSION_IDENT(2,0,1,0)));
4569
4570     /* special EM style explosion behaviour regarding chain reactions */
4571     for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
4572       SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
4573                    level.em_explodes_by_fire);
4574   }
4575
4576   /* this is needed because some graphics depend on element properties */
4577   if (game_status == GAME_MODE_PLAYING)
4578     InitElementGraphicInfo();
4579 }
4580
4581 void InitElementPropertiesAfterLoading(int engine_version)
4582 {
4583   int i;
4584
4585   /* set some other uninitialized values of custom elements in older levels */
4586   if (engine_version < VERSION_IDENT(3,1,0,0))
4587   {
4588     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4589     {
4590       int element = EL_CUSTOM_START + i;
4591
4592       element_info[element].access_direction = MV_ALL_DIRECTIONS;
4593
4594       element_info[element].explosion_delay = 17;
4595       element_info[element].ignition_delay = 8;
4596     }
4597   }
4598 }
4599
4600 void InitElementPropertiesGfxElement()
4601 {
4602   int i;
4603
4604   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4605   {
4606     struct ElementInfo *ei = &element_info[i];
4607
4608     ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
4609   }
4610 }
4611
4612 static void InitGlobal()
4613 {
4614   int graphic;
4615   int i;
4616
4617   for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
4618   {
4619     /* check if element_name_info entry defined for each element in "main.h" */
4620     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
4621       Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
4622
4623     element_info[i].token_name = element_name_info[i].token_name;
4624     element_info[i].class_name = element_name_info[i].class_name;
4625     element_info[i].editor_description= element_name_info[i].editor_description;
4626   }
4627
4628   /* create hash from image config list */
4629   image_config_hash = newSetupFileHash();
4630   for (i = 0; image_config[i].token != NULL; i++)
4631     setHashEntry(image_config_hash,
4632                  image_config[i].token,
4633                  image_config[i].value);
4634
4635   /* create hash from element token list */
4636   element_token_hash = newSetupFileHash();
4637   for (i = 0; element_name_info[i].token_name != NULL; i++)
4638     setHashEntry(element_token_hash,
4639                  element_name_info[i].token_name,
4640                  int2str(i, 0));
4641
4642   /* create hash from graphic token list */
4643   graphic_token_hash = newSetupFileHash();
4644   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
4645     if (strSuffix(image_config[i].value, ".png") ||
4646         strSuffix(image_config[i].value, ".pcx") ||
4647         strSuffix(image_config[i].value, ".wav") ||
4648         strEqual(image_config[i].value, UNDEFINED_FILENAME))
4649       setHashEntry(graphic_token_hash,
4650                    image_config[i].token,
4651                    int2str(graphic++, 0));
4652
4653   /* create hash from font token list */
4654   font_token_hash = newSetupFileHash();
4655   for (i = 0; font_info[i].token_name != NULL; i++)
4656     setHashEntry(font_token_hash,
4657                  font_info[i].token_name,
4658                  int2str(i, 0));
4659
4660   /* set default filenames for all cloned graphics in static configuration */
4661   for (i = 0; image_config[i].token != NULL; i++)
4662   {
4663     if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
4664     {
4665       char *token = image_config[i].token;
4666       char *token_clone_from = getStringCat2(token, ".clone_from");
4667       char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
4668
4669       if (token_cloned != NULL)
4670       {
4671         char *value_cloned = getHashEntry(image_config_hash, token_cloned);
4672
4673         if (value_cloned != NULL)
4674         {
4675           /* set default filename in static configuration */
4676           image_config[i].value = value_cloned;
4677
4678           /* set default filename in image config hash */
4679           setHashEntry(image_config_hash, token, value_cloned);
4680         }
4681       }
4682
4683       free(token_clone_from);
4684     }
4685   }
4686
4687   /* always start with reliable default values (all elements) */
4688   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4689     ActiveElement[i] = i;
4690
4691   /* now add all entries that have an active state (active elements) */
4692   for (i = 0; element_with_active_state[i].element != -1; i++)
4693   {
4694     int element = element_with_active_state[i].element;
4695     int element_active = element_with_active_state[i].element_active;
4696
4697     ActiveElement[element] = element_active;
4698   }
4699
4700   /* always start with reliable default values (all buttons) */
4701   for (i = 0; i < NUM_IMAGE_FILES; i++)
4702     ActiveButton[i] = i;
4703
4704   /* now add all entries that have an active state (active buttons) */
4705   for (i = 0; button_with_active_state[i].button != -1; i++)
4706   {
4707     int button = button_with_active_state[i].button;
4708     int button_active = button_with_active_state[i].button_active;
4709
4710     ActiveButton[button] = button_active;
4711   }
4712
4713   /* always start with reliable default values (all fonts) */
4714   for (i = 0; i < NUM_FONTS; i++)
4715     ActiveFont[i] = i;
4716
4717   /* now add all entries that have an active state (active fonts) */
4718   for (i = 0; font_with_active_state[i].font_nr != -1; i++)
4719   {
4720     int font = font_with_active_state[i].font_nr;
4721     int font_active = font_with_active_state[i].font_nr_active;
4722
4723     ActiveFont[font] = font_active;
4724   }
4725
4726   global.autoplay_leveldir = NULL;
4727   global.convert_leveldir = NULL;
4728   global.create_images_dir = NULL;
4729
4730   global.frames_per_second = 0;
4731
4732   global.border_status = GAME_MODE_LOADING;
4733   global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
4734
4735   global.use_envelope_request = FALSE;
4736 }
4737
4738 void Execute_Command(char *command)
4739 {
4740   int i;
4741
4742   if (strEqual(command, "print graphicsinfo.conf"))
4743   {
4744     Print("# You can configure additional/alternative image files here.\n");
4745     Print("# (The entries below are default and therefore commented out.)\n");
4746     Print("\n");
4747     Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
4748     Print("\n");
4749     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4750     Print("\n");
4751
4752     for (i = 0; image_config[i].token != NULL; i++)
4753       Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
4754                                              image_config[i].value));
4755
4756     exit(0);
4757   }
4758   else if (strEqual(command, "print soundsinfo.conf"))
4759   {
4760     Print("# You can configure additional/alternative sound files here.\n");
4761     Print("# (The entries below are default and therefore commented out.)\n");
4762     Print("\n");
4763     Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
4764     Print("\n");
4765     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4766     Print("\n");
4767
4768     for (i = 0; sound_config[i].token != NULL; i++)
4769       Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
4770                                              sound_config[i].value));
4771
4772     exit(0);
4773   }
4774   else if (strEqual(command, "print musicinfo.conf"))
4775   {
4776     Print("# You can configure additional/alternative music files here.\n");
4777     Print("# (The entries below are default and therefore commented out.)\n");
4778     Print("\n");
4779     Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
4780     Print("\n");
4781     Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
4782     Print("\n");
4783
4784     for (i = 0; music_config[i].token != NULL; i++)
4785       Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
4786                                              music_config[i].value));
4787
4788     exit(0);
4789   }
4790   else if (strEqual(command, "print editorsetup.conf"))
4791   {
4792     Print("# You can configure your personal editor element list here.\n");
4793     Print("# (The entries below are default and therefore commented out.)\n");
4794     Print("\n");
4795
4796     /* this is needed to be able to check element list for cascade elements */
4797     InitElementPropertiesStatic();
4798     InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
4799
4800     PrintEditorElementList();
4801
4802     exit(0);
4803   }
4804   else if (strEqual(command, "print helpanim.conf"))
4805   {
4806     Print("# You can configure different element help animations here.\n");
4807     Print("# (The entries below are default and therefore commented out.)\n");
4808     Print("\n");
4809
4810     for (i = 0; helpanim_config[i].token != NULL; i++)
4811     {
4812       Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
4813                                              helpanim_config[i].value));
4814
4815       if (strEqual(helpanim_config[i].token, "end"))
4816         Print("#\n");
4817     }
4818
4819     exit(0);
4820   }
4821   else if (strEqual(command, "print helptext.conf"))
4822   {
4823     Print("# You can configure different element help text here.\n");
4824     Print("# (The entries below are default and therefore commented out.)\n");
4825     Print("\n");
4826
4827     for (i = 0; helptext_config[i].token != NULL; i++)
4828       Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
4829                                              helptext_config[i].value));
4830
4831     exit(0);
4832   }
4833   else if (strPrefix(command, "dump level "))
4834   {
4835     char *filename = &command[11];
4836
4837     if (!fileExists(filename))
4838       Error(ERR_EXIT, "cannot open file '%s'", filename);
4839
4840     LoadLevelFromFilename(&level, filename);
4841     DumpLevel(&level);
4842
4843     exit(0);
4844   }
4845   else if (strPrefix(command, "dump tape "))
4846   {
4847     char *filename = &command[10];
4848
4849     if (!fileExists(filename))
4850       Error(ERR_EXIT, "cannot open file '%s'", filename);
4851
4852     LoadTapeFromFilename(filename);
4853     DumpTape(&tape);
4854
4855     exit(0);
4856   }
4857   else if (strPrefix(command, "autotest ") ||
4858            strPrefix(command, "autoplay ") ||
4859            strPrefix(command, "autoffwd "))
4860   {
4861     char *str_ptr = getStringCopy(&command[9]); /* read command parameters */
4862
4863     global.autoplay_mode = (strPrefix(command, "autotest") ? AUTOPLAY_TEST :
4864                             strPrefix(command, "autoplay") ? AUTOPLAY_PLAY :
4865                             strPrefix(command, "autoffwd") ? AUTOPLAY_FFWD : 0);
4866
4867     while (*str_ptr != '\0')                    /* continue parsing string */
4868     {
4869       /* cut leading whitespace from string, replace it by string terminator */
4870       while (*str_ptr == ' ' || *str_ptr == '\t')
4871         *str_ptr++ = '\0';
4872
4873       if (*str_ptr == '\0')                     /* end of string reached */
4874         break;
4875
4876       if (global.autoplay_leveldir == NULL)     /* read level set string */
4877       {
4878         global.autoplay_leveldir = str_ptr;
4879         global.autoplay_all = TRUE;             /* default: play all tapes */
4880
4881         for (i = 0; i < MAX_TAPES_PER_SET; i++)
4882           global.autoplay_level[i] = FALSE;
4883       }
4884       else                                      /* read level number string */
4885       {
4886         int level_nr = atoi(str_ptr);           /* get level_nr value */
4887
4888         if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
4889           global.autoplay_level[level_nr] = TRUE;
4890
4891         global.autoplay_all = FALSE;
4892       }
4893
4894       /* advance string pointer to the next whitespace (or end of string) */
4895       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
4896         str_ptr++;
4897     }
4898   }
4899   else if (strPrefix(command, "convert "))
4900   {
4901     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
4902     char *str_ptr = strchr(str_copy, ' ');
4903
4904     global.convert_leveldir = str_copy;
4905     global.convert_level_nr = -1;
4906
4907     if (str_ptr != NULL)                        /* level number follows */
4908     {
4909       *str_ptr++ = '\0';                        /* terminate leveldir string */
4910       global.convert_level_nr = atoi(str_ptr);  /* get level_nr value */
4911     }
4912   }
4913   else if (strPrefix(command, "create images "))
4914   {
4915     global.create_images_dir = getStringCopy(&command[14]);
4916
4917     if (access(global.create_images_dir, W_OK) != 0)
4918       Error(ERR_EXIT, "image target directory '%s' not found or not writable",
4919             global.create_images_dir);
4920   }
4921   else if (strPrefix(command, "create CE image "))
4922   {
4923     CreateCustomElementImages(&command[16]);
4924
4925     exit(0);
4926   }
4927   else
4928   {
4929     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
4930   }
4931 }
4932
4933 static void InitSetup()
4934 {
4935   LoadSetup();                                  /* global setup info */
4936
4937   /* set some options from setup file */
4938
4939   if (setup.options.verbose)
4940     options.verbose = TRUE;
4941 }
4942
4943 static void InitGameInfo()
4944 {
4945   game.restart_level = FALSE;
4946 }
4947
4948 static void InitPlayerInfo()
4949 {
4950   int i;
4951
4952   /* choose default local player */
4953   local_player = &stored_player[0];
4954
4955   for (i = 0; i < MAX_PLAYERS; i++)
4956     stored_player[i].connected = FALSE;
4957
4958   local_player->connected = TRUE;
4959 }
4960
4961 static void InitArtworkInfo()
4962 {
4963   LoadArtworkInfo();
4964 }
4965
4966 static char *get_string_in_brackets(char *string)
4967 {
4968   char *string_in_brackets = checked_malloc(strlen(string) + 3);
4969
4970   sprintf(string_in_brackets, "[%s]", string);
4971
4972   return string_in_brackets;
4973 }
4974
4975 static char *get_level_id_suffix(int id_nr)
4976 {
4977   char *id_suffix = checked_malloc(1 + 3 + 1);
4978
4979   if (id_nr < 0 || id_nr > 999)
4980     id_nr = 0;
4981
4982   sprintf(id_suffix, ".%03d", id_nr);
4983
4984   return id_suffix;
4985 }
4986
4987 static void InitArtworkConfig()
4988 {
4989   static char *image_id_prefix[MAX_NUM_ELEMENTS +
4990                                NUM_FONTS +
4991                                NUM_GLOBAL_ANIM_TOKENS + 1];
4992   static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
4993                                NUM_GLOBAL_ANIM_TOKENS + 1];
4994   static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
4995   static char *action_id_suffix[NUM_ACTIONS + 1];
4996   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
4997   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
4998   static char *level_id_suffix[MAX_LEVELS + 1];
4999   static char *dummy[1] = { NULL };
5000   static char *ignore_generic_tokens[] =
5001   {
5002     "name",
5003     "sort_priority",
5004     NULL
5005   };
5006   static char **ignore_image_tokens;
5007   static char **ignore_sound_tokens;
5008   static char **ignore_music_tokens;
5009   int num_ignore_generic_tokens;
5010   int num_ignore_image_tokens;
5011   int num_ignore_sound_tokens;
5012   int num_ignore_music_tokens;
5013   int i;
5014
5015   /* dynamically determine list of generic tokens to be ignored */
5016   num_ignore_generic_tokens = 0;
5017   for (i = 0; ignore_generic_tokens[i] != NULL; i++)
5018     num_ignore_generic_tokens++;
5019
5020   /* dynamically determine list of image tokens to be ignored */
5021   num_ignore_image_tokens = num_ignore_generic_tokens;
5022   for (i = 0; image_config_vars[i].token != NULL; i++)
5023     num_ignore_image_tokens++;
5024   ignore_image_tokens =
5025     checked_malloc((num_ignore_image_tokens + 1) * sizeof(char *));
5026   for (i = 0; i < num_ignore_generic_tokens; i++)
5027     ignore_image_tokens[i] = ignore_generic_tokens[i];
5028   for (i = 0; i < num_ignore_image_tokens - num_ignore_generic_tokens; i++)
5029     ignore_image_tokens[num_ignore_generic_tokens + i] =
5030       image_config_vars[i].token;
5031   ignore_image_tokens[num_ignore_image_tokens] = NULL;
5032
5033   /* dynamically determine list of sound tokens to be ignored */
5034   num_ignore_sound_tokens = num_ignore_generic_tokens;
5035   ignore_sound_tokens =
5036     checked_malloc((num_ignore_sound_tokens + 1) * sizeof(char *));
5037   for (i = 0; i < num_ignore_generic_tokens; i++)
5038     ignore_sound_tokens[i] = ignore_generic_tokens[i];
5039   ignore_sound_tokens[num_ignore_sound_tokens] = NULL;
5040
5041   /* dynamically determine list of music tokens to be ignored */
5042   num_ignore_music_tokens = num_ignore_generic_tokens;
5043   ignore_music_tokens =
5044     checked_malloc((num_ignore_music_tokens + 1) * sizeof(char *));
5045   for (i = 0; i < num_ignore_generic_tokens; i++)
5046     ignore_music_tokens[i] = ignore_generic_tokens[i];
5047   ignore_music_tokens[num_ignore_music_tokens] = NULL;
5048
5049   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5050     image_id_prefix[i] = element_info[i].token_name;
5051   for (i = 0; i < NUM_FONTS; i++)
5052     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
5053   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5054     image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
5055       global_anim_info[i].token_name;
5056   image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5057
5058   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5059     sound_id_prefix[i] = element_info[i].token_name;
5060   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5061     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
5062       get_string_in_brackets(element_info[i].class_name);
5063   for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
5064     sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
5065       global_anim_info[i].token_name;
5066   sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
5067
5068   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
5069     music_id_prefix[i] = music_prefix_info[i].prefix;
5070   music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
5071
5072   for (i = 0; i < NUM_ACTIONS; i++)
5073     action_id_suffix[i] = element_action_info[i].suffix;
5074   action_id_suffix[NUM_ACTIONS] = NULL;
5075
5076   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5077     direction_id_suffix[i] = element_direction_info[i].suffix;
5078   direction_id_suffix[NUM_DIRECTIONS_FULL] = NULL;
5079
5080   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5081     special_id_suffix[i] = special_suffix_info[i].suffix;
5082   special_id_suffix[NUM_SPECIAL_GFX_ARGS] = NULL;
5083
5084   for (i = 0; i < MAX_LEVELS; i++)
5085     level_id_suffix[i] = get_level_id_suffix(i);
5086   level_id_suffix[MAX_LEVELS] = NULL;
5087
5088   InitImageList(image_config, NUM_IMAGE_FILES, image_config_suffix,
5089                 image_id_prefix, action_id_suffix, direction_id_suffix,
5090                 special_id_suffix, ignore_image_tokens);
5091   InitSoundList(sound_config, NUM_SOUND_FILES, sound_config_suffix,
5092                 sound_id_prefix, action_id_suffix, dummy,
5093                 special_id_suffix, ignore_sound_tokens);
5094   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
5095                 music_id_prefix, special_id_suffix, level_id_suffix,
5096                 dummy, ignore_music_tokens);
5097 }
5098
5099 static void InitMixer()
5100 {
5101   OpenAudio();
5102
5103   StartMixer();
5104 }
5105
5106 void InitGfxBuffers()
5107 {
5108   static int win_xsize_last = -1;
5109   static int win_ysize_last = -1;
5110
5111   /* create additional image buffers for double-buffering and cross-fading */
5112
5113   if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
5114   {
5115     /* may contain content for cross-fading -- only re-create if changed */
5116     ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5117     ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
5118
5119     win_xsize_last = WIN_XSIZE;
5120     win_ysize_last = WIN_YSIZE;
5121   }
5122
5123   ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
5124   ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
5125   ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
5126   ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
5127   ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
5128
5129   /* initialize screen properties */
5130   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
5131                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
5132                    bitmap_db_field);
5133   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
5134   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
5135   InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
5136   InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
5137   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
5138   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
5139
5140   /* required if door size definitions have changed */
5141   InitGraphicCompatibilityInfo_Doors();
5142
5143   InitGfxBuffers_EM();
5144   InitGfxBuffers_SP();
5145 }
5146
5147 void InitGfx()
5148 {
5149   struct GraphicInfo *graphic_info_last = graphic_info;
5150   char *filename_font_initial = NULL;
5151   char *filename_anim_initial = NULL;
5152   Bitmap *bitmap_font_initial = NULL;
5153   int font_height;
5154   int i, j;
5155
5156   /* determine settings for initial font (for displaying startup messages) */
5157   for (i = 0; image_config[i].token != NULL; i++)
5158   {
5159     for (j = 0; j < NUM_INITIAL_FONTS; j++)
5160     {
5161       char font_token[128];
5162       int len_font_token;
5163
5164       sprintf(font_token, "%s_%d", CONFIG_TOKEN_FONT_INITIAL, j + 1);
5165       len_font_token = strlen(font_token);
5166
5167       if (strEqual(image_config[i].token, font_token))
5168         filename_font_initial = image_config[i].value;
5169       else if (strlen(image_config[i].token) > len_font_token &&
5170                strncmp(image_config[i].token, font_token, len_font_token) == 0)
5171       {
5172         if (strEqual(&image_config[i].token[len_font_token], ".x"))
5173           font_initial[j].src_x = atoi(image_config[i].value);
5174         else if (strEqual(&image_config[i].token[len_font_token], ".y"))
5175           font_initial[j].src_y = atoi(image_config[i].value);
5176         else if (strEqual(&image_config[i].token[len_font_token], ".width"))
5177           font_initial[j].width = atoi(image_config[i].value);
5178         else if (strEqual(&image_config[i].token[len_font_token], ".height"))
5179           font_initial[j].height = atoi(image_config[i].value);
5180       }
5181     }
5182   }
5183
5184   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5185   {
5186     font_initial[j].num_chars = DEFAULT_NUM_CHARS_PER_FONT;
5187     font_initial[j].num_chars_per_line = DEFAULT_NUM_CHARS_PER_LINE;
5188   }
5189
5190   if (filename_font_initial == NULL)    /* should not happen */
5191     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
5192
5193   InitGfxBuffers();
5194   InitGfxCustomArtworkInfo();
5195   InitGfxOtherSettings();
5196
5197   bitmap_font_initial = LoadCustomImage(filename_font_initial);
5198
5199   for (j = 0; j < NUM_INITIAL_FONTS; j++)
5200     font_initial[j].bitmap = bitmap_font_initial;
5201
5202   InitFontGraphicInfo();
5203
5204   font_height = getFontHeight(FC_RED);
5205
5206   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
5207   DrawInitText(setup.internal.program_copyright, 50, FC_RED);
5208   DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
5209                FC_RED);
5210
5211   DrawInitText("Loading graphics", 120, FC_GREEN);
5212
5213   /* initialize settings for busy animation with default values */
5214   int parameter[NUM_GFX_ARGS];
5215   for (i = 0; i < NUM_GFX_ARGS; i++)
5216     parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
5217                                                image_config_suffix[i].token,
5218                                                image_config_suffix[i].type);
5219
5220   char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
5221   int len_anim_token = strlen(anim_token);
5222
5223   /* read settings for busy animation from default custom artwork config */
5224   char *gfx_config_filename = getPath3(options.graphics_directory,
5225                                        GFX_DEFAULT_SUBDIR,
5226                                        GRAPHICSINFO_FILENAME);
5227
5228   if (fileExists(gfx_config_filename))
5229   {
5230     SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
5231
5232     if (setup_file_hash)
5233     {
5234       char *filename = getHashEntry(setup_file_hash, anim_token);
5235
5236       if (filename)
5237       {
5238         filename_anim_initial = getStringCopy(filename);
5239
5240         for (j = 0; image_config_suffix[j].token != NULL; j++)
5241         {
5242           int type = image_config_suffix[j].type;
5243           char *suffix = image_config_suffix[j].token;
5244           char *token = getStringCat2(anim_token, suffix);
5245           char *value = getHashEntry(setup_file_hash, token);
5246
5247           checked_free(token);
5248
5249           if (value)
5250             parameter[j] = get_graphic_parameter_value(value, suffix, type);
5251         }
5252       }
5253
5254       freeSetupFileHash(setup_file_hash);
5255     }
5256   }
5257
5258   if (filename_anim_initial == NULL)
5259   {
5260     /* read settings for busy animation from static default artwork config */
5261     for (i = 0; image_config[i].token != NULL; i++)
5262     {
5263       if (strEqual(image_config[i].token, anim_token))
5264         filename_anim_initial = getStringCopy(image_config[i].value);
5265       else if (strlen(image_config[i].token) > len_anim_token &&
5266                strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
5267       {
5268         for (j = 0; image_config_suffix[j].token != NULL; j++)
5269         {
5270           if (strEqual(&image_config[i].token[len_anim_token],
5271                        image_config_suffix[j].token))
5272             parameter[j] =
5273               get_graphic_parameter_value(image_config[i].value,
5274                                           image_config_suffix[j].token,
5275                                           image_config_suffix[j].type);
5276         }
5277       }
5278     }
5279   }
5280
5281   if (filename_anim_initial == NULL)    /* should not happen */
5282     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
5283
5284   anim_initial.bitmaps =
5285     checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
5286
5287   anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
5288     LoadCustomImage(filename_anim_initial);
5289
5290   checked_free(filename_anim_initial);
5291
5292   graphic_info = &anim_initial;         /* graphic == 0 => anim_initial */
5293
5294   set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
5295
5296   graphic_info = graphic_info_last;
5297
5298   init.busy.width  = anim_initial.width;
5299   init.busy.height = anim_initial.height;
5300
5301   InitMenuDesignSettings_Static();
5302
5303   InitGfxDrawBusyAnimFunction(DrawInitAnim);
5304   InitGfxDrawGlobalAnimFunction(DrawGlobalAnim);
5305   InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
5306
5307   gfx.fade_border_source_status = global.border_status;
5308   gfx.fade_border_target_status = global.border_status;
5309   gfx.masked_border_bitmap_ptr = backbuffer;
5310
5311   /* use copy of busy animation to prevent change while reloading artwork */
5312   init_last = init;
5313 }
5314
5315 void InitGfxBackground()
5316 {
5317   fieldbuffer = bitmap_db_field;
5318   SetDrawtoField(DRAW_BACKBUFFER);
5319
5320   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
5321
5322   redraw_mask = REDRAW_ALL;
5323 }
5324
5325 static void InitLevelInfo()
5326 {
5327   LoadLevelInfo();                              /* global level info */
5328   LoadLevelSetup_LastSeries();                  /* last played series info */
5329   LoadLevelSetup_SeriesInfo();                  /* last played level info */
5330
5331   if (global.autoplay_leveldir &&
5332       global.autoplay_mode != AUTOPLAY_TEST)
5333   {
5334     leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
5335                                                  global.autoplay_leveldir);
5336     if (leveldir_current == NULL)
5337       leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
5338   }
5339 }
5340
5341 static void InitLevelArtworkInfo()
5342 {
5343   LoadLevelArtworkInfo();
5344 }
5345
5346 static void InitImages()
5347 {
5348   print_timestamp_init("InitImages");
5349
5350 #if 0
5351   printf("::: leveldir_current->identifier == '%s'\n",
5352          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5353   printf("::: leveldir_current->graphics_path == '%s'\n",
5354          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5355   printf("::: leveldir_current->graphics_set == '%s'\n",
5356          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5357   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5358          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5359 #endif
5360
5361   setLevelArtworkDir(artwork.gfx_first);
5362
5363 #if 0
5364   printf("::: leveldir_current->identifier == '%s'\n",
5365          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5366   printf("::: leveldir_current->graphics_path == '%s'\n",
5367          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5368   printf("::: leveldir_current->graphics_set == '%s'\n",
5369          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5370   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5371          leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
5372 #endif
5373
5374 #if 0
5375   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
5376          leveldir_current->identifier,
5377          artwork.gfx_current_identifier,
5378          artwork.gfx_current->identifier,
5379          leveldir_current->graphics_set,
5380          leveldir_current->graphics_path);
5381 #endif
5382
5383   UPDATE_BUSY_STATE();
5384
5385   ReloadCustomImages();
5386   print_timestamp_time("ReloadCustomImages");
5387
5388   UPDATE_BUSY_STATE();
5389
5390   LoadCustomElementDescriptions();
5391   print_timestamp_time("LoadCustomElementDescriptions");
5392
5393   UPDATE_BUSY_STATE();
5394
5395   LoadMenuDesignSettings();
5396   print_timestamp_time("LoadMenuDesignSettings");
5397
5398   UPDATE_BUSY_STATE();
5399
5400   ReinitializeGraphics();
5401   print_timestamp_time("ReinitializeGraphics");
5402
5403   UPDATE_BUSY_STATE();
5404
5405   print_timestamp_done("InitImages");
5406 }
5407
5408 static void InitSound(char *identifier)
5409 {
5410   print_timestamp_init("InitSound");
5411
5412   if (identifier == NULL)
5413     identifier = artwork.snd_current->identifier;
5414
5415   /* set artwork path to send it to the sound server process */
5416   setLevelArtworkDir(artwork.snd_first);
5417
5418   InitReloadCustomSounds(identifier);
5419   print_timestamp_time("InitReloadCustomSounds");
5420
5421   ReinitializeSounds();
5422   print_timestamp_time("ReinitializeSounds");
5423
5424   print_timestamp_done("InitSound");
5425 }
5426
5427 static void InitMusic(char *identifier)
5428 {
5429   print_timestamp_init("InitMusic");
5430
5431   if (identifier == NULL)
5432     identifier = artwork.mus_current->identifier;
5433
5434   /* set artwork path to send it to the sound server process */
5435   setLevelArtworkDir(artwork.mus_first);
5436
5437   InitReloadCustomMusic(identifier);
5438   print_timestamp_time("InitReloadCustomMusic");
5439
5440   ReinitializeMusic();
5441   print_timestamp_time("ReinitializeMusic");
5442
5443   print_timestamp_done("InitMusic");
5444 }
5445
5446 static void InitArtworkDone()
5447 {
5448   InitGlobalAnimations();
5449 }
5450
5451 void InitNetworkServer()
5452 {
5453 #if defined(NETWORK_AVALIABLE)
5454   int nr_wanted;
5455 #endif
5456
5457   if (!options.network)
5458     return;
5459
5460 #if defined(NETWORK_AVALIABLE)
5461   nr_wanted = Request("Choose player", REQ_PLAYER | REQ_STAY_CLOSED);
5462
5463   if (!ConnectToServer(options.server_host, options.server_port))
5464     Error(ERR_EXIT, "cannot connect to network game server");
5465
5466   SendToServer_PlayerName(setup.player_name);
5467   SendToServer_ProtocolVersion();
5468
5469   if (nr_wanted)
5470     SendToServer_NrWanted(nr_wanted);
5471 #endif
5472 }
5473
5474 static boolean CheckArtworkConfigForCustomElements(char *filename)
5475 {
5476   SetupFileHash *setup_file_hash;
5477   boolean redefined_ce_found = FALSE;
5478
5479   /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
5480
5481   if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
5482   {
5483     BEGIN_HASH_ITERATION(setup_file_hash, itr)
5484     {
5485       char *token = HASH_ITERATION_TOKEN(itr);
5486
5487       if (strPrefix(token, "custom_"))
5488       {
5489         redefined_ce_found = TRUE;
5490
5491         break;
5492       }
5493     }
5494     END_HASH_ITERATION(setup_file_hash, itr)
5495
5496     freeSetupFileHash(setup_file_hash);
5497   }
5498
5499   return redefined_ce_found;
5500 }
5501
5502 static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
5503 {
5504   char *filename_base, *filename_local;
5505   boolean redefined_ce_found = FALSE;
5506
5507   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
5508
5509 #if 0
5510   printf("::: leveldir_current->identifier == '%s'\n",
5511          leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
5512   printf("::: leveldir_current->graphics_path == '%s'\n",
5513          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
5514   printf("::: leveldir_current->graphics_set == '%s'\n",
5515          leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
5516   printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
5517          leveldir_current == NULL ? "[NULL]" :
5518          LEVELDIR_ARTWORK_SET(leveldir_current, type));
5519 #endif
5520
5521   /* first look for special artwork configured in level series config */
5522   filename_base = getCustomArtworkLevelConfigFilename(type);
5523
5524 #if 0
5525   printf("::: filename_base == '%s'\n", filename_base);
5526 #endif
5527
5528   if (fileExists(filename_base))
5529     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
5530
5531   filename_local = getCustomArtworkConfigFilename(type);
5532
5533 #if 0
5534   printf("::: filename_local == '%s'\n", filename_local);
5535 #endif
5536
5537   if (filename_local != NULL && !strEqual(filename_base, filename_local))
5538     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
5539
5540 #if 0
5541   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5542 #endif
5543
5544   return redefined_ce_found;
5545 }
5546
5547 static void InitOverrideArtwork()
5548 {
5549   boolean redefined_ce_found = FALSE;
5550
5551   /* to check if this level set redefines any CEs, do not use overriding */
5552   gfx.override_level_graphics = FALSE;
5553   gfx.override_level_sounds   = FALSE;
5554   gfx.override_level_music    = FALSE;
5555
5556   /* now check if this level set has definitions for custom elements */
5557   if (setup.override_level_graphics == AUTO ||
5558       setup.override_level_sounds   == AUTO ||
5559       setup.override_level_music    == AUTO)
5560     redefined_ce_found =
5561       (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
5562        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
5563        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
5564
5565 #if 0
5566   printf("::: redefined_ce_found == %d\n", redefined_ce_found);
5567 #endif
5568
5569   if (redefined_ce_found)
5570   {
5571     /* this level set has CE definitions: change "AUTO" to "FALSE" */
5572     gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
5573     gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
5574     gfx.override_level_music    = (setup.override_level_music    == TRUE);
5575   }
5576   else
5577   {
5578     /* this level set has no CE definitions: change "AUTO" to "TRUE" */
5579     gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
5580     gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
5581     gfx.override_level_music    = (setup.override_level_music    != FALSE);
5582   }
5583
5584 #if 0
5585   printf("::: => %d, %d, %d\n",
5586          gfx.override_level_graphics,
5587          gfx.override_level_sounds,
5588          gfx.override_level_music);
5589 #endif
5590 }
5591
5592 static char *getNewArtworkIdentifier(int type)
5593 {
5594   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
5595   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
5596   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
5597   static boolean initialized[3] = { FALSE, FALSE, FALSE };
5598   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
5599   boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
5600   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
5601   char *leveldir_identifier = leveldir_current->identifier;
5602   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
5603   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
5604   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
5605   char *artwork_current_identifier;
5606   char *artwork_new_identifier = NULL;  /* default: nothing has changed */
5607
5608   /* leveldir_current may be invalid (level group, parent link) */
5609   if (!validLevelSeries(leveldir_current))
5610     return NULL;
5611
5612   /* 1st step: determine artwork set to be activated in descending order:
5613      --------------------------------------------------------------------
5614      1. setup artwork (when configured to override everything else)
5615      2. artwork set configured in "levelinfo.conf" of current level set
5616         (artwork in level directory will have priority when loading later)
5617      3. artwork in level directory (stored in artwork sub-directory)
5618      4. setup artwork (currently configured in setup menu) */
5619
5620   if (setup_override_artwork)
5621     artwork_current_identifier = setup_artwork_set;
5622   else if (leveldir_artwork_set != NULL)
5623     artwork_current_identifier = leveldir_artwork_set;
5624   else if (getTreeInfoFromIdentifier(artwork_first_node, leveldir_identifier))
5625     artwork_current_identifier = leveldir_identifier;
5626   else
5627     artwork_current_identifier = setup_artwork_set;
5628
5629
5630   /* 2nd step: check if it is really needed to reload artwork set
5631      ------------------------------------------------------------ */
5632
5633   /* ---------- reload if level set and also artwork set has changed ------- */
5634   if (leveldir_current_identifier[type] != leveldir_identifier &&
5635       (last_has_level_artwork_set[type] || has_level_artwork_set))
5636     artwork_new_identifier = artwork_current_identifier;
5637
5638   leveldir_current_identifier[type] = leveldir_identifier;
5639   last_has_level_artwork_set[type] = has_level_artwork_set;
5640
5641   /* ---------- reload if "override artwork" setting has changed ----------- */
5642   if (last_override_level_artwork[type] != setup_override_artwork)
5643     artwork_new_identifier = artwork_current_identifier;
5644
5645   last_override_level_artwork[type] = setup_override_artwork;
5646
5647   /* ---------- reload if current artwork identifier has changed ----------- */
5648   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
5649                 artwork_current_identifier))
5650     artwork_new_identifier = artwork_current_identifier;
5651
5652   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
5653
5654   /* ---------- do not reload directly after starting ---------------------- */
5655   if (!initialized[type])
5656     artwork_new_identifier = NULL;
5657
5658   initialized[type] = TRUE;
5659
5660   return artwork_new_identifier;
5661 }
5662
5663 void ReloadCustomArtwork(int force_reload)
5664 {
5665   int last_game_status = game_status;   /* save current game status */
5666   char *gfx_new_identifier;
5667   char *snd_new_identifier;
5668   char *mus_new_identifier;
5669   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
5670   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
5671   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
5672   boolean reload_needed;
5673
5674   InitOverrideArtwork();
5675
5676   force_reload_gfx |= AdjustGraphicsForEMC();
5677
5678   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
5679   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
5680   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
5681
5682   reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
5683                    snd_new_identifier != NULL || force_reload_snd ||
5684                    mus_new_identifier != NULL || force_reload_mus);
5685
5686   if (!reload_needed)
5687     return;
5688
5689   print_timestamp_init("ReloadCustomArtwork");
5690
5691   SetGameStatus(GAME_MODE_LOADING);
5692
5693   FadeOut(REDRAW_ALL);
5694
5695   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5696   print_timestamp_time("ClearRectangle");
5697
5698   FadeIn(REDRAW_ALL);
5699
5700   if (gfx_new_identifier != NULL || force_reload_gfx)
5701   {
5702 #if 0
5703     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
5704            artwork.gfx_current_identifier,
5705            gfx_new_identifier,
5706            artwork.gfx_current->identifier,
5707            leveldir_current->graphics_set);
5708 #endif
5709
5710     InitImages();
5711     print_timestamp_time("InitImages");
5712   }
5713
5714   if (snd_new_identifier != NULL || force_reload_snd)
5715   {
5716     InitSound(snd_new_identifier);
5717     print_timestamp_time("InitSound");
5718   }
5719
5720   if (mus_new_identifier != NULL || force_reload_mus)
5721   {
5722     InitMusic(mus_new_identifier);
5723     print_timestamp_time("InitMusic");
5724   }
5725
5726   InitArtworkDone();
5727
5728   SetGameStatus(last_game_status);      /* restore current game status */
5729
5730   init_last = init;                     /* switch to new busy animation */
5731
5732   FadeOut(REDRAW_ALL);
5733
5734   RedrawGlobalBorder();
5735
5736   /* force redraw of (open or closed) door graphics */
5737   SetDoorState(DOOR_OPEN_ALL);
5738   CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
5739
5740   FadeSetEnterScreen();
5741   FadeSkipNextFadeOut();
5742
5743   print_timestamp_done("ReloadCustomArtwork");
5744
5745   LimitScreenUpdates(FALSE);
5746 }
5747
5748 void KeyboardAutoRepeatOffUnlessAutoplay()
5749 {
5750   if (global.autoplay_leveldir == NULL)
5751     KeyboardAutoRepeatOff();
5752 }
5753
5754 void DisplayExitMessage(char *format, va_list ap)
5755 {
5756   // check if draw buffer and fonts for exit message are already available
5757   if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
5758     return;
5759
5760   int font_1 = FC_RED;
5761   int font_2 = FC_YELLOW;
5762   int font_3 = FC_BLUE;
5763   int font_width = getFontWidth(font_2);
5764   int font_height = getFontHeight(font_2);
5765   int sx = SX;
5766   int sy = SY;
5767   int sxsize = WIN_XSIZE - 2 * sx;
5768   int sysize = WIN_YSIZE - 2 * sy;
5769   int line_length = sxsize / font_width;
5770   int max_lines = sysize / font_height;
5771   int num_lines_printed;
5772
5773   gfx.sx = sx;
5774   gfx.sy = sy;
5775   gfx.sxsize = sxsize;
5776   gfx.sysize = sysize;
5777
5778   sy = 20;
5779
5780   ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
5781
5782   DrawTextSCentered(sy, font_1, "Fatal error:");
5783   sy += 3 * font_height;;
5784
5785   num_lines_printed =
5786     DrawTextBufferVA(sx, sy, format, ap, font_2,
5787                      line_length, line_length, max_lines,
5788                      0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5789   sy += (num_lines_printed + 3) * font_height;
5790
5791   DrawTextSCentered(sy, font_1, "For details, see the following error file:");
5792   sy += 3 * font_height;
5793
5794   num_lines_printed =
5795     DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
5796                    line_length, line_length, max_lines,
5797                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
5798
5799   DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
5800
5801   redraw_mask = REDRAW_ALL;
5802
5803   /* force drawing exit message even if screen updates are currently limited */
5804   LimitScreenUpdates(FALSE);
5805
5806   BackToFront();
5807
5808   /* deactivate toons on error message screen */
5809   setup.toons = FALSE;
5810
5811   WaitForEventToContinue();
5812 }
5813
5814
5815 /* ========================================================================= */
5816 /* OpenAll()                                                                 */
5817 /* ========================================================================= */
5818
5819 void OpenAll()
5820 {
5821   print_timestamp_init("OpenAll");
5822
5823   SetGameStatus(GAME_MODE_LOADING);
5824
5825   InitCounter();
5826
5827   InitGlobal();                 /* initialize some global variables */
5828
5829   print_timestamp_time("[init global stuff]");
5830
5831   InitSetup();
5832
5833   print_timestamp_time("[init setup/config stuff (1)]");
5834
5835   if (options.execute_command)
5836     Execute_Command(options.execute_command);
5837
5838   if (options.serveronly)
5839   {
5840 #if defined(PLATFORM_UNIX)
5841     NetworkServer(options.server_port, options.serveronly);
5842 #else
5843     Error(ERR_WARN, "networking only supported in Unix version");
5844 #endif
5845
5846     exit(0);                    /* never reached, server loops forever */
5847   }
5848
5849   InitGameInfo();
5850   print_timestamp_time("[init setup/config stuff (2)]");
5851   InitPlayerInfo();
5852   print_timestamp_time("[init setup/config stuff (3)]");
5853   InitArtworkInfo();            /* needed before loading gfx, sound & music */
5854   print_timestamp_time("[init setup/config stuff (4)]");
5855   InitArtworkConfig();          /* needed before forking sound child process */
5856   print_timestamp_time("[init setup/config stuff (5)]");
5857   InitMixer();
5858   print_timestamp_time("[init setup/config stuff (6)]");
5859
5860   InitRND(NEW_RANDOMIZE);
5861   InitSimpleRandom(NEW_RANDOMIZE);
5862
5863   InitJoysticks();
5864
5865   print_timestamp_time("[init setup/config stuff]");
5866
5867   InitVideoDisplay();
5868   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
5869
5870   InitEventFilter(FilterEvents);
5871
5872   print_timestamp_time("[init video stuff]");
5873
5874   InitElementPropertiesStatic();
5875   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
5876   InitElementPropertiesGfxElement();
5877
5878   print_timestamp_time("[init element properties stuff]");
5879
5880   InitGfx();
5881
5882   print_timestamp_time("InitGfx");
5883
5884   InitLevelInfo();
5885   print_timestamp_time("InitLevelInfo");
5886
5887   InitLevelArtworkInfo();
5888   print_timestamp_time("InitLevelArtworkInfo");
5889
5890   InitOverrideArtwork();        /* needs to know current level directory */
5891   print_timestamp_time("InitOverrideArtwork");
5892
5893   InitImages();                 /* needs to know current level directory */
5894   print_timestamp_time("InitImages");
5895
5896   InitSound(NULL);              /* needs to know current level directory */
5897   print_timestamp_time("InitSound");
5898
5899   InitMusic(NULL);              /* needs to know current level directory */
5900   print_timestamp_time("InitMusic");
5901
5902   InitArtworkDone();
5903
5904   InitGfxBackground();
5905
5906   em_open_all();
5907   sp_open_all();
5908
5909   if (global.autoplay_leveldir)
5910   {
5911     AutoPlayTape();
5912     return;
5913   }
5914   else if (global.convert_leveldir)
5915   {
5916     ConvertLevels();
5917     return;
5918   }
5919   else if (global.create_images_dir)
5920   {
5921     CreateLevelSketchImages();
5922     return;
5923   }
5924
5925   SetGameStatus(GAME_MODE_MAIN);
5926
5927   FadeSetEnterScreen();
5928   if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
5929     FadeSkipNextFadeOut();
5930
5931   print_timestamp_time("[post-artwork]");
5932
5933   print_timestamp_done("OpenAll");
5934
5935   DrawMainMenu();
5936
5937   InitNetworkServer();
5938
5939 #if 0
5940   Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
5941         SDL_GetBasePath());
5942   Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
5943         SDL_GetPrefPath("artsoft", "rocksndiamonds"));
5944 #if defined(PLATFORM_ANDROID)
5945   Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
5946         SDL_AndroidGetInternalStoragePath());
5947   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
5948         SDL_AndroidGetExternalStoragePath());
5949   Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
5950         (SDL_AndroidGetExternalStorageState() ==
5951          SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
5952          SDL_AndroidGetExternalStorageState() ==
5953          SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
5954 #endif
5955 #endif
5956 }
5957
5958 void CloseAllAndExit(int exit_value)
5959 {
5960   StopSounds();
5961   FreeAllSounds();
5962   FreeAllMusic();
5963   CloseAudio();         /* called after freeing sounds (needed for SDL) */
5964
5965   em_close_all();
5966   sp_close_all();
5967
5968   FreeAllImages();
5969
5970 #if defined(TARGET_SDL)
5971 #if defined(TARGET_SDL2)
5972   // !!! TODO !!!
5973   // set a flag to tell the network server thread to quit and wait for it
5974   // using SDL_WaitThread()
5975 #else
5976   if (network_server)   /* terminate network server */
5977     SDL_KillThread(server_thread);
5978 #endif
5979 #endif
5980
5981   CloseVideoDisplay();
5982   ClosePlatformDependentStuff();
5983
5984   if (exit_value != 0)
5985   {
5986     /* fall back to default level set (current set may have caused an error) */
5987     SaveLevelSetup_LastSeries_Deactivate();
5988
5989     /* tell user where to find error log file which may contain more details */
5990     // (error notification now directly displayed on screen inside R'n'D
5991     // NotifyUserAboutErrorFile();      /* currently only works for Windows */
5992   }
5993
5994   exit(exit_value);
5995 }