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