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