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